<commit_before>'use strict';

// some nice helpers
var q = document.querySelector.bind(document);
var qAll = document.querySelectorAll.bind(document);

var each = function(query, fn) {
  Array.prototype.slice.call(qAll(query), 0).forEach(fn);
};

function ajax(addr, blob, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', addr, true);
  if (blob) {
    xhr.responseType = 'blob';
  } else {
    // Hack to pass bytes through unprocessed.
    xhr.overrideMimeType('text/plain; charset=utf-8');
  }
  xhr.onreadystatechange = function() {
    if (this.readyState === 4 && this.status === 200) {
      var res = (blob) ? this.response : JSON.parse(this.response);
      callback(res);
    }
  };
  xhr.send();
}

var settings = {
  zoomLevel: {
    type: 'checkbox',
    value: 15
  },
  enableRotate: {
    type: 'number',
    value: true
  }
};

function addMap(lat, lng, link) {
  var url = 'https://maps.googleapis.com/maps/api/staticmap?center=' + lat + ',' + lng + '&zoom=' + settings.zoomLevel.value + '&size=547x390&markers=color:blue%7C' + lat + ',' + lng + '&maptype=roadmap&sensor=true';
  ajax(url, true, function(res) {
    var image = new Image();
    image.src = window.webkitURL.createObjectURL(res);
    image.style.opacity = 1;
    image.height = '390';
    image.width = '547';
    image.style.maxWidth = '100%';
    image.onload = function() {
      q('#UserContent').innerHTML += '

Enhanced Map Preview

';
      q('#NewMapLink').appendChild(image);
    };
  });
}

function doRotate() {
  var container = q('#MainContainer .img-scroll');

  if (container && settings.enableRotate.value) {
    // add some space for the button
    var area = q('#PageViewImage .centered-item.large-image');
    if (area) {
      area.style.margin = '40px 0';
    }
    var style = ['position: relative;', 'right: 0;', 'top: 12px;', 'border: solid 1px #EC7D1B;', 'border-radius: 5px;', 'background-clip: padding-box;', 'color: #FFF;', 'background: -webkit-gradient(linear,left top,left bottom,color-stop(12%,#FFB929),color-stop(50%,#F39D00));', 'background: -webkit-linear-gradient(top,#FFB929 12%,#F39D00 50%);', 'background: linear-gradient(top,#ffb929 12%,#f39d00 50%);', 'margin: 0;', 'padding: 3px 4px;', 'outline: none;'].join('');

    var rotateBtn = '<button type=\"button\" id=\"rotate-image\" style=\"' + style + '\">ROTATE IMAGE</button>';

    q('#MainContainer .img-scroll').innerHTML += rotateBtn;

    // set a data-attribute for all the items
    each('.photo-navigation li.showing a', function(item) {
      item.setAttribute('data-rotation', 0);
    });

    // now the event listener for the button
    q('#rotate-image').addEventListener('click', function(event) {
      event.preventDefault();
      var item = q('.photo-navigation li.showing a');
      item.style.display = 'block';
      // get the rotation
      var rotation = parseInt(item.getAttribute('data-rotation'), 10);
      rotation += 90;
      // firgure out the orientation of this thing
      var orientation = {
        '0': 'normal',
        '0.25': 'right',
        '0.5': 'bottom',
        '0.75': 'left'
      }[((rotation / 360) % 1).toString()];
      var image = item.querySelector('img');
      // which side is bigger
      var prop = (image.offsetWidth >= image.offsetHeight) ? 'offsetWidth' : 'offsetHeight';
      // assign the attribute
      item.style.height = image[prop] + 'px';
      item.style.width = image[prop] + 'px';
      // adjust the margin for the different orientation
      if (prop === 'offsetWidth') {
        var amount = ((image.offsetWidth - image.offsetHeight) / 2).toFixed(1);
        if (orientation === 'normal') {
          image.style.margin = '0';
        } else if (orientation === 'bottom') {
          image.style.margin = (amount * 2) + 'px 0 0 0';
        } else {
          image.style.margin = amount + 'px 0 0 0';
        }
      }
      // finally rotate it
      item.style.transform = 'rotate(' + rotation + 'deg)';
      // save the attribute for next click
      item.setAttribute('data-rotation', rotation);
      return false;
    });
  }
}

function getMap() {
  var map = q('#MapLink');
  // does the map exist?
  if (map) {
    // make this url-safe
    var link = encodeURIComponent(map.parentElement.innerText.split('\n')[0]);
    ajax('https://maps.googleapis.com/maps/api/geocode/json?address=' + link + '&sensor=true', false, function(res) {
      // res = JSON.parse(res);
      if (typeof(res) !== 'undefined') {
        res = res.results[0].geometry.location;
        addMap(res.lat, res.lng, link);
      }
    });
  }
}

function sizeThumbnails() {
  each('.container-results .image img', function(item) {
    item.style.maxWidth = '200px';
    item.style.maxHeight = '200px';
  });
}

function start() {
  doRotate();
  sizeThumbnails();
  getMap();
}

chrome.storage.sync.get(['zoomLevel', 'enableRotate'], function(result) {
  settings.zoomLevel = result.zoomLevel;
  settings.enableRotate = result.enableRotate;
  start();
});<commit_msg>update comments and general cleanup<commit_after>'use strict';

// some nice helpers
var q = document.querySelector.bind(document);
var qAll = document.querySelectorAll.bind(document);

var each = function(query, fn) {
  Array.prototype.slice.call(qAll(query), 0).forEach(fn);
};

// my main fetching function
function ajax(addr, blob, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', addr, true);
  if (blob) {
    xhr.responseType = 'blob';
  } else {
    // Hack to pass bytes through unprocessed.
    xhr.overrideMimeType('text/plain; charset=utf-8');
  }
  xhr.onreadystatechange = function() {
    if (this.readyState === 4 && this.status === 200) {
      var res = (blob) ? this.response : JSON.parse(this.response);
      callback(res);
    }
  };
  xhr.send();
}

// default settings
var settings = {
  zoomLevel: {
    type: 'checkbox',
    value: 15
  },
  enableRotate: {
    type: 'number',
    value: true
  }
};

function addMap(lat, lng, link) {
  var url = 'https://maps.googleapis.com/maps/api/staticmap?center=' + lat + ',' + lng + '&zoom=' + settings.zoomLevel.value + '&size=547x390&markers=color:blue%7C' + lat + ',' + lng + '&maptype=roadmap&sensor=true';
  ajax(url, true, function(res) {
    var image = new Image();
    image.src = window.webkitURL.createObjectURL(res);
    image.style.opacity = 1;
    image.height = '390';
    image.width = '547';
    image.style.maxWidth = '100%';
    // dont do anything until loaded
    image.onload = function() {
      // inject a nice title and a link
      q('#UserContent').innerHTML += '

Enhanced Map Preview

';
      // throw the image in that new link
      q('#NewMapLink').appendChild(image);
    };
  });
}

function doRotate() {
  var container = q('#MainContainer .img-scroll');
  // make sure we are on the right page, and the setting is on
  if (container && settings.enableRotate.value) {
    // add some space for the button
    var area = q('#PageViewImage .centered-item.large-image');
    if (area) {
      area.style.margin = '40px 0';
    }
    var style = ['position: relative;', 'right: 0;', 'top: 12px;', 'border: solid 1px #EC7D1B;', 'border-radius: 5px;', 'background-clip: padding-box;', 'color: #FFF;', 'background: -webkit-gradient(linear,left top,left bottom,color-stop(12%,#FFB929),color-stop(50%,#F39D00));', 'background: -webkit-linear-gradient(top,#FFB929 12%,#F39D00 50%);', 'background: linear-gradient(top,#ffb929 12%,#f39d00 50%);', 'margin: 0;', 'padding: 3px 4px;', 'outline: none;'].join('');

    var rotateBtn = '<button type=\"button\" id=\"rotate-image\" style=\"' + style + '\">ROTATE IMAGE</button>';

    q('#MainContainer .img-scroll').innerHTML += rotateBtn;

    // set a data-attribute for all the items
    each('.photo-navigation li.showing a', function(item) {
      item.setAttribute('data-rotation', 0);
    });

    // now the event listener for the button
    q('#rotate-image').addEventListener('click', function(event) {
      event.preventDefault();
      var item = q('.photo-navigation li.showing a');
      item.style.display = 'block';
      // get the rotation
      var rotation = parseInt(item.getAttribute('data-rotation'), 10);
      rotation += 90;
      // firgure out the orientation of this thing
      var orientation = {
        '0': 'normal',
        '0.25': 'right',
        '0.5': 'bottom',
        '0.75': 'left'
      }[((rotation / 360) % 1).toString()];
      var image = item.querySelector('img');
      // which side is bigger
      var prop = (image.offsetWidth >= image.offsetHeight) ? 'offsetWidth' : 'offsetHeight';
      // assign the attribute
      item.style.height = image[prop] + 'px';
      item.style.width = image[prop] + 'px';
      // adjust the margin for the different orientation
      if (prop === 'offsetWidth') {
        var amount = ((image.offsetWidth - image.offsetHeight) / 2).toFixed(1);
        if (orientation === 'normal') {
          image.style.margin = '0';
        } else if (orientation === 'bottom') {
          image.style.margin = (amount * 2) + 'px 0 0 0';
        } else {
          image.style.margin = amount + 'px 0 0 0';
        }
      }
      // finally rotate it
      item.style.transform = 'rotate(' + rotation + 'deg)';
      // save the attribute for next click
      item.setAttribute('data-rotation', rotation);
      return false;
    });
  }
}

function getMap() {
  var map = q('#MapLink');
  // does the map exist?
  if (map) {
    // make this url-safe
    var link = encodeURIComponent(map.parentElement.innerText.split('\n')[0]);
    ajax('https://maps.googleapis.com/maps/api/geocode/json?address=' + link + '&sensor=true', false, function(res) {
      if (typeof(res) !== 'undefined') {
        res = res.results[0].geometry.location;
        // fetch a new map with that location and link
        addMap(res.lat, res.lng, link);
      }
    });
  }
}

function sizeThumbnails() {
  // apply these styles to the list thumbnails
  each('.container-results .image img', function(item) {
    item.style.maxWidth = '200px';
    item.style.maxHeight = '200px';
  });
}

function start() {
  doRotate();
  sizeThumbnails();
  getMap();
}

chrome.storage.sync.get(['zoomLevel', 'enableRotate'], function(result) {
  settings.zoomLevel = result.zoomLevel;
  settings.enableRotate = result.enableRotate;
  // there is no DOMReady in extensions, we have a start() though
  start();
});<|endoftext|>


<commit_before>/*
SHJS - Syntax Highlighting in JavaScript
Copyright (C) 2007, 2008 gnombat@users.sourceforge.net
License: http://shjs.sourceforge.net/doc/gplv3.html
*/

if (! this.sh_languages) {
  this.sh_languages = {};
}
var sh_requests = {};

function sh_isEmailAddress(url) {
  if (/^mailto:/.test(url)) {
    return false;
  }
  return url.indexOf('@') !== -1;
}

function sh_setHref(tags, numTags, inputString) {
  var url = inputString.substring(tags[numTags - 2].pos, tags[numTags - 1].pos);
  if (url.length >= 2 && url.charAt(0) === '<' && url.charAt(url.length - 1) === '>') {
    url = url.substr(1, url.length - 2);
  }
  if (sh_isEmailAddress(url)) {
    url = 'mailto:' + url;
  }
  tags[numTags - 2].node.href = url;
}

/*
Konqueror has a bug where the regular expression /$/g will not match at the end
of a line more than once:

  var regex = /$/g;
  var match;

  var line = '1234567890';
  regex.lastIndex = 10;
  match = regex.exec(line);

  var line2 = 'abcde';
  regex.lastIndex = 5;
  match = regex.exec(line2);  // fails
*/
function sh_konquerorExec(s) {
  var result = [''];
  result.index = s.length;
  result.input = s;
  return result;
}

/**
Highlights all elements containing source code in a text string.  The return
value is an array of objects, each representing an HTML start or end tag.  Each
object has a property named pos, which is an integer representing the text
offset of the tag. Every start tag also has a property named node, which is the
DOM element started by the tag. End tags do not have this property.
@param  inputString  a text string
@param  language  a language definition object
@return  an array of tag objects
*/
function sh_highlightString(inputString, language) {
  if (/Konqueror/.test(navigator.userAgent)) {
    if (! language.konquered) {
      for (var s = 0; s < language.length; s++) {
        for (var p = 0; p < language[s].length; p++) {
          var r = language[s][p][0];
          if (r.source === '$') {
            r.exec = sh_konquerorExec;
          }
        }
      }
      language.konquered = true;
    }
  }

  var a = document.createElement('a');
  var span = document.createElement('span');

  // the result
  var tags = [];
  var numTags = 0;

  // each element is a pattern object from language
  var patternStack = [];

  // the current position within inputString
  var pos = 0;

  // the name of the current style, or null if there is no current style
  var currentStyle = null;

  var output = function(s, style) {
    var length = s.length;
    // this is more than just an optimization - we don't want to output empty  elements
    if (length === 0) {
      return;
    }
    if (! style) {
      var stackLength = patternStack.length;
      if (stackLength !== 0) {
        var pattern = patternStack[stackLength - 1];
        // check whether this is a state or an environment
        if (! pattern[3]) {
          // it's not a state - it's an environment; use the style for this environment
          style = pattern[1];
        }
      }
    }
    if (currentStyle !== style) {
      if (currentStyle) {
        tags[numTags++] = {pos: pos};
        if (currentStyle === 'sh_url') {
          sh_setHref(tags, numTags, inputString);
        }
      }
      if (style) {
        var clone;
        if (style === 'sh_url') {
          clone = a.cloneNode(false);
        }
        else {
          clone = span.cloneNode(false);
        }
        clone.className = style;
        tags[numTags++] = {node: clone, pos: pos};
      }
    }
    pos += length;
    currentStyle = style;
  };

  var endOfLinePattern = /\r\n|\r|\n/g;
  endOfLinePattern.lastIndex = 0;
  var inputStringLength = inputString.length;
  while (pos < inputStringLength) {
    var start = pos;
    var end;
    var startOfNextLine;
    var endOfLineMatch = endOfLinePattern.exec(inputString);
    if (endOfLineMatch === null) {
      end = inputStringLength;
      startOfNextLine = inputStringLength;
    }
    else {
      end = endOfLineMatch.index;
      startOfNextLine = endOfLinePattern.lastIndex;
    }

    var line = inputString.substring(start, end);

    var matchCache = [];
    for (;;) {
      var posWithinLine = pos - start;

      var stateIndex;
      var stackLength = patternStack.length;
      if (stackLength === 0) {
        stateIndex = 0;
      }
      else {
        // get the next state
        stateIndex = patternStack[stackLength - 1][2];
      }

      var state = language[stateIndex];
      var numPatterns = state.length;
      var mc = matchCache[stateIndex];
      if (! mc) {
        mc = matchCache[stateIndex] = [];
      }
      var bestMatch = null;
      var bestPatternIndex = -1;
      for (var i = 0; i < numPatterns; i++) {
        var match;
        if (i < mc.length && (mc[i] === null || posWithinLine <= mc[i].index)) {
          match = mc[i];
        }
        else {
          var regex = state[i][0];
          regex.lastIndex = posWithinLine;
          match = regex.exec(line);
          mc[i] = match;
        }
        if (match !== null && (bestMatch === null || match.index < bestMatch.index)) {
          bestMatch = match;
          bestPatternIndex = i;
          if (match.index === posWithinLine) {
            break;
          }
        }
      }

      if (bestMatch === null) {
        output(line.substring(posWithinLine), null);
        break;
      }
      else {
        // got a match
        if (bestMatch.index > posWithinLine) {
          output(line.substring(posWithinLine, bestMatch.index), null);
        }

        var pattern = state[bestPatternIndex];

        var newStyle = pattern[1];
        var matchedString;
        if (newStyle instanceof Array) {
          for (var subexpression = 0; subexpression < newStyle.length; subexpression++) {
            matchedString = bestMatch[subexpression + 1];
            output(matchedString, newStyle[subexpression]);
          }
        }
        else {
          matchedString = bestMatch[0];
          output(matchedString, newStyle);
        }

        switch (pattern[2]) {
        case -1:
          // do nothing
          break;
        case -2:
          // exit
          patternStack.pop();
          break;
        case -3:
          // exitall
          patternStack.length = 0;
          break;
        default:
          // this was the start of a delimited pattern or a state/environment
          patternStack.push(pattern);
          break;
        }
      }
    }

    // end of the line
    if (currentStyle) {
      tags[numTags++] = {pos: pos};
      if (currentStyle === 'sh_url') {
        sh_setHref(tags, numTags, inputString);
      }
      currentStyle = null;
    }
    pos = startOfNextLine;
  }

  return tags;
}

////////////////////////////////////////////////////////////////////////////////
// DOM-dependent functions

function sh_getClasses(element) {
  var result = [];
  var htmlClass = element.className;
  if (htmlClass && htmlClass.length > 0) {
    var htmlClasses = htmlClass.split(' ');
    for (var i = 0; i < htmlClasses.length; i++) {
      if (htmlClasses[i].length > 0) {
        result.push(htmlClasses[i]);
      }
    }
  }
  return result;
}

function sh_addClass(element, name) {
  var htmlClasses = sh_getClasses(element);
  for (var i = 0; i < htmlClasses.length; i++) {
    if (name.toLowerCase() === htmlClasses[i].toLowerCase()) {
      return;
    }
  }
  htmlClasses.push(name);
  element.className = htmlClasses.join(' ');
}

/**
Extracts the tags from an HTML DOM NodeList.
@param  nodeList  a DOM NodeList
@param  result  an object with text, tags and pos properties
*/
function sh_extractTagsFromNodeList(nodeList, result) {
  var length = nodeList.length;
  for (var i = 0; i < length; i++) {
    var node = nodeList.item(i);
    switch (node.nodeType) {
    case 1:
      if (node.nodeName.toLowerCase() === 'br') {
        var terminator;
        if (/MSIE/.test(navigator.userAgent)) {
          terminator = '\r';
        }
        else {
          terminator = '\n';
        }
        result.text.push(terminator);
        result.pos++;
      }
      else {
        result.tags.push({node: node.cloneNode(false), pos: result.pos});
        sh_extractTagsFromNodeList(node.childNodes, result);
        result.tags.push({pos: result.pos});
      }
      break;
    case 3:
    case 4:
      result.text.push(node.data);
      result.pos += node.length;
      break;
    }
  }
}

/**
Extracts the tags from the text of an HTML element. The extracted tags will be
returned as an array of tag objects. See sh_highlightString for the format of
the tag objects.
@param  element  a DOM element
@param  tags  an empty array; the extracted tag objects will be returned in it
@return  the text of the element
@see  sh_highlightString
*/
function sh_extractTags(element, tags) {
  var result = {};
  result.text = [];
  result.tags = tags;
  result.pos = 0;
  sh_extractTagsFromNodeList(element.childNodes, result);
  return result.text.join('');
}

/**
Merges the original tags from an element with the tags produced by highlighting.
@param  originalTags  an array containing the original tags
@param  highlightTags  an array containing the highlighting tags - these must not overlap
@result  an array containing the merged tags
*/
function sh_mergeTags(originalTags, highlightTags) {
  var numOriginalTags = originalTags.length;
  if (numOriginalTags === 0) {
    return highlightTags;
  }

  var numHighlightTags = highlightTags.length;
  if (numHighlightTags === 0) {
    return originalTags;
  }

  var result = [];
  var originalIndex = 0;
  var highlightIndex = 0;

  while (originalIndex < numOriginalTags && highlightIndex < numHighlightTags) {
    var originalTag = originalTags[originalIndex];
    var highlightTag = highlightTags[highlightIndex];

    if (originalTag.pos <= highlightTag.pos) {
      result.push(originalTag);
      originalIndex++;
    }
    else {
      result.push(highlightTag);
      if (highlightTags[highlightIndex + 1].pos <= originalTag.pos) {
        highlightIndex++;
        result.push(highlightTags[highlightIndex]);
        highlightIndex++;
      }
      else {
        // new end tag
        result.push({pos: originalTag.pos});

        // new start tag
        highlightTags[highlightIndex] = {node: highlightTag.node.cloneNode(false), pos: originalTag.pos};
      }
    }
  }

  while (originalIndex < numOriginalTags) {
    result.push(originalTags[originalIndex]);
    originalIndex++;
  }

  while (highlightIndex < numHighlightTags) {
    result.push(highlightTags[highlightIndex]);
    highlightIndex++;
  }

  return result;
}

/**
Inserts tags into text.
@param  tags  an array of tag objects
@param  text  a string representing the text
@return  a DOM DocumentFragment representing the resulting HTML
*/
function sh_insertTags(tags, text) {
  var doc = document;

  var result = document.createDocumentFragment();
  var tagIndex = 0;
  var numTags = tags.length;
  var textPos = 0;
  var textLength = text.length;
  var currentNode = result;

  // output one tag or text node every iteration
  while (textPos < textLength || tagIndex < numTags) {
    var tag;
    var tagPos;
    if (tagIndex < numTags) {
      tag = tags[tagIndex];
      tagPos = tag.pos;
    }
    else {
      tagPos = textLength;
    }

    if (tagPos <= textPos) {
      // output the tag
      if (tag.node) {
        // start tag
        var newNode = tag.node;
        currentNode.appendChild(newNode);
        currentNode = newNode;
      }
      else {
        // end tag
        currentNode = currentNode.parentNode;
      }
      tagIndex++;
    }
    else {
      // output text
      currentNode.appendChild(doc.createTextNode(text.substring(textPos, tagPos)));
      textPos = tagPos;
    }
  }

  return result;
}

/**
Highlights an element containing source code.  Upon completion of this function,
the element will have been placed in the "sh_sourceCode" class.
@param  element  a DOM
 element containing the source code to be highlighted
@param  language  a language definition object
*/
function sh_highlightElement(element, language) {
  sh_addClass(element, 'sh_sourceCode');
  var originalTags = [];
  var inputString = sh_extractTags(element, originalTags);
  var highlightTags = sh_highlightString(inputString, language);
  var tags = sh_mergeTags(originalTags, highlightTags);
  var documentFragment = sh_insertTags(tags, inputString);
  while (element.hasChildNodes()) {
    element.removeChild(element.firstChild);
  }
  element.appendChild(documentFragment);
}

function sh_getXMLHttpRequest() {
  if (window.ActiveXObject) {
    return new ActiveXObject('Msxml2.XMLHTTP');
  }
  else if (window.XMLHttpRequest) {
    return new XMLHttpRequest();
  }
  throw 'No XMLHttpRequest implementation available';
}

function sh_load(language, element, prefix, suffix) {
  if (language in sh_requests) {
    sh_requests[language].push(element);
    return;
  }
  sh_requests[language] = [element];
  var request = sh_getXMLHttpRequest();
  var url = prefix + 'sh_' + language + suffix;
  request.open('GET', url, true);
  request.onreadystatechange = function () {
    if (request.readyState === 4) {
      try {
        if (! request.status || request.status === 200) {
          eval(request.responseText);
          var elements = sh_requests[language];
          for (var i = 0; i < elements.length; i++) {
            sh_highlightElement(elements[i], sh_languages[language]);
          }
        }
        else {
          throw 'HTTP error: status ' + request.status;
        }
      }
      finally {
        request = null;
      }
    }
  };
  request.send(null);
}

/**
Highlights all elements containing source code on the current page. Elements
containing source code must be "pre" elements with a "class" attribute of
"sh_LANGUAGE", where LANGUAGE is a valid language identifier; e.g., "sh_java"
identifies the element as containing "java" language source code.
*/
function sh_highlightDocument(prefix, suffix) {
  var nodeList = document.getElementsByTagName('pre');
  for (var i = 0; i < nodeList.length; i++) {
    var element = nodeList.item(i);
    var htmlClasses = sh_getClasses(element);
    for (var j = 0; j < htmlClasses.length; j++) {
      var htmlClass = htmlClasses[j].toLowerCase();
      if (htmlClass === 'sh_sourcecode') {
        continue;
      }
      if (htmlClass.substr(0, 3) === 'sh_') {
        var language = htmlClass.substring(3);
        if (language in sh_languages) {
          sh_highlightElement(element, sh_languages[language]);
        }
        else if (typeof(prefix) === 'string' && typeof(suffix) === 'string') {
          sh_load(language, element, prefix, suffix);
        }
        else {
          throw 'Found
 element with class="' + htmlClass + '", but no such language exists';
        }
        break;
      }
    }
  }
}
<commit_msg>Remove windows line endings.<commit_after>/*
SHJS - Syntax Highlighting in JavaScript
Copyright (C) 2007, 2008 gnombat@users.sourceforge.net
License: http://shjs.sourceforge.net/doc/gplv3.html
*/

if (! this.sh_languages) {
  this.sh_languages = {};
}
var sh_requests = {};

function sh_isEmailAddress(url) {
  if (/^mailto:/.test(url)) {
    return false;
  }
  return url.indexOf('@') !== -1;
}

function sh_setHref(tags, numTags, inputString) {
  var url = inputString.substring(tags[numTags - 2].pos, tags[numTags - 1].pos);
  if (url.length >= 2 && url.charAt(0) === '<' && url.charAt(url.length - 1) === '>') {
    url = url.substr(1, url.length - 2);
  }
  if (sh_isEmailAddress(url)) {
    url = 'mailto:' + url;
  }
  tags[numTags - 2].node.href = url;
}

/*
Konqueror has a bug where the regular expression /$/g will not match at the end
of a line more than once:

  var regex = /$/g;
  var match;

  var line = '1234567890';
  regex.lastIndex = 10;
  match = regex.exec(line);

  var line2 = 'abcde';
  regex.lastIndex = 5;
  match = regex.exec(line2);  // fails
*/
function sh_konquerorExec(s) {
  var result = [''];
  result.index = s.length;
  result.input = s;
  return result;
}

/**
Highlights all elements containing source code in a text string.  The return
value is an array of objects, each representing an HTML start or end tag.  Each
object has a property named pos, which is an integer representing the text
offset of the tag. Every start tag also has a property named node, which is the
DOM element started by the tag. End tags do not have this property.
@param  inputString  a text string
@param  language  a language definition object
@return  an array of tag objects
*/
function sh_highlightString(inputString, language) {
  if (/Konqueror/.test(navigator.userAgent)) {
    if (! language.konquered) {
      for (var s = 0; s < language.length; s++) {
        for (var p = 0; p < language[s].length; p++) {
          var r = language[s][p][0];
          if (r.source === '$') {
            r.exec = sh_konquerorExec;
          }
        }
      }
      language.konquered = true;
    }
  }

  var a = document.createElement('a');
  var span = document.createElement('span');

  // the result
  var tags = [];
  var numTags = 0;

  // each element is a pattern object from language
  var patternStack = [];

  // the current position within inputString
  var pos = 0;

  // the name of the current style, or null if there is no current style
  var currentStyle = null;

  var output = function(s, style) {
    var length = s.length;
    // this is more than just an optimization - we don't want to output empty  elements
    if (length === 0) {
      return;
    }
    if (! style) {
      var stackLength = patternStack.length;
      if (stackLength !== 0) {
        var pattern = patternStack[stackLength - 1];
        // check whether this is a state or an environment
        if (! pattern[3]) {
          // it's not a state - it's an environment; use the style for this environment
          style = pattern[1];
        }
      }
    }
    if (currentStyle !== style) {
      if (currentStyle) {
        tags[numTags++] = {pos: pos};
        if (currentStyle === 'sh_url') {
          sh_setHref(tags, numTags, inputString);
        }
      }
      if (style) {
        var clone;
        if (style === 'sh_url') {
          clone = a.cloneNode(false);
        }
        else {
          clone = span.cloneNode(false);
        }
        clone.className = style;
        tags[numTags++] = {node: clone, pos: pos};
      }
    }
    pos += length;
    currentStyle = style;
  };

  var endOfLinePattern = /\r\n|\r|\n/g;
  endOfLinePattern.lastIndex = 0;
  var inputStringLength = inputString.length;
  while (pos < inputStringLength) {
    var start = pos;
    var end;
    var startOfNextLine;
    var endOfLineMatch = endOfLinePattern.exec(inputString);
    if (endOfLineMatch === null) {
      end = inputStringLength;
      startOfNextLine = inputStringLength;
    }
    else {
      end = endOfLineMatch.index;
      startOfNextLine = endOfLinePattern.lastIndex;
    }

    var line = inputString.substring(start, end);

    var matchCache = [];
    for (;;) {
      var posWithinLine = pos - start;

      var stateIndex;
      var stackLength = patternStack.length;
      if (stackLength === 0) {
        stateIndex = 0;
      }
      else {
        // get the next state
        stateIndex = patternStack[stackLength - 1][2];
      }

      var state = language[stateIndex];
      var numPatterns = state.length;
      var mc = matchCache[stateIndex];
      if (! mc) {
        mc = matchCache[stateIndex] = [];
      }
      var bestMatch = null;
      var bestPatternIndex = -1;
      for (var i = 0; i < numPatterns; i++) {
        var match;
        if (i < mc.length && (mc[i] === null || posWithinLine <= mc[i].index)) {
          match = mc[i];
        }
        else {
          var regex = state[i][0];
          regex.lastIndex = posWithinLine;
          match = regex.exec(line);
          mc[i] = match;
        }
        if (match !== null && (bestMatch === null || match.index < bestMatch.index)) {
          bestMatch = match;
          bestPatternIndex = i;
          if (match.index === posWithinLine) {
            break;
          }
        }
      }

      if (bestMatch === null) {
        output(line.substring(posWithinLine), null);
        break;
      }
      else {
        // got a match
        if (bestMatch.index > posWithinLine) {
          output(line.substring(posWithinLine, bestMatch.index), null);
        }

        var pattern = state[bestPatternIndex];

        var newStyle = pattern[1];
        var matchedString;
        if (newStyle instanceof Array) {
          for (var subexpression = 0; subexpression < newStyle.length; subexpression++) {
            matchedString = bestMatch[subexpression + 1];
            output(matchedString, newStyle[subexpression]);
          }
        }
        else {
          matchedString = bestMatch[0];
          output(matchedString, newStyle);
        }

        switch (pattern[2]) {
        case -1:
          // do nothing
          break;
        case -2:
          // exit
          patternStack.pop();
          break;
        case -3:
          // exitall
          patternStack.length = 0;
          break;
        default:
          // this was the start of a delimited pattern or a state/environment
          patternStack.push(pattern);
          break;
        }
      }
    }

    // end of the line
    if (currentStyle) {
      tags[numTags++] = {pos: pos};
      if (currentStyle === 'sh_url') {
        sh_setHref(tags, numTags, inputString);
      }
      currentStyle = null;
    }
    pos = startOfNextLine;
  }

  return tags;
}

////////////////////////////////////////////////////////////////////////////////
// DOM-dependent functions

function sh_getClasses(element) {
  var result = [];
  var htmlClass = element.className;
  if (htmlClass && htmlClass.length > 0) {
    var htmlClasses = htmlClass.split(' ');
    for (var i = 0; i < htmlClasses.length; i++) {
      if (htmlClasses[i].length > 0) {
        result.push(htmlClasses[i]);
      }
    }
  }
  return result;
}

function sh_addClass(element, name) {
  var htmlClasses = sh_getClasses(element);
  for (var i = 0; i < htmlClasses.length; i++) {
    if (name.toLowerCase() === htmlClasses[i].toLowerCase()) {
      return;
    }
  }
  htmlClasses.push(name);
  element.className = htmlClasses.join(' ');
}

/**
Extracts the tags from an HTML DOM NodeList.
@param  nodeList  a DOM NodeList
@param  result  an object with text, tags and pos properties
*/
function sh_extractTagsFromNodeList(nodeList, result) {
  var length = nodeList.length;
  for (var i = 0; i < length; i++) {
    var node = nodeList.item(i);
    switch (node.nodeType) {
    case 1:
      if (node.nodeName.toLowerCase() === 'br') {
        var terminator;
        if (/MSIE/.test(navigator.userAgent)) {
          terminator = '\r';
        }
        else {
          terminator = '\n';
        }
        result.text.push(terminator);
        result.pos++;
      }
      else {
        result.tags.push({node: node.cloneNode(false), pos: result.pos});
        sh_extractTagsFromNodeList(node.childNodes, result);
        result.tags.push({pos: result.pos});
      }
      break;
    case 3:
    case 4:
      result.text.push(node.data);
      result.pos += node.length;
      break;
    }
  }
}

/**
Extracts the tags from the text of an HTML element. The extracted tags will be
returned as an array of tag objects. See sh_highlightString for the format of
the tag objects.
@param  element  a DOM element
@param  tags  an empty array; the extracted tag objects will be returned in it
@return  the text of the element
@see  sh_highlightString
*/
function sh_extractTags(element, tags) {
  var result = {};
  result.text = [];
  result.tags = tags;
  result.pos = 0;
  sh_extractTagsFromNodeList(element.childNodes, result);
  return result.text.join('');
}

/**
Merges the original tags from an element with the tags produced by highlighting.
@param  originalTags  an array containing the original tags
@param  highlightTags  an array containing the highlighting tags - these must not overlap
@result  an array containing the merged tags
*/
function sh_mergeTags(originalTags, highlightTags) {
  var numOriginalTags = originalTags.length;
  if (numOriginalTags === 0) {
    return highlightTags;
  }

  var numHighlightTags = highlightTags.length;
  if (numHighlightTags === 0) {
    return originalTags;
  }

  var result = [];
  var originalIndex = 0;
  var highlightIndex = 0;

  while (originalIndex < numOriginalTags && highlightIndex < numHighlightTags) {
    var originalTag = originalTags[originalIndex];
    var highlightTag = highlightTags[highlightIndex];

    if (originalTag.pos <= highlightTag.pos) {
      result.push(originalTag);
      originalIndex++;
    }
    else {
      result.push(highlightTag);
      if (highlightTags[highlightIndex + 1].pos <= originalTag.pos) {
        highlightIndex++;
        result.push(highlightTags[highlightIndex]);
        highlightIndex++;
      }
      else {
        // new end tag
        result.push({pos: originalTag.pos});

        // new start tag
        highlightTags[highlightIndex] = {node: highlightTag.node.cloneNode(false), pos: originalTag.pos};
      }
    }
  }

  while (originalIndex < numOriginalTags) {
    result.push(originalTags[originalIndex]);
    originalIndex++;
  }

  while (highlightIndex < numHighlightTags) {
    result.push(highlightTags[highlightIndex]);
    highlightIndex++;
  }

  return result;
}

/**
Inserts tags into text.
@param  tags  an array of tag objects
@param  text  a string representing the text
@return  a DOM DocumentFragment representing the resulting HTML
*/
function sh_insertTags(tags, text) {
  var doc = document;

  var result = document.createDocumentFragment();
  var tagIndex = 0;
  var numTags = tags.length;
  var textPos = 0;
  var textLength = text.length;
  var currentNode = result;

  // output one tag or text node every iteration
  while (textPos < textLength || tagIndex < numTags) {
    var tag;
    var tagPos;
    if (tagIndex < numTags) {
      tag = tags[tagIndex];
      tagPos = tag.pos;
    }
    else {
      tagPos = textLength;
    }

    if (tagPos <= textPos) {
      // output the tag
      if (tag.node) {
        // start tag
        var newNode = tag.node;
        currentNode.appendChild(newNode);
        currentNode = newNode;
      }
      else {
        // end tag
        currentNode = currentNode.parentNode;
      }
      tagIndex++;
    }
    else {
      // output text
      currentNode.appendChild(doc.createTextNode(text.substring(textPos, tagPos)));
      textPos = tagPos;
    }
  }

  return result;
}

/**
Highlights an element containing source code.  Upon completion of this function,
the element will have been placed in the "sh_sourceCode" class.
@param  element  a DOM
 element containing the source code to be highlighted
@param  language  a language definition object
*/
function sh_highlightElement(element, language) {
  sh_addClass(element, 'sh_sourceCode');
  var originalTags = [];
  var inputString = sh_extractTags(element, originalTags);
  var highlightTags = sh_highlightString(inputString, language);
  var tags = sh_mergeTags(originalTags, highlightTags);
  var documentFragment = sh_insertTags(tags, inputString);
  while (element.hasChildNodes()) {
    element.removeChild(element.firstChild);
  }
  element.appendChild(documentFragment);
}

function sh_getXMLHttpRequest() {
  if (window.ActiveXObject) {
    return new ActiveXObject('Msxml2.XMLHTTP');
  }
  else if (window.XMLHttpRequest) {
    return new XMLHttpRequest();
  }
  throw 'No XMLHttpRequest implementation available';
}

function sh_load(language, element, prefix, suffix) {
  if (language in sh_requests) {
    sh_requests[language].push(element);
    return;
  }
  sh_requests[language] = [element];
  var request = sh_getXMLHttpRequest();
  var url = prefix + 'sh_' + language + suffix;
  request.open('GET', url, true);
  request.onreadystatechange = function () {
    if (request.readyState === 4) {
      try {
        if (! request.status || request.status === 200) {
          eval(request.responseText);
          var elements = sh_requests[language];
          for (var i = 0; i < elements.length; i++) {
            sh_highlightElement(elements[i], sh_languages[language]);
          }
        }
        else {
          throw 'HTTP error: status ' + request.status;
        }
      }
      finally {
        request = null;
      }
    }
  };
  request.send(null);
}

/**
Highlights all elements containing source code on the current page. Elements
containing source code must be "pre" elements with a "class" attribute of
"sh_LANGUAGE", where LANGUAGE is a valid language identifier; e.g., "sh_java"
identifies the element as containing "java" language source code.
*/
function sh_highlightDocument(prefix, suffix) {
  var nodeList = document.getElementsByTagName('pre');
  for (var i = 0; i < nodeList.length; i++) {
    var element = nodeList.item(i);
    var htmlClasses = sh_getClasses(element);
    for (var j = 0; j < htmlClasses.length; j++) {
      var htmlClass = htmlClasses[j].toLowerCase();
      if (htmlClass === 'sh_sourcecode') {
        continue;
      }
      if (htmlClass.substr(0, 3) === 'sh_') {
        var language = htmlClass.substring(3);
        if (language in sh_languages) {
          sh_highlightElement(element, sh_languages[language]);
        }
        else if (typeof(prefix) === 'string' && typeof(suffix) === 'string') {
          sh_load(language, element, prefix, suffix);
        }
        else {
          throw 'Found
 element with class="' + htmlClass + '", but no such language exists';
        }
        break;
      }
    }
  }
}
<|endoftext|>


<commit_before>/** @format */
const korpApp = angular.module("korpApp")
korpApp.factory("kwicDownload", function() {
    const emptyRow = function(length) {
        return _.fill(new Array(length), "")
    }

    const createFile = function(dataType, fileType, content) {
        const date = moment().format("YYYYDDMM_HHmmss")
        const filename = `korp_${dataType}_${date}.${fileType}`
        const blobURL = window.URL.createObjectURL(
            new Blob([content], { type: `text/${fileType}` })
        )
        return [filename, blobURL]
    }

    const padRows = (data, length) =>
        _.map(data, function(row) {
            const newRow = emptyRow(length)
            newRow[0] = row
            return newRow
        })

    const createSearchInfo = function(requestInfo, totalHits) {
        const rows = []
        const fields = ["cqp", "context", "within", "sorting", "start", "end", "hits"]
        for (let field of fields) {
            var row
            if (field === "cqp") {
                row = `## CQP query: ${requestInfo.cqp}`
            }
            if (field === "context") {
                row = `## context: ${requestInfo.default_context}`
            }
            if (field === "within") {
                row = `## within: ${requestInfo.default_within}`
            }
            if (field === "sorting") {
                const sorting = requestInfo.sort || "none"
                row = `## sorting: ${sorting}`
            }
            if (field === "start") {
                row = `## start: ${requestInfo.start}`
            }
            if (field === "end") {
                const cqpQuery = ""
                row = `## end: ${requestInfo.end}`
            }
            if (field === "hits") {
                row = `## Total hits: ${totalHits}`
            }
            rows.push(row)
        }
        return rows
    }

    const transformDataToAnnotations = function(data, searchInfo) {
        const headers = _.filter(
            _.keys(data[1].tokens[0]),
            val =>
                val.indexOf("_") !== 0 &&
                val !== "structs" &&
                val !== "$$hashKey" &&
                val !== "position"
        )
        const columnCount = headers.length + 1
        let corpus
        const res = padRows(searchInfo, columnCount)
        res.push(["match"].concat(headers))
        for (let row of data) {
            if (row.tokens) {
                const textAttributes = []
                for (let attrName in row.structs) {
                    const attrValue = row.structs[attrName]
                    textAttributes.push(attrName + ': "' + attrValue + '"')
                }
                const hitInfo = emptyRow(columnCount)
                hitInfo[0] = `# ${corpus}; text attributes: ${textAttributes.join(", ")}`
                res.push(hitInfo)

                for (let token of row.tokens || []) {
                    var match
                    if (token.position >= row.match.start && token.position < row.match.end) {
                        match = "***"
                    } else {
                        match = ""
                    }
                    const newRow = [match]
                    for (let field of headers) {
                        newRow.push(token[field])
                    }
                    res.push(newRow)
                }
            } else if (row.newCorpus) {
                corpus = row.newCorpus
            }
        }

        return res
    }

    const transformDataToKWIC = function(data, searchInfo) {
        let row
        let corpus
        const structHeaders = []
        let res = []
        for (row of data) {
            if (row.tokens) {
                if (row.isLinked) {
                    // parallell mode does not have matches or structs for the linked sentences
                    // current wordaround is to add all tokens to the left context
                    res.push(["", "", row.tokens.map(token => token.word).join(" "), "", ""])
                    continue
                }

                var attrName, token
                const leftContext = []
                const match = []
                const rightContext = []

                for (token of row.tokens.slice(0, row.match.start)) {
                    leftContext.push(token.word)
                }
                for (token of row.tokens.slice(row.match.start, row.match.end)) {
                    match.push(token.word)
                }
                for (token of row.tokens.slice(row.match.end, row.tokens.length)) {
                    rightContext.push(token.word)
                }

                const structs = []
                for (attrName in row.structs) {
                    if (!structHeaders.includes(attrName)) {
                        structHeaders.push(attrName)
                    }
                }
                for (attrName of structHeaders) {
                    if (attrName in row.structs) {
                        structs.push(row.structs[attrName])
                    } else {
                        structs.push("")
                    }
                }
                const newRow = [
                    corpus,
                    row.match.position,
                    leftContext.join(" "),
                    match.join(" "),
                    rightContext.join(" ")
                ].concat(structs)
                res.push(newRow)
            } else if (row.newCorpus) {
                corpus = row.newCorpus
            }
        }

        const headers = [
            "corpus",
            "match_position",
            "left context",
            "match",
            "right_context"
        ].concat(structHeaders)
        res = [headers].concat(res)

        res.push(emptyRow(headers.length))
        for (let row of padRows(searchInfo, headers.length)) {
            res.push(row)
        }

        return res
    }

    const transformData = function(dataType, data, requestInfo, totalHits) {
        const searchInfo = createSearchInfo(requestInfo, totalHits)
        if (dataType === "annotations") {
            return transformDataToAnnotations(data, searchInfo)
        }
        if (dataType === "kwic") {
            return transformDataToKWIC(data, searchInfo)
        }
    }

    const makeContent = function(fileType, transformedData) {
        let dataDelimiter
        if (fileType === "csv") {
            dataDelimiter = ","
        }
        if (fileType === "tsv") {
            dataDelimiter = "   "
        }

        const csv = new CSV(transformedData, {
            delimiter: dataDelimiter
        })

        return csv.encode()
    }

    // dataType: either "kwic" or "annotations"
    // fileType: either "csv" or "tsv"
    // data: json from the backend
    return {
        makeDownload(dataType, fileType, data, requestInfo, totalHits) {
            const tmp = transformData(dataType, data, requestInfo, totalHits)
            const tmp2 = makeContent(fileType, tmp)
            return createFile(dataType, fileType, tmp2)
        }
    }
})
<commit_msg>fix tab-separated kwic download<commit_after>/** @format */
const korpApp = angular.module("korpApp")
korpApp.factory("kwicDownload", function() {
    const emptyRow = function(length) {
        return _.fill(new Array(length), "")
    }

    const createFile = function(dataType, fileType, content) {
        const date = moment().format("YYYYDDMM_HHmmss")
        const filename = `korp_${dataType}_${date}.${fileType}`
        const blobURL = window.URL.createObjectURL(
            new Blob([content], { type: `text/${fileType}` })
        )
        return [filename, blobURL]
    }

    const padRows = (data, length) =>
        _.map(data, function(row) {
            const newRow = emptyRow(length)
            newRow[0] = row
            return newRow
        })

    const createSearchInfo = function(requestInfo, totalHits) {
        const rows = []
        const fields = ["cqp", "context", "within", "sorting", "start", "end", "hits"]
        for (let field of fields) {
            var row
            if (field === "cqp") {
                row = `## CQP query: ${requestInfo.cqp}`
            }
            if (field === "context") {
                row = `## context: ${requestInfo.default_context}`
            }
            if (field === "within") {
                row = `## within: ${requestInfo.default_within}`
            }
            if (field === "sorting") {
                const sorting = requestInfo.sort || "none"
                row = `## sorting: ${sorting}`
            }
            if (field === "start") {
                row = `## start: ${requestInfo.start}`
            }
            if (field === "end") {
                const cqpQuery = ""
                row = `## end: ${requestInfo.end}`
            }
            if (field === "hits") {
                row = `## Total hits: ${totalHits}`
            }
            rows.push(row)
        }
        return rows
    }

    const transformDataToAnnotations = function(data, searchInfo) {
        const headers = _.filter(
            _.keys(data[1].tokens[0]),
            val =>
                val.indexOf("_") !== 0 &&
                val !== "structs" &&
                val !== "$$hashKey" &&
                val !== "position"
        )
        const columnCount = headers.length + 1
        let corpus
        const res = padRows(searchInfo, columnCount)
        res.push(["match"].concat(headers))
        for (let row of data) {
            if (row.tokens) {
                const textAttributes = []
                for (let attrName in row.structs) {
                    const attrValue = row.structs[attrName]
                    textAttributes.push(attrName + ': "' + attrValue + '"')
                }
                const hitInfo = emptyRow(columnCount)
                hitInfo[0] = `# ${corpus}; text attributes: ${textAttributes.join(", ")}`
                res.push(hitInfo)

                for (let token of row.tokens || []) {
                    var match
                    if (token.position >= row.match.start && token.position < row.match.end) {
                        match = "***"
                    } else {
                        match = ""
                    }
                    const newRow = [match]
                    for (let field of headers) {
                        newRow.push(token[field])
                    }
                    res.push(newRow)
                }
            } else if (row.newCorpus) {
                corpus = row.newCorpus
            }
        }

        return res
    }

    const transformDataToKWIC = function(data, searchInfo) {
        let row
        let corpus
        const structHeaders = []
        let res = []
        for (row of data) {
            if (row.tokens) {
                if (row.isLinked) {
                    // parallell mode does not have matches or structs for the linked sentences
                    // current wordaround is to add all tokens to the left context
                    res.push(["", "", row.tokens.map(token => token.word).join(" "), "", ""])
                    continue
                }

                var attrName, token
                const leftContext = []
                const match = []
                const rightContext = []

                for (token of row.tokens.slice(0, row.match.start)) {
                    leftContext.push(token.word)
                }
                for (token of row.tokens.slice(row.match.start, row.match.end)) {
                    match.push(token.word)
                }
                for (token of row.tokens.slice(row.match.end, row.tokens.length)) {
                    rightContext.push(token.word)
                }

                const structs = []
                for (attrName in row.structs) {
                    if (!structHeaders.includes(attrName)) {
                        structHeaders.push(attrName)
                    }
                }
                for (attrName of structHeaders) {
                    if (attrName in row.structs) {
                        structs.push(row.structs[attrName])
                    } else {
                        structs.push("")
                    }
                }
                const newRow = [
                    corpus,
                    row.match.position,
                    leftContext.join(" "),
                    match.join(" "),
                    rightContext.join(" ")
                ].concat(structs)
                res.push(newRow)
            } else if (row.newCorpus) {
                corpus = row.newCorpus
            }
        }

        const headers = [
            "corpus",
            "match_position",
            "left context",
            "match",
            "right_context"
        ].concat(structHeaders)
        res = [headers].concat(res)

        res.push(emptyRow(headers.length))
        for (let row of padRows(searchInfo, headers.length)) {
            res.push(row)
        }

        return res
    }

    const transformData = function(dataType, data, requestInfo, totalHits) {
        const searchInfo = createSearchInfo(requestInfo, totalHits)
        if (dataType === "annotations") {
            return transformDataToAnnotations(data, searchInfo)
        }
        if (dataType === "kwic") {
            return transformDataToKWIC(data, searchInfo)
        }
    }

    const makeContent = function(fileType, transformedData) {
        let dataDelimiter
        if (fileType === "csv") {
            dataDelimiter = ","
        }
        if (fileType === "tsv") {
            dataDelimiter = "\t"
        }

        const csv = new CSV(transformedData, {
            delimiter: dataDelimiter
        })

        return csv.encode()
    }

    // dataType: either "kwic" or "annotations"
    // fileType: either "csv" or "tsv"
    // data: json from the backend
    return {
        makeDownload(dataType, fileType, data, requestInfo, totalHits) {
            const tmp = transformData(dataType, data, requestInfo, totalHits)
            const tmp2 = makeContent(fileType, tmp)
            return createFile(dataType, fileType, tmp2)
        }
    }
})
<|endoftext|>


<commit_before>"use strict";

app.factory('I18nService', function($window, $location) {
    var i18n = {
        enums: {
            veganCategory: {
                concise: {
                    vegan: {
                        en: "vegan",
                        de: "vegan",
                    },
                    vegetarian: {
                        en: "vegetarian",
                        de: "vegetarisch",
                    },
                    omnivorous: {
                        en: "omnivorous",
                        de: "omnivor",
                    },
                },
                verbose: {
                    vegan: {
                        en: "100% vegan",
                        de: "100% vegan",
                    },
                    vegetarian: {
                        en: "vegetarian, vegan declared",
                        de: "vegetarisch, vegan deklariert",
                    },
                    omnivorous: {
                        en: "omnivorous, vegan declared",
                        de: "omnivor, vegan deklariert",
                    },
                },
            },
            tag: {
                // Capitalized values because they are capitalized in the data source.
                Cafe: {
                    en: "Cafe",
                    de: "Café",
                },
                Eiscafe: {
                    en: "Ice cream shop",
                    de: "Eiscafé",
                },
                Imbiss: {
                    en: "Snack bar",
                    de: "Imbiss",
                },
                Restaurant: {
                    en: "Restaurant",
                    de: "Restaurant",
                },
            },
            weekday: {
                all: {
                    en: "All days",
                    de: "Alle Wochentage",
                },
                today: {
                    en: "Today",
                    de: "Heute",
                },
                "0": {
                    en: "Sunday",
                    de: "Sonntag",
                },
                "1": {
                    en: "Monday",
                    de: "Montag",
                },
                "2": {
                    en: "Tuesday",
                    de: "Dienstag",
                },
                "3": {
                    en: "Wednesday",
                    de: "Mittwoch",
                },
                "4": {
                    en: "Thursday",
                    de: "Donnerstag",
                },
                "5": {
                    en: "Friday",
                    de: "Freitag",
                },
                "6": {
                    en: "Saturday",
                    de: "Samstag",
                },
            },
        },
        search: {
            text: {
                placeholder: {
                    en: "Search text",
                    de: "Suchtext",
                },
                namesOnly: {
                    en: "Search names only",
                    de: "Nur Namen durchsuchen",
                },
            },
        },
        category: {
            header: {
                en: "Category",
                de: "Kategorie",
            },
        },
        tag: {
            header: {
                en: "Type",
                de: "Art",
            },
        },
        features: {
            organic: {
                en: "Organic",
                de: "Bioware",
            },
            glutenFree: {
                en: "Gluten-free food",
                de: "glutenfreie Speisen",
            },
            dog: {
                en: "Dogs allowed",
                de: "Hunde erlaubt",
            },
            childChair: {
                en: "Child chair",
                de: "Kinderstuhl",
            },
            handicappedAccessible: {
                en: "Suitable for wheelchairs",
                de: "Rollstuhlgeeignet",
            },
            handicappedAccessibleWc: {
                en: "Toilet suitable for wheelchairs",
                de: "Rollstuhlgeeignetes WC",
            },
            delivery: {
                en: "Delivery service",
                de: "Lieferdienst",
            },
            catering: {
                en: "Catering",
                de: "Catering",
            },
            wlan: {
                en: "Wi-Fi",
                de: "WLAN",
            },
            review: {
                en: "With Review (German)",
                de: "Mit Rezension",
            },
        },
        openingTimes: {
            header: {
                en: "Open",
                de: "Geöffnet",
            },
            timePlaceholder: {
                openNow: {
                    en: "- Now -",
                    de: "- Jetzt -",
                },
                notOpenNow: {
                    en: "hh:mm (Time)",
                    de: "hh:mm (Uhrzeit)",
                },
            },
            invalidTime: {
                en: "Invalid time (ignored); Format: hh:mm",
                de: "Ungültige Zeit (wird ignoriert); Format: hh:mm",
            },
            nowCheckbox: {
                en: "Now",
                de: "Jetzt",
            },
            isOpenToday: {
                en: "Open today",
                de: "Heute geöffnet",
            },
            isClosedToday: {
                en: "Closed today",
                de: "Heute geschlossen",
            },
            isClosed: {
                en: "Closed",
                de: "Geschlossen",
            },
        },
        geolocation: {
            header: {
                en: "Geolocation",
                de: "Standorterkennung",
            },
            currentLocation: {
                en: "Current location",
                de: "Aktueller Standort",
            },
            distance: {
                en: "Distance",
                de: "Entfernung",
            },
            detecting: {
                en: "Geolocating...",
                de: "Ermittle Standort...",
            },
            theError: {
                en: "Geolocation impossible",
                de: "Standortzugriff nicht möglich",
            },
            PERMISSION_DENIED: {
                en: "Permission denied",
                de: "Zugriff verweigert",
            },
            POSITION_UNAVAILABLE: {
                en: "Position unavailable",
                de: "Standort nicht verfügbar",
            },
            TIMEOUT: {
                en: "Timeout",
                de: "Zeitüberschreitung",
            },
        },
        sortBy: {
            header: {
                en: "Sort by",
                de: "Sortierung",
            },
            name: {
                en: "Name",
                de: "Name",
            },
            distance: {
                en: "Distance",
                de: "Entfernung",
            },
            distanceRequiresGeolocation: {
                en: "Geolocation required",
                de: "Standorterkennung erforderlich",
            },
        },
        resultsLength: {
            en: " results of ",
            de: " Treffer von ",
        },
        infoWindow: {
            distance: {
                en: "Distance",
                de: "Entfernung",
            },
            openingTimes: {
                en: "Opening times",
                de: "Öffnungszeiten",
            },
            review: {
                en: "Review (German)",
                de: "Rezension",
            },
        },
        footer: {
            infoPrefix: {
                en: "The map contains ",
                de: "Die Karte umfasst insgesamt ",
            },
            infoPostfix: {
                en: " locations altogether. Vegan food is declared.",
                de: " Restaurants/Cafés usw. Die veganen Speisen sind deklariert.",
            },
            feedback: {
                en: "Problems and suggestions to",
                de: "Probleme und Verbesserungsvorschläge bitte an",
            },
            language: {
                // A bit dirty, but we want to display the language in its language.
                en: {
                    en: "English",
                    de: "English",
                },
                de: {
                    en: "Deutsch",
                    de: "Deutsch",
                },
            },
        },
    };

    var transformedI18n = getTransformedI18n(global_language);

    function getTransformedI18n(language) {
        return {
            // This kinda sucks. TODO.
            enums: {
                veganCategory: {
                    concise: {
                        vegan: i18n.enums.veganCategory.concise.vegan[language],
                        vegetarian: i18n.enums.veganCategory.concise.vegetarian[language],
                        omnivorous: i18n.enums.veganCategory.concise.omnivorous[language],
                    },
                    verbose: {
                        vegan: i18n.enums.veganCategory.verbose.vegan[language],
                        vegetarian: i18n.enums.veganCategory.verbose.vegetarian[language],
                        omnivorous: i18n.enums.veganCategory.verbose.omnivorous[language],
                    },
                },
                tag: {
                    Cafe: i18n.enums.tag.Cafe[language],
                    Eiscafe: i18n.enums.tag.Eiscafe[language],
                    Imbiss: i18n.enums.tag.Imbiss[language],
                    Restaurant: i18n.enums.tag.Restaurant[language],
                },
                weekday: {
                    all: i18n.enums.weekday.all[language],
                    today: i18n.enums.weekday.today[language],
                    "0": i18n.enums.weekday["0"][language],
                    "1": i18n.enums.weekday["1"][language],
                    "2": i18n.enums.weekday["2"][language],
                    "3": i18n.enums.weekday["3"][language],
                    "4": i18n.enums.weekday["4"][language],
                    "5": i18n.enums.weekday["5"][language],
                    "6": i18n.enums.weekday["6"][language],
                },
            },
            search: {
                text: {
                    placeholder: i18n.search.text.placeholder[language],
                    namesOnly: i18n.search.text.namesOnly[language],
                },
            },
            category: {
                header: i18n.category.header[language],
            },
            tag: {
                header: i18n.tag.header[language],
            },
            features: {
                organic: i18n.features.organic[language],
                glutenFree: i18n.features.glutenFree[language],
                dog: i18n.features.dog[language],
                childChair: i18n.features.childChair[language],
                handicappedAccessible: i18n.features.handicappedAccessible[language],
                handicappedAccessibleWc: i18n.features.handicappedAccessibleWc[language],
                delivery: i18n.features.delivery[language],
                catering: i18n.features.catering[language],
                wlan: i18n.features.wlan[language],
                review: i18n.features.review[language],
            },
            openingTimes: {
                header: i18n.openingTimes.header[language],
                timePlaceholder: {
                    openNow: i18n.openingTimes.timePlaceholder.openNow[language],
                    notOpenNow: i18n.openingTimes.timePlaceholder.notOpenNow[language],
                },
                invalidTime: i18n.openingTimes.invalidTime[language],
                nowCheckbox: i18n.openingTimes.nowCheckbox[language],
                isOpenToday: i18n.openingTimes.isOpenToday[language],
                isClosedToday: i18n.openingTimes.isClosedToday[language],
                isClosed: i18n.openingTimes.isClosed[language],
            },
            geolocation: {
                header: i18n.geolocation.header[language],
                currentLocation: i18n.geolocation.currentLocation[language],
                distance: i18n.geolocation.distance[language],
                detecting: i18n.geolocation.detecting[language],
                theError: i18n.geolocation.theError[language],
                PERMISSION_DENIED: i18n.geolocation.PERMISSION_DENIED[language],
                POSITION_UNAVAILABLE: i18n.geolocation.POSITION_UNAVAILABLE[language],
                TIMEOUT: i18n.geolocation.TIMEOUT[language],
            },
            sortBy: {
                header: i18n.sortBy.header[language],
                name: i18n.sortBy.name[language],
                distance: i18n.sortBy.distance[language],
                distanceRequiresGeolocation: i18n.sortBy.distanceRequiresGeolocation[language],
            },
            resultsLength: i18n.resultsLength[language],
            infoWindow: {
                distance: i18n.infoWindow.distance[language],
                openingTimes: i18n.infoWindow.openingTimes[language],
                review: i18n.infoWindow.review[language],
            },
            footer: {
                infoPrefix: i18n.footer.infoPrefix[language],
                infoPostfix: i18n.footer.infoPostfix[language],
                feedback: i18n.footer.feedback[language],
                language: {
                    en: i18n.footer.language.en[language],
                    de: i18n.footer.language.de[language],
                }
            },
        };
    }

    return {
        setLanguage: function(language) {
            if (localStorage) {
                localStorage.setItem("lang", language);
                $location.search("lang", null);
            } else {
                $location.search("lang", language);
            }
            $window.location.href = $location.absUrl();
            $window.location.reload();
        },
        getLanguage: function() {
            return global_language;
        },
        getI18n: function() {
            return transformedI18n;
        },
        formatNumberString: function(numberString) {
            return global_language === "en"? numberString : numberString.replace(/\./, ",");
        },
        abbreviateWeekDay: function(weekday) {
            var charCount = global_language === "en" ? 3 : 2;
            return weekday.substring(0, charCount);
        },
        formatTimeInterval: function(beginDate, endDate) {
            var extraLongHyphen = "–"; // Your editor may display this as a regular hyphen.
            var separator = " " + extraLongHyphen + " ";
            var postfix = global_language === "en" ? "" : " Uhr";
            return formatTime(beginDate) + separator + formatTime(endDate) + postfix;

            function formatTime(date) {
                var h = date.getHours();
                var m = date.getMinutes();
                if (global_language === "en") {
                    if (m === 0) {
                        if (h === 0) {
                            return "12 midnight";
                        } else if (h < 12) {
                            return h + " am";
                        } else if (h === 12) {
                            return "12 noon";
                        } else {
                            return (h - 12) + " pm";
                        }
                    } else {
                        if (h < 12) {
                            return h + ":" + pad(m) + " am";
                        } else if (h === 12) {
                            return h + ":" + pad(m) + " pm";
                        } else {
                            return (h - 12) + ":" + pad(m) + " pm";
                        }
                    }
                } else {
                    if (m === 0) {
                        return h;
                    } else {
                        return h + ":" + pad(m);
                    }
                }

                function pad(n) {
                    return n < 10 ? "0" + n : n;
                }
            }
        }
    };
});
<commit_msg>"vegan declared" -> "vegan declaration" (as requested by Christiane)<commit_after>"use strict";

app.factory('I18nService', function($window, $location) {
    var i18n = {
        enums: {
            veganCategory: {
                concise: {
                    vegan: {
                        en: "vegan",
                        de: "vegan",
                    },
                    vegetarian: {
                        en: "vegetarian",
                        de: "vegetarisch",
                    },
                    omnivorous: {
                        en: "omnivorous",
                        de: "omnivor",
                    },
                },
                verbose: {
                    vegan: {
                        en: "100% vegan",
                        de: "100% vegan",
                    },
                    vegetarian: {
                        en: "vegetarian, vegan declaration",
                        de: "vegetarisch, vegan deklariert",
                    },
                    omnivorous: {
                        en: "omnivorous, vegan declaration",
                        de: "omnivor, vegan deklariert",
                    },
                },
            },
            tag: {
                // Capitalized values because they are capitalized in the data source.
                Cafe: {
                    en: "Cafe",
                    de: "Café",
                },
                Eiscafe: {
                    en: "Ice cream shop",
                    de: "Eiscafé",
                },
                Imbiss: {
                    en: "Snack bar",
                    de: "Imbiss",
                },
                Restaurant: {
                    en: "Restaurant",
                    de: "Restaurant",
                },
            },
            weekday: {
                all: {
                    en: "All days",
                    de: "Alle Wochentage",
                },
                today: {
                    en: "Today",
                    de: "Heute",
                },
                "0": {
                    en: "Sunday",
                    de: "Sonntag",
                },
                "1": {
                    en: "Monday",
                    de: "Montag",
                },
                "2": {
                    en: "Tuesday",
                    de: "Dienstag",
                },
                "3": {
                    en: "Wednesday",
                    de: "Mittwoch",
                },
                "4": {
                    en: "Thursday",
                    de: "Donnerstag",
                },
                "5": {
                    en: "Friday",
                    de: "Freitag",
                },
                "6": {
                    en: "Saturday",
                    de: "Samstag",
                },
            },
        },
        search: {
            text: {
                placeholder: {
                    en: "Search text",
                    de: "Suchtext",
                },
                namesOnly: {
                    en: "Search names only",
                    de: "Nur Namen durchsuchen",
                },
            },
        },
        category: {
            header: {
                en: "Category",
                de: "Kategorie",
            },
        },
        tag: {
            header: {
                en: "Type",
                de: "Art",
            },
        },
        features: {
            organic: {
                en: "Organic",
                de: "Bioware",
            },
            glutenFree: {
                en: "Gluten-free food",
                de: "glutenfreie Speisen",
            },
            dog: {
                en: "Dogs allowed",
                de: "Hunde erlaubt",
            },
            childChair: {
                en: "Child chair",
                de: "Kinderstuhl",
            },
            handicappedAccessible: {
                en: "Suitable for wheelchairs",
                de: "Rollstuhlgeeignet",
            },
            handicappedAccessibleWc: {
                en: "Toilet suitable for wheelchairs",
                de: "Rollstuhlgeeignetes WC",
            },
            delivery: {
                en: "Delivery service",
                de: "Lieferdienst",
            },
            catering: {
                en: "Catering",
                de: "Catering",
            },
            wlan: {
                en: "Wi-Fi",
                de: "WLAN",
            },
            review: {
                en: "With Review (German)",
                de: "Mit Rezension",
            },
        },
        openingTimes: {
            header: {
                en: "Open",
                de: "Geöffnet",
            },
            timePlaceholder: {
                openNow: {
                    en: "- Now -",
                    de: "- Jetzt -",
                },
                notOpenNow: {
                    en: "hh:mm (Time)",
                    de: "hh:mm (Uhrzeit)",
                },
            },
            invalidTime: {
                en: "Invalid time (ignored); Format: hh:mm",
                de: "Ungültige Zeit (wird ignoriert); Format: hh:mm",
            },
            nowCheckbox: {
                en: "Now",
                de: "Jetzt",
            },
            isOpenToday: {
                en: "Open today",
                de: "Heute geöffnet",
            },
            isClosedToday: {
                en: "Closed today",
                de: "Heute geschlossen",
            },
            isClosed: {
                en: "Closed",
                de: "Geschlossen",
            },
        },
        geolocation: {
            header: {
                en: "Geolocation",
                de: "Standorterkennung",
            },
            currentLocation: {
                en: "Current location",
                de: "Aktueller Standort",
            },
            distance: {
                en: "Distance",
                de: "Entfernung",
            },
            detecting: {
                en: "Geolocating...",
                de: "Ermittle Standort...",
            },
            theError: {
                en: "Geolocation impossible",
                de: "Standortzugriff nicht möglich",
            },
            PERMISSION_DENIED: {
                en: "Permission denied",
                de: "Zugriff verweigert",
            },
            POSITION_UNAVAILABLE: {
                en: "Position unavailable",
                de: "Standort nicht verfügbar",
            },
            TIMEOUT: {
                en: "Timeout",
                de: "Zeitüberschreitung",
            },
        },
        sortBy: {
            header: {
                en: "Sort by",
                de: "Sortierung",
            },
            name: {
                en: "Name",
                de: "Name",
            },
            distance: {
                en: "Distance",
                de: "Entfernung",
            },
            distanceRequiresGeolocation: {
                en: "Geolocation required",
                de: "Standorterkennung erforderlich",
            },
        },
        resultsLength: {
            en: " results of ",
            de: " Treffer von ",
        },
        infoWindow: {
            distance: {
                en: "Distance",
                de: "Entfernung",
            },
            openingTimes: {
                en: "Opening times",
                de: "Öffnungszeiten",
            },
            review: {
                en: "Review (German)",
                de: "Rezension",
            },
        },
        footer: {
            infoPrefix: {
                en: "The map contains ",
                de: "Die Karte umfasst insgesamt ",
            },
            infoPostfix: {
                en: " locations altogether. Vegan food is declared.",
                de: " Restaurants/Cafés usw. Die veganen Speisen sind deklariert.",
            },
            feedback: {
                en: "Problems and suggestions to",
                de: "Probleme und Verbesserungsvorschläge bitte an",
            },
            language: {
                // A bit dirty, but we want to display the language in its language.
                en: {
                    en: "English",
                    de: "English",
                },
                de: {
                    en: "Deutsch",
                    de: "Deutsch",
                },
            },
        },
    };

    var transformedI18n = getTransformedI18n(global_language);

    function getTransformedI18n(language) {
        return {
            // This kinda sucks. TODO.
            enums: {
                veganCategory: {
                    concise: {
                        vegan: i18n.enums.veganCategory.concise.vegan[language],
                        vegetarian: i18n.enums.veganCategory.concise.vegetarian[language],
                        omnivorous: i18n.enums.veganCategory.concise.omnivorous[language],
                    },
                    verbose: {
                        vegan: i18n.enums.veganCategory.verbose.vegan[language],
                        vegetarian: i18n.enums.veganCategory.verbose.vegetarian[language],
                        omnivorous: i18n.enums.veganCategory.verbose.omnivorous[language],
                    },
                },
                tag: {
                    Cafe: i18n.enums.tag.Cafe[language],
                    Eiscafe: i18n.enums.tag.Eiscafe[language],
                    Imbiss: i18n.enums.tag.Imbiss[language],
                    Restaurant: i18n.enums.tag.Restaurant[language],
                },
                weekday: {
                    all: i18n.enums.weekday.all[language],
                    today: i18n.enums.weekday.today[language],
                    "0": i18n.enums.weekday["0"][language],
                    "1": i18n.enums.weekday["1"][language],
                    "2": i18n.enums.weekday["2"][language],
                    "3": i18n.enums.weekday["3"][language],
                    "4": i18n.enums.weekday["4"][language],
                    "5": i18n.enums.weekday["5"][language],
                    "6": i18n.enums.weekday["6"][language],
                },
            },
            search: {
                text: {
                    placeholder: i18n.search.text.placeholder[language],
                    namesOnly: i18n.search.text.namesOnly[language],
                },
            },
            category: {
                header: i18n.category.header[language],
            },
            tag: {
                header: i18n.tag.header[language],
            },
            features: {
                organic: i18n.features.organic[language],
                glutenFree: i18n.features.glutenFree[language],
                dog: i18n.features.dog[language],
                childChair: i18n.features.childChair[language],
                handicappedAccessible: i18n.features.handicappedAccessible[language],
                handicappedAccessibleWc: i18n.features.handicappedAccessibleWc[language],
                delivery: i18n.features.delivery[language],
                catering: i18n.features.catering[language],
                wlan: i18n.features.wlan[language],
                review: i18n.features.review[language],
            },
            openingTimes: {
                header: i18n.openingTimes.header[language],
                timePlaceholder: {
                    openNow: i18n.openingTimes.timePlaceholder.openNow[language],
                    notOpenNow: i18n.openingTimes.timePlaceholder.notOpenNow[language],
                },
                invalidTime: i18n.openingTimes.invalidTime[language],
                nowCheckbox: i18n.openingTimes.nowCheckbox[language],
                isOpenToday: i18n.openingTimes.isOpenToday[language],
                isClosedToday: i18n.openingTimes.isClosedToday[language],
                isClosed: i18n.openingTimes.isClosed[language],
            },
            geolocation: {
                header: i18n.geolocation.header[language],
                currentLocation: i18n.geolocation.currentLocation[language],
                distance: i18n.geolocation.distance[language],
                detecting: i18n.geolocation.detecting[language],
                theError: i18n.geolocation.theError[language],
                PERMISSION_DENIED: i18n.geolocation.PERMISSION_DENIED[language],
                POSITION_UNAVAILABLE: i18n.geolocation.POSITION_UNAVAILABLE[language],
                TIMEOUT: i18n.geolocation.TIMEOUT[language],
            },
            sortBy: {
                header: i18n.sortBy.header[language],
                name: i18n.sortBy.name[language],
                distance: i18n.sortBy.distance[language],
                distanceRequiresGeolocation: i18n.sortBy.distanceRequiresGeolocation[language],
            },
            resultsLength: i18n.resultsLength[language],
            infoWindow: {
                distance: i18n.infoWindow.distance[language],
                openingTimes: i18n.infoWindow.openingTimes[language],
                review: i18n.infoWindow.review[language],
            },
            footer: {
                infoPrefix: i18n.footer.infoPrefix[language],
                infoPostfix: i18n.footer.infoPostfix[language],
                feedback: i18n.footer.feedback[language],
                language: {
                    en: i18n.footer.language.en[language],
                    de: i18n.footer.language.de[language],
                }
            },
        };
    }

    return {
        setLanguage: function(language) {
            if (localStorage) {
                localStorage.setItem("lang", language);
                $location.search("lang", null);
            } else {
                $location.search("lang", language);
            }
            $window.location.href = $location.absUrl();
            $window.location.reload();
        },
        getLanguage: function() {
            return global_language;
        },
        getI18n: function() {
            return transformedI18n;
        },
        formatNumberString: function(numberString) {
            return global_language === "en"? numberString : numberString.replace(/\./, ",");
        },
        abbreviateWeekDay: function(weekday) {
            var charCount = global_language === "en" ? 3 : 2;
            return weekday.substring(0, charCount);
        },
        formatTimeInterval: function(beginDate, endDate) {
            var extraLongHyphen = "–"; // Your editor may display this as a regular hyphen.
            var separator = " " + extraLongHyphen + " ";
            var postfix = global_language === "en" ? "" : " Uhr";
            return formatTime(beginDate) + separator + formatTime(endDate) + postfix;

            function formatTime(date) {
                var h = date.getHours();
                var m = date.getMinutes();
                if (global_language === "en") {
                    if (m === 0) {
                        if (h === 0) {
                            return "12 midnight";
                        } else if (h < 12) {
                            return h + " am";
                        } else if (h === 12) {
                            return "12 noon";
                        } else {
                            return (h - 12) + " pm";
                        }
                    } else {
                        if (h < 12) {
                            return h + ":" + pad(m) + " am";
                        } else if (h === 12) {
                            return h + ":" + pad(m) + " pm";
                        } else {
                            return (h - 12) + ":" + pad(m) + " pm";
                        }
                    }
                } else {
                    if (m === 0) {
                        return h;
                    } else {
                        return h + ":" + pad(m);
                    }
                }

                function pad(n) {
                    return n < 10 ? "0" + n : n;
                }
            }
        }
    };
});
<|endoftext|>


<commit_before>'use strict';

/**
 * @module core-servers
 */

var express = require('express');

/**
 * Defines an HTTP Server. This Class must not be used directly,
 * instead use one of the sub classes.
 *
 * @example
 *     var Server = process.require("app/server/servers/Server.js");
 *     function MyServer(app){
 *       Server.prototype.init.call(this);
 *     }
 *
 *     module.exports = MyServer;
 *     util.inherits(MyServer, Server);
 *
 * @class Server
 * @constructor
 * @param {Object} configuration Service configuration
 */
function Server(configuration) {

  /**
   * Server configuration object.
   *
   * @property configuration
   * @type Object
   */
  this.configuration = configuration;

  /**
   * Express application.
   *
   * @property app
   * @type Application
   */
  this.app = express();

  // Remove x-powered-by http header
  this.app.set('x-powered-by', false);

}

/**
 * Handles database available event.
 *
 * It assures that the database is loaded and can be accessed.
 *
 * @method onDatabaseAvailable
 * @param {Database} db The application database
 */
Server.prototype.onDatabaseAvailable = function() {
};

/**
 * Handles plugin available event.
 *
 * It assures that the given plugin's configuration is available.
 *
 * @example
 *     MyServer.prototype.onPluginAvailable(plugin){
 *       console.log(plugin);
 *       // {
 *       //   router: [Function],
 *       //   privateRouter: [Function],
 *       //   webServiceRouter: [Function],
 *       //   mountPath: "/publish",
 *       //   name: "publish",
 *       //   assetsDirectory: "/home/veo-labs/openveo/node_modules/@openveo/publish/public",
 *       //   i18nDirectory: "/home/veo-labs/openveo/node_modules/@openveo/publish/i18n",
 *       //   custom: [Object],
 *       //   webServiceScopes: [Object],
 *       //   permissions: [Array],
 *       //   viewsFolders: [Array],
 *       //   routes: [Array],
 *       //   privateRoutes: [Array],
 *       //   webServiceRoutes: [Array],
 *       //   entities: [Object],
 *       //   menu: [Array],
 *       //   scriptLibFiles: [Array],
 *       //   scriptFiles: [Array],
 *       //   cssFiles: [Array]
 *       // }
 *     };
 *
 * @method onPluginAvailable
 * @param {Object} plugin The available openveo plugin
 */
Server.prototype.onPluginAvailable = function() {
};

/**
 * Handles plugin loaded event.
 *
 * It assures that the given plugin is fully loaded.
 *
 * @example
 *     MyServer.prototype.onPluginLoaded(plugin){
 *       console.log(plugin);
 *       // {
 *       //   router: [Function],
 *       //   privateRouter: [Function],
 *       //   webServiceRouter: [Function],
 *       //   mountPath: "/publish",
 *       //   name: "publish",
 *       //   assetsDirectory: "/home/veo-labs/openveo/node_modules/@openveo/publish/public",
 *       //   i18nDirectory: "/home/veo-labs/openveo/node_modules/@openveo/publish/i18n",
 *       //   custom: [Object],
 *       //   webServiceScopes: [Object],
 *       //   permissions: [Array],
 *       //   viewsFolders: [Array],
 *       //   routes: [Array],
 *       //   privateRoutes: [Array],
 *       //   webServiceRoutes: [Array],
 *       //   entities: [Object],
 *       //   menu: [Array],
 *       //   scriptLibFiles: [Array],
 *       //   scriptFiles: [Array],
 *       //   cssFiles: [Array]
 *       // }
 *     };
 *
 * @method onPluginLoaded
 * @param {Object} plugin The available openveo plugin
 */
Server.prototype.onPluginLoaded = function() {
};

/**
 * Handles plugins loaded event.
 *
 * It assures that all plugins are fully loaded.
 *
 * @method onPluginsLoaded
 */
Server.prototype.onPluginsLoaded = function() {
};

/**
 * Starts the server.
 *
 * @method startServer
 */
Server.prototype.startServer = function() {
  throw new Error('startServer method not implemented for this server');
};

module.exports = Server;
<commit_msg>Correct documentation on Server.js and remove method onPluginAvailable<commit_after>'use strict';

/**
 * @module core-servers
 */

var express = require('express');

/**
 * Defines an HTTP Server. This Class must not be used directly,
 * instead use one of the sub classes.
 *
 * @example
 *     var Server = process.require("app/server/servers/Server.js");
 *     function MyServer(app){
 *       Server.prototype.init.call(this);
 *     }
 *
 *     module.exports = MyServer;
 *     util.inherits(MyServer, Server);
 *
 * @class Server
 * @constructor
 * @param {Object} configuration Service configuration
 */
function Server(configuration) {

  /**
   * Server configuration object.
   *
   * @property configuration
   * @type Object
   */
  this.configuration = configuration;

  /**
   * Express application.
   *
   * @property app
   * @type Application
   */
  this.app = express();

  // Remove x-powered-by http header
  this.app.set('x-powered-by', false);

}

/**
 * Handles database available event.
 *
 * It assures that the database is loaded and can be accessed.
 *
 * @async
 * @param {Database} db The application database
 * @param {Function} callback Function to call when its done with:
 *  - **Error** An error if something went wrong
 */
Server.prototype.onDatabaseAvailable = function(db, callback) {
};

/**
 * Handles plugin loaded event.
 *
 * It assures that the given plugin is fully loaded.
 *
 * @example
 *     MyServer.prototype.onPluginLoaded(plugin){
 *       console.log(plugin);
 *       // {
 *       //   router: [Function],
 *       //   privateRouter: [Function],
 *       //   webServiceRouter: [Function],
 *       //   mountPath: "/publish",
 *       //   name: "publish",
 *       //   assetsDirectory: "/home/veo-labs/openveo/node_modules/@openveo/publish/public",
 *       //   i18nDirectory: "/home/veo-labs/openveo/node_modules/@openveo/publish/i18n",
 *       //   custom: [Object],
 *       //   webServiceScopes: [Object],
 *       //   permissions: [Array],
 *       //   viewsFolders: [Array],
 *       //   routes: [Array],
 *       //   privateRoutes: [Array],
 *       //   webServiceRoutes: [Array],
 *       //   entities: [Object],
 *       //   menu: [Array],
 *       //   scriptLibFiles: [Array],
 *       //   scriptFiles: [Array],
 *       //   cssFiles: [Array]
 *       // }
 *     };
 *
 * @method onPluginLoaded
 * @async
 * @param {Object} plugin The openveo plugin
 * @param {Function} callback Function to call when its done with:
 *  - **Error** An error if something went wrong
 */
Server.prototype.onPluginLoaded = function(plugin, callback) {
};

/**
 * Handles plugins loaded event.
 *
 * It assures that all plugins are fully loaded.
 *
 * @method onPluginsLoaded
 * @method async
 * @param {Function} callback Function to call when its done with:
 *  - **Error** An error if something went wrong
 */
Server.prototype.onPluginsLoaded = function(callback) {
};

/**
 * Starts the server.
 *
 * @method startServer
 * @async
 * @param {Function} callback Function to call when it's done with :
 *  - **Error** An error if something went wrong, null otherwise
 */
Server.prototype.startServer = function(callback) {
  throw new Error('startServer method not implemented for this server');
};

module.exports = Server;
<|endoftext|>