text:
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var EXPORTED_SYMBOLS = ["Microformats", "adr", "tag", "hCard", "hCalendar", "geo"];

var Microformats = {
  /* When a microformat is added, the name is placed in this list */
  list: [],
  /* Custom iterator so that microformats can be enumerated as */
  /* for (i in Microformats) */
  __iterator__: function () {
    for (let i=0; i < this.list.length; i++) {
      yield this.list[i];
    }
  },
  /**
   * Retrieves microformats objects of the given type from a document
   *
   * @param  name          The name of the microformat (required)
   * @param  rootElement   The DOM element at which to start searching (required)
   * @param  options       Literal object with the following options:
   *                       recurseExternalFrames - Whether or not to search child frames
   *                       that reference external pages (with a src attribute)
   *                       for microformats (optional - defaults to true)
   *                       showHidden -  Whether or not to add hidden microformat
   *                       (optional - defaults to false)
   *                       debug - Whether or not we are in debug mode (optional
   *                       - defaults to false)
   * @param  targetArray  An array of microformat objects to which is added the results (optional)
   * @return A new array of microformat objects or the passed in microformat
   *         object array with the new objects added
   */
  get: function(name, rootElement, options, targetArray) {
    function isAncestor(haystack, needle) {
      var parent = needle;
      while (parent = parent.parentNode) {
        /* We need to check parentNode because defaultView.frames[i].frameElement */
        /* isn't a real DOM node */
        if (parent == needle.parentNode) {
          return true;
        }
      }
      return false;
    }
    if (!Microformats[name] || !rootElement) {
      return;
    }
    targetArray = targetArray || [];

    /* Root element might not be the document - we need the document's default view */
    /* to get frames and to check their ancestry */
    var defaultView = rootElement.defaultView || rootElement.ownerDocument.defaultView;
    var rootDocument = rootElement.ownerDocument || rootElement;

    /* If recurseExternalFrames is undefined or true, look through all child frames for microformats */
    if (!options || !options.hasOwnProperty("recurseExternalFrames") || options.recurseExternalFrames) {
      if (defaultView && defaultView.frames.length > 0) {
        for (let i=0; i < defaultView.frames.length; i++) {
          if (isAncestor(rootDocument, defaultView.frames[i].frameElement)) {
            Microformats.get(name, defaultView.frames[i].document, options, targetArray);
          }
        }
      }
    }

    /* Get the microformat nodes for the document */
    var microformatNodes = [];
    if (Microformats[name].className) {
      microformatNodes = Microformats.getElementsByClassName(rootElement,
                                        Microformats[name].className);
      /* alternateClassName is for cases where a parent microformat is inferred by the children */
      /* If we find alternateClassName, the entire document becomes the microformat */
      if ((microformatNodes.length == 0) && Microformats[name].alternateClassName) {
        var altClass = Microformats.getElementsByClassName(rootElement, Microformats[name].alternateClassName);
        if (altClass.length > 0) {
          microformatNodes.push(rootElement);
        }
      }
    } else if (Microformats[name].attributeValues) {
      microformatNodes =
        Microformats.getElementsByAttribute(rootElement,
                                            Microformats[name].attributeName,
                                            Microformats[name].attributeValues);

    }

    function isVisible(node, checkChildren) {
      if (node.getBoundingClientRect) {
        var box = node.getBoundingClientRect();
      } else {
        var box = node.ownerDocument.getBoxObjectFor(node);
      }
      /* If the parent has is an empty box, double check the children */
      if ((box.height == 0) || (box.width == 0)) {
        if (checkChildren && node.childNodes.length > 0) {
          for(let i=0; i < node.childNodes.length; i++) {
            if (node.childNodes[i].nodeType == Components.interfaces.nsIDOMNode.ELEMENT_NODE) {
              /* For performance reasons, we only go down one level */
              /* of children */
              if (isVisible(node.childNodes[i], false)) {
                return true;
              }
            }
          }
        }
        return false
      }
      return true;
    }

    /* Create objects for the microformat nodes and put them into the microformats */
    /* array */
    for (let i = 0; i < microformatNodes.length; i++) {
      /* If showHidden undefined or false, don't add microformats to the list that aren't visible */
      if (!options || !options.hasOwnProperty("showHidden") || !options.showHidden) {
        if (microformatNodes[i].ownerDocument) {
          if (!isVisible(microformatNodes[i], true)) {
            continue;
          }
        }
      }
      try {
        if (options && options.debug) {
          /* Don't validate in the debug case so that we don't get errors thrown */
          /* in the debug case, we want all microformats, even if they are invalid */
          targetArray.push(new Microformats[name].mfObject(microformatNodes[i], false));
        } else {
          targetArray.push(new Microformats[name].mfObject(microformatNodes[i], true));
        }
      } catch (ex) {
        /* Creation of individual object probably failed because it is invalid. */
        /* This isn't a problem, because the page might have invalid microformats */
      }
    }
    return targetArray;
  },
  /**
   * Counts microformats objects of the given type from a document
   *
   * @param  name          The name of the microformat (required)
   * @param  rootElement   The DOM element at which to start searching (required)
   * @param  options       Literal object with the following options:
   *                       recurseExternalFrames - Whether or not to search child frames
   *                       that reference external pages (with a src attribute)
   *                       for microformats (optional - defaults to true)
   *                       showHidden -  Whether or not to add hidden microformat
   *                       (optional - defaults to false)
   *                       debug - Whether or not we are in debug mode (optional
   *                       - defaults to false)
   * @return The new count
   */
  count: function(name, rootElement, options) {
    var mfArray = Microformats.get(name, rootElement, options);
    if (mfArray) {
      return mfArray.length;
    }
    return 0;
  },
  /**
   * Returns true if the passed in node is a microformat. Does NOT return true
   * if the passed in node is a child of a microformat.
   *
   * @param  node          DOM node to check
   * @return true if the node is a microformat, false if it is not
   */
  isMicroformat: function(node) {
    for (let i in Microformats)
    {
      if (Microformats[i].className) {
        if (Microformats.matchClass(node, Microformats[i].className)) {
            return true;
        }
      } else {
        var attribute;
        if (attribute = node.getAttribute(Microformats[i].attributeName)) {
          var attributeList = Microformats[i].attributeValues.split(" ");
          for (let j=0; j < attributeList.length; j++) {
            if (attribute.match("(^|\\s)" + attributeList[j] + "(\\s|$)")) {
              return true;
            }
          }
        }
      }
    }
    return false;
  },
  /**
   * This function searches a given nodes ancestors looking for a microformat
   * and if it finds it, returns it. It does NOT include self, so if the passed
   * in node is a microformat, it will still search ancestors for a microformat.
   *
   * @param  node          DOM node to check
   * @return If the node is contained in a microformat, it returns the parent
   *         DOM node, otherwise returns null
   */
  getParent: function(node) {
    var xpathExpression;
    var xpathResult;

    xpathExpression = "ancestor::*[";
    for (let i=0; i < Microformats.list.length; i++) {
      var mfname = Microformats.list[i];
      if (i != 0) {
        xpathExpression += " or ";
      }
      if (Microformats[mfname].className) {
        xpathExpression += "contains(concat(' ', @class, ' '), ' " + Microformats[mfname].className + " ')";
      } else {
        var attributeList = Microformats[mfname].attributeValues.split(" ");
        for (let j=0; j < attributeList.length; j++) {
          if (j != 0) {
            xpathExpression += " or ";
          }
          xpathExpression += "contains(concat(' ', @" + Microformats[mfname].attributeName + ", ' '), ' " + attributeList[j] + " ')";
        }
      }
    }
    xpathExpression += "][1]";
    xpathResult = (node.ownerDocument || node).evaluate(xpathExpression, node, null,  Components.interfaces.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE, null);
    if (xpathResult.singleNodeValue) {
      xpathResult.singleNodeValue.microformat = mfname;
      return xpathResult.singleNodeValue;
    }
    return null;
  },
  /**
   * If the passed in node is a microformat, this function returns a space
   * separated list of the microformat names that correspond to this node
   *
   * @param  node          DOM node to check
   * @return If the node is a microformat, a space separated list of microformat
   *         names, otherwise returns nothing
   */
  getNamesFromNode: function(node) {
    var microformatNames = [];
    var xpathExpression;
    var xpathResult;
    for (let i in Microformats)
    {
      if (Microformats[i]) {
        if (Microformats[i].className) {
          if (Microformats.matchClass(node, Microformats[i].className)) {
            microformatNames.push(i);
            continue;
          }
        } else if (Microformats[i].attributeValues) {
          var attribute;
          if (attribute = node.getAttribute(Microformats[i].attributeName)) {
            var attributeList = Microformats[i].attributeValues.split(" ");
            for (let j=0; j < attributeList.length; j++) {
              /* If we match any attribute, we've got a microformat */
              if (attribute.match("(^|\\s)" + attributeList[j] + "(\\s|$)")) {
                microformatNames.push(i);
                break;
              }
            }
          }
        }
      }
    }
    return microformatNames.join(" ");
  },
  /**
   * Outputs the contents of a microformat object for debug purposes.
   *
   * @param  microformatObject JavaScript object that represents a microformat
   * @return string containing a visual representation of the contents of the microformat
   */
  debug: function debug(microformatObject) {
    function dumpObject(item, indent)
    {
      if (!indent) {
        indent = "";
      }
      var toreturn = "";
      var testArray = [];

      for (let i in item)
      {
        if (testArray[i]) {
          continue;
        }
        if (typeof item[i] == "object") {
          if ((i != "node") && (i != "resolvedNode")) {
            if (item[i] && item[i].semanticType) {
              toreturn += indent + item[i].semanticType + " [" + i + "] { \n";
            } else {
              toreturn += indent + "object " + i + " { \n";
            }
            toreturn += dumpObject(item[i], indent + "\t");
            toreturn += indent + "}\n";
          }
        } else if ((typeof item[i] != "function") && (i != "semanticType")) {
          if (item[i]) {
            toreturn += indent + i + "=" + item[i] + "\n";
          }
        }
      }
      if (!toreturn && item) {
        toreturn = item.toString();
      }
      return toreturn;
    }
    return dumpObject(microformatObject);
  },
  add: function add(microformat, microformatDefinition) {
    /* We always replace an existing definition with the new one */
    if (!Microformats[microformat]) {
      Microformats.list.push(microformat);
    }
    Microformats[microformat] = microformatDefinition;
    microformatDefinition.mfObject.prototype.debug =
      function(microformatObject) {
        return Microformats.debug(microformatObject)
      };
  },
  remove: function remove(microformat) {
    if (Microformats[microformat]) {
      var list = Microformats.list;
      var index = list.indexOf(microformat, 1);
      if (index != -1) {
        list.splice(index, 1);
      }
      delete Microformats[microformat];
    }
  },
  /* All parser specific functions are contained in this object */
  parser: {
    /**
     * Uses the microformat patterns to decide what the correct text for a
     * given microformat property is. This includes looking at things like
     * abbr, img/alt, area/alt and value excerpting.
     *
     * @param  propnode   The DOMNode to check
     * @param  parentnode The parent node of the property. If it is a subproperty,
     *                    this is the parent property node. If it is not, this is the
     *                    microformat node.
     & @param  datatype   HTML/text - whether to use innerHTML or innerText - defaults to text
     * @return A string with the value of the property
     */
    defaultGetter: function(propnode, parentnode, datatype) {
      function collapseWhitespace(instring) {
        /* Remove new lines, carriage returns and tabs */
        outstring = instring.replace(/[\n\r\t]/gi, ' ');
        /* Replace any double spaces with single spaces */
        outstring = outstring.replace(/\s{2,}/gi, ' ');
        /* Remove any double spaces that are left */
        outstring = outstring.replace(/\s{2,}/gi, '');
        /* Remove any spaces at the beginning */
        outstring = outstring.replace(/^\s+/, '');
        /* Remove any spaces at the end */
        outstring = outstring.replace(/\s+$/, '');
        return outstring;
      }

      if (((((propnode.localName.toLowerCase() == "abbr") || (propnode.localName.toLowerCase() == "html:abbr")) && !propnode.namespaceURI) ||
         ((propnode.localName.toLowerCase() == "abbr") && (propnode.namespaceURI == "http://www.w3.org/1999/xhtml"))) && (propnode.hasAttribute("title"))) {
        return propnode.getAttribute("title");
      } else if ((propnode.nodeName.toLowerCase() == "img") && (propnode.hasAttribute("alt"))) {
        return propnode.getAttribute("alt");
      } else if ((propnode.nodeName.toLowerCase() == "area") && (propnode.hasAttribute("alt"))) {
        return propnode.getAttribute("alt");
      } else if ((propnode.nodeName.toLowerCase() == "textarea") ||
                 (propnode.nodeName.toLowerCase() == "select") ||
                 (propnode.nodeName.toLowerCase() == "input")) {
        return propnode.value;
      } else {
        var values = Microformats.getElementsByClassName(propnode, "value");
        /* Verify that values are children of the propnode */
        for (let i = values.length-1; i >= 0; i--) {
          if (values[i].parentNode != propnode) {
            values.splice(i,1);
          }
        }
        if (values.length > 0) {
          var value = "";
          for (let j=0;j<values.length;j++) {
            value += Microformats.parser.defaultGetter(values[j], propnode, datatype);
          }
          return collapseWhitespace(value);
        }
        var s;
        if (datatype == "HTML") {
          s = propnode.innerHTML;
        } else {
          if (propnode.innerText) {
            s = propnode.innerText;
          } else {
            s = propnode.textContent;
          }
        }
        /* If we are processing a value node, don't remove whitespace now */
        /* (we'll do it later) */
        if (!Microformats.matchClass(propnode, "value")) {
          s = collapseWhitespace(s);
        }
        if (s.length > 0) {
          return s;
        }
      }
    },
    /**
     * Used to specifically retrieve a date in a microformat node.
     * After getting the default text, it normalizes it to an ISO8601 date.
     *
     * @param  propnode   The DOMNode to check
     * @param  parentnode The parent node of the property. If it is a subproperty,
     *                    this is the parent property node. If it is not, this is the
     *                    microformat node.
     * @return A string with the normalized date.
     */
    dateTimeGetter: function(propnode, parentnode) {
      var date = Microformats.parser.textGetter(propnode, parentnode);
      if (date) {
        return Microformats.parser.normalizeISO8601(date);
      }
    },
    /**
     * Used to specifically retrieve a URI in a microformat node. This includes
     * looking at an href/img/object/area to get the fully qualified URI.
     *
     * @param  propnode   The DOMNode to check
     * @param  parentnode The parent node of the property. If it is a subproperty,
     *                    this is the parent property node. If it is not, this is the
     *                    microformat node.
     * @return A string with the fully qualified URI.
     */
    uriGetter: function(propnode, parentnode) {
      var pairs = {"a":"href", "img":"src", "object":"data", "area":"href"};
      var name = propnode.nodeName.toLowerCase();
      if (pairs.hasOwnProperty(name)) {
        return propnode[pairs[name]];
      }
      return Microformats.parser.textGetter(propnode, parentnode);
    },
    /**
     * Used to specifically retrieve a telephone number in a microformat node.
     * Basically this is to handle the face that telephone numbers use value
     * as the name as one of their subproperties, but value is also used for
     * value excerpting (http://microformats.org/wiki/hcard#Value_excerpting)

     * @param  propnode   The DOMNode to check
     * @param  parentnode The parent node of the property. If it is a subproperty,
     *                    this is the parent property node. If it is not, this is the
     *                    microformat node.
     * @return A string with the telephone number
     */
    telGetter: function(propnode, parentnode) {
      var pairs = {"a":"href", "object":"data", "area":"href"};
      var name = propnode.nodeName.toLowerCase();
      if (pairs.hasOwnProperty(name)) {
        var protocol;
        if (propnode[pairs[name]].indexOf("tel:") == 0) {
          protocol = "tel:";
        }
        if (propnode[pairs[name]].indexOf("fax:") == 0) {
          protocol = "fax:";
        }
        if (propnode[pairs[name]].indexOf("modem:") == 0) {
          protocol = "modem:";
        }
        if (protocol) {
          if (propnode[pairs[name]].indexOf('?') > 0) {
            return unescape(propnode[pairs[name]].substring(protocol.length, propnode[pairs[name]].indexOf('?')));
          } else {
            return unescape(propnode[pairs[name]].substring(protocol.length));
          }
        }
      }
     /* Special case - if this node is a value, use the parent node to get all the values */
      if (Microformats.matchClass(propnode, "value")) {
        return Microformats.parser.textGetter(parentnode, parentnode);
      } else {
        /* Virtual case */
        if (!parentnode && (Microformats.getElementsByClassName(propnode, "type").length > 0)) {
          var tempNode = propnode.cloneNode(true);
          var typeNodes = Microformats.getElementsByClassName(tempNode, "type");
          for (let i=0; i < typeNodes.length; i++) {
            typeNodes[i].parentNode.removeChild(typeNodes[i]);
          }
          return Microformats.parser.textGetter(tempNode);
        }
        return Microformats.parser.textGetter(propnode, parentnode);
      }
    },
    /**
     * Used to specifically retrieve an email address in a microformat node.
     * This includes at an href, as well as removing subject if specified and
     * the mailto prefix.
     *
     * @param  propnode   The DOMNode to check
     * @param  parentnode The parent node of the property. If it is a subproperty,
     *                    this is the parent property node. If it is not, this is the
     *                    microformat node.
     * @return A string with the email address.
     */
    emailGetter: function(propnode, parentnode) {
      if ((propnode.nodeName.toLowerCase() == "a") || (propnode.nodeName.toLowerCase() == "area")) {
        var mailto = propnode.href;
        /* IO Service won't fully parse mailto, so we do it manually */
        if (mailto.indexOf('?') > 0) {
          return unescape(mailto.substring("mailto:".length, mailto.indexOf('?')));
        } else {
          return unescape(mailto.substring("mailto:".length));
        }
      } else {
        /* Special case - if this node is a value, use the parent node to get all the values */
        /* If this case gets executed, per the value design pattern, the result */
        /* will be the EXACT email address with no extra parsing required */
        if (Microformats.matchClass(propnode, "value")) {
          return Microformats.parser.textGetter(parentnode, parentnode);
        } else {
          /* Virtual case */
          if (!parentnode && (Microformats.getElementsByClassName(propnode, "type").length > 0)) {
            var tempNode = propnode.cloneNode(true);
            var typeNodes = Microformats.getElementsByClassName(tempNode, "type");
            for (let i=0; i < typeNodes.length; i++) {
              typeNodes[i].parentNode.removeChild(typeNodes[i]);
            }
            return Microformats.parser.textGetter(tempNode);
          }
          return Microformats.parser.textGetter(propnode, parentnode);
        }
      }
    },
    /**
     * Used when a caller needs the text inside a particular DOM node.
     * It calls defaultGetter to handle all the subtleties of getting
     * text from a microformat.
     *
     * @param  propnode   The DOMNode to check
     * @param  parentnode The parent node of the property. If it is a subproperty,
     *                    this is the parent property node. If it is not, this is the
     *                    microformat node.
     * @return A string with just the text including all tags.
     */
    textGetter: function(propnode, parentnode) {
      return Microformats.parser.defaultGetter(propnode, parentnode, "text");
    },
    /**
     * Used when a caller needs the HTML inside a particular DOM node.
     *
     * @param  propnode   The DOMNode to check
     * @param  parentnode The parent node of the property. If it is a subproperty,
     *                    this is the parent property node. If it is not, this is the
     *                    microformat node.
     * @return An emulated string object that also has a new function called toHTML
     */
    HTMLGetter: function(propnode, parentnode) {
      /* This is so we can have a string that behaves like a string */
      /* but also has a new function that can return the HTML that corresponds */
      /* to the string. */
      function mfHTML(value) {
        this.valueOf = function() {return value ? value.valueOf() : "";}
        this.toString = function() {return value ? value.toString() : "";}
      }
      mfHTML.prototype = new String;
      mfHTML.prototype.toHTML = function() {
        return Microformats.parser.defaultGetter(propnode, parentnode, "HTML");
      }
      return new mfHTML(Microformats.parser.defaultGetter(propnode, parentnode, "text"));
    },
    /**
     * Internal parser API used to determine which getter to call based on the
     * datatype specified in the microformat definition.
     *
     * @param  prop       The microformat property in the definition
     * @param  propnode   The DOMNode to check
     * @param  parentnode The parent node of the property. If it is a subproperty,
     *                    this is the parent property node. If it is not, this is the
     *                    microformat node.
     * @return A string with the property value.
     */
    datatypeHelper: function(prop, node, parentnode) {
      var result;
      var datatype = prop.datatype;
      switch (datatype) {
        case "dateTime":
          result = Microformats.parser.dateTimeGetter(node, parentnode);
          break;
        case "anyURI":
          result = Microformats.parser.uriGetter(node, parentnode);
          break;
        case "email":
          result = Microformats.parser.emailGetter(node, parentnode);
          break;
        case "tel":
          result = Microformats.parser.telGetter(node, parentnode);
          break;
        case "HTML":
          result = Microformats.parser.HTMLGetter(node, parentnode);
          break;
        case "float":
          var asText = Microformats.parser.textGetter(node, parentnode);
          if (!isNaN(asText)) {
            result = parseFloat(asText);
          }
          break;
        case "custom":
          result = prop.customGetter(node, parentnode);
          break;
        case "microformat":
          try {
            result = new Microformats[prop.microformat].mfObject(node, true);
          } catch (ex) {
            /* There are two reasons we get here, one because the node is not */
            /* a microformat and two because the node is a microformat and */
            /* creation failed. If the node is not a microformat, we just fall */
            /* through and use the default getter since there are some cases */
            /* (location in hCalendar) where a property can be either a microformat */
            /* or a string. If creation failed, we break and simply don't add the */
            /* microformat property to the parent microformat */
            if (ex != "Node is not a microformat (" + prop.microformat + ")") {
              break;
            }
          }
          if (result != undefined) {
            if (prop.microformat_property) {
              result = result[prop.microformat_property];
            }
            break;
          }
        default:
          result = Microformats.parser.textGetter(node, parentnode);
          break;
      }
      /* This handles the case where one property implies another property */
      /* For instance, org by itself is actually org.organization-name */
      if (prop.values && (result != undefined)) {
        var validType = false;
        for (let value in prop.values) {
          if (result.toLowerCase() == prop.values[value]) {
            result = result.toLowerCase();
            validType = true;
            break;
          }
        }
        if (!validType) {
          return;
        }
      }
      return result;
    },
    newMicroformat: function(object, in_node, microformat, validate) {
      /* check to see if we are even valid */
      if (!Microformats[microformat]) {
        throw("Invalid microformat - " + microformat);
      }
      if (in_node.ownerDocument) {
        if (Microformats[microformat].attributeName) {
          if (!(in_node.hasAttribute(Microformats[microformat].attributeName))) {
            throw("Node is not a microformat (" + microformat + ")");
          }
        } else {
          if (!Microformats.matchClass(in_node, Microformats[microformat].className)) {
            throw("Node is not a microformat (" + microformat + ")");
          }
        }
      }
      var node = in_node;
      if ((Microformats[microformat].className) && in_node.ownerDocument) {
        node = Microformats.parser.preProcessMicroformat(in_node);
      }

      for (let i in Microformats[microformat].properties) {
        object.__defineGetter__(i, Microformats.parser.getMicroformatPropertyGenerator(node, microformat, i, object));
      }

      /* The node in the object should be the original node */
      object.node = in_node;
      /* we also store the node that has been "resolved" */
      object.resolvedNode = node;
      object.semanticType = microformat;
      if (validate) {
        Microformats.parser.validate(node, microformat);
      }
    },
    getMicroformatPropertyGenerator: function getMicroformatPropertyGenerator(node, name, property, microformat)
    {
      return function() {
        var result = Microformats.parser.getMicroformatProperty(node, name, property);
//        delete microformat[property];
//        microformat[property] = result;
        return result;
      };
    },
    getPropertyInternal: function getPropertyInternal(propnode, parentnode, propobj, propname, mfnode) {
      var result;
      if (propobj.subproperties) {
        for (let subpropname in propobj.subproperties) {
          var subpropnodes;
          var subpropobj = propobj.subproperties[subpropname];
          if (subpropobj.rel == true) {
            subpropnodes = Microformats.getElementsByAttribute(propnode, "rel", subpropname);
          } else {
            subpropnodes = Microformats.getElementsByClassName(propnode, subpropname);
          }
          var resultArray = [];
          var subresult;
          for (let i = 0; i < subpropnodes.length; i++) {
            subresult = Microformats.parser.getPropertyInternal(subpropnodes[i], propnode,
                                                                subpropobj,
                                                                subpropname, mfnode);
            if (subresult != undefined) {
              resultArray.push(subresult);
              /* If we're not a plural property, don't bother getting more */
              if (!subpropobj.plural) {
                break;
              }
            }
          }
          if (resultArray.length == 0) {
            subresult = Microformats.parser.getPropertyInternal(propnode, null,
                                                                subpropobj,
                                                                subpropname, mfnode);
            if (subresult != undefined) {
              resultArray.push(subresult);
            }
          }
          if (resultArray.length > 0) {
            result = result || {};
            if (subpropobj.plural) {
              result[subpropname] = resultArray;
            } else {
              result[subpropname] = resultArray[0];
            }
          }
        }
      }
      if (!parentnode || (!result && propobj.subproperties)) {
        if (propobj.virtual) {
          if (propobj.virtualGetter) {
            result = propobj.virtualGetter(mfnode || propnode);
          } else {
            result = Microformats.parser.datatypeHelper(propobj, propnode);
          }
        }
      } else if (!result) {
        result = Microformats.parser.datatypeHelper(propobj, propnode, parentnode);
      }
      return result;
    },
    getMicroformatProperty: function getMicroformatProperty(in_mfnode, mfname, propname) {
      var mfnode = in_mfnode;
      /* If the node has not been preprocessed, the requested microformat */
      /* is a class based microformat and the passed in node is not the */
      /* entire document, preprocess it. Preprocessing the node involves */
      /* creating a duplicate of the node and taking care of things like */
      /* the include and header design patterns */
      if (!in_mfnode.origNode && Microformats[mfname].className && in_mfnode.ownerDocument) {
        mfnode = Microformats.parser.preProcessMicroformat(in_mfnode);
      }
      /* propobj is the corresponding property object in the microformat */
      var propobj;
      /* If there is a corresponding property in the microformat, use it */
      if (Microformats[mfname].properties[propname]) {
        propobj = Microformats[mfname].properties[propname];
      } else {
        /* If we didn't get a property, bail */
        return;
      }
      /* Query the correct set of nodes (rel or class) based on the setting */
      /* in the property */
      var propnodes;
      if (propobj.rel == true) {
        propnodes = Microformats.getElementsByAttribute(mfnode, "rel", propname);
      } else {
        propnodes = Microformats.getElementsByClassName(mfnode, propname);
      }
      for (let i=propnodes.length-1; i >= 0; i--) {
        /* The reason getParent is not used here is because this code does */
        /* not apply to attribute based microformats, plus adr and geo */
        /* when contained in hCard are a special case */
        var parentnode;
        var node = propnodes[i];
        var xpathExpression = "";
        for (let j=0; j < Microformats.list.length; j++) {
          /* Don't treat adr or geo in an hCard as a microformat in this case */
          if ((mfname == "hCard") && ((Microformats.list[j] == "adr") || (Microformats.list[j] == "geo"))) {
            continue;
          }
          if (Microformats[Microformats.list[j]].className) {
            if (xpathExpression.length == 0) {
              xpathExpression = "ancestor::*[";
            } else {
              xpathExpression += " or ";
            }
            xpathExpression += "contains(concat(' ', @class, ' '), ' " + Microformats[Microformats.list[j]].className + " ')";
          }
        }
        xpathExpression += "][1]";
        var xpathResult = (node.ownerDocument || node).evaluate(xpathExpression, node, null,  Components.interfaces.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE, null);
        if (xpathResult.singleNodeValue) {
          xpathResult.singleNodeValue.microformat = mfname;
          parentnode = xpathResult.singleNodeValue;
        }
        /* If the propnode is not a child of the microformat, and */
        /* the property belongs to the parent microformat as well, */
        /* remove it. */
        if (parentnode != mfnode) {
          var mfNameString = Microformats.getNamesFromNode(parentnode);
          var mfNames = mfNameString.split(" ");
          var j;
          for (j=0; j < mfNames.length; j++) {
            /* If this property is in the parent microformat, remove the node  */
            if (Microformats[mfNames[j]].properties[propname]) {
              propnodes.splice(i,1);
              break;
            }
          }
        }
      }
      if (propnodes.length > 0) {
        var resultArray = [];
        for (let i = 0; i < propnodes.length; i++) {
          var subresult = Microformats.parser.getPropertyInternal(propnodes[i],
                                                                  mfnode,
                                                                  propobj,
                                                                  propname);
          if (subresult != undefined) {
            resultArray.push(subresult);
            /* If we're not a plural property, don't bother getting more */
            if (!propobj.plural) {
              return resultArray[0];
            }
          }
        }
        if (resultArray.length > 0) {
          return resultArray;
        }
      } else {
        /* If we didn't find any class nodes, check to see if this property */
        /* is virtual and if so, call getPropertyInternal again */
        if (propobj.virtual) {
          return Microformats.parser.getPropertyInternal(mfnode, null,
                                                         propobj, propname);
        }
      }
      return;
    },
    /**
     * Internal parser API used to resolve includes and headers. Includes are
     * resolved by simply cloning the node and replacing it in a clone of the
     * original DOM node. Headers are resolved by creating a span and then copying
     * the innerHTML and the class name.
     *
     * @param  in_mfnode The node to preProcess.
     * @return If the node had includes or headers, a cloned node otherwise
     *         the original node. You can check to see if the node was cloned
     *         by looking for .origNode in the new node.
     */
    preProcessMicroformat: function preProcessMicroformat(in_mfnode) {
      var mfnode;
      if ((in_mfnode.nodeName.toLowerCase() == "td") && (in_mfnode.hasAttribute("headers"))) {
        mfnode = in_mfnode.cloneNode(true);
        mfnode.origNode = in_mfnode;
        var headers = in_mfnode.getAttribute("headers").split(" ");
        for (let i = 0; i < headers.length; i++) {
          var tempNode = in_mfnode.ownerDocument.createElement("span");
          var headerNode = in_mfnode.ownerDocument.getElementById(headers[i]);
          if (headerNode) {
            tempNode.innerHTML = headerNode.innerHTML;
            tempNode.className = headerNode.className;
            mfnode.appendChild(tempNode);
          }
        }
      } else {
        mfnode = in_mfnode;
      }
      var includes = Microformats.getElementsByClassName(mfnode, "include");
      if (includes.length > 0) {
        /* If we didn't clone, clone now */
        if (!mfnode.origNode) {
          mfnode = in_mfnode.cloneNode(true);
          mfnode.origNode = in_mfnode;
        }
        includes = Microformats.getElementsByClassName(mfnode, "include");
        var includeId;
        var include_length = includes.length;
        for (let i = include_length -1; i >= 0; i--) {
          if (includes[i].nodeName.toLowerCase() == "a") {
            includeId = includes[i].getAttribute("href").substr(1);
          }
          if (includes[i].nodeName.toLowerCase() == "object") {
            includeId = includes[i].getAttribute("data").substr(1);
          }
          if (in_mfnode.ownerDocument.getElementById(includeId)) {
            includes[i].parentNode.replaceChild(in_mfnode.ownerDocument.getElementById(includeId).cloneNode(true), includes[i]);
          }
        }
      }
      return mfnode;
    },
    validate: function validate(mfnode, mfname) {
      var error = "";
      if (Microformats[mfname].validate) {
        return Microformats[mfname].validate(mfnode);
      } else if (Microformats[mfname].required) {
        for (let i=0;i<Microformats[mfname].required.length;i++) {
          if (!Microformats.parser.getMicroformatProperty(mfnode, mfname, Microformats[mfname].required[i])) {
            error += "Required property " + Microformats[mfname].required[i] + " not specified\n";
          }
        }
        if (error.length > 0) {
          throw(error);
        }
        return true;
      }
    },
    /* This function normalizes an ISO8601 date by adding punctuation and */
    /* ensuring that hours and seconds have values */
    normalizeISO8601: function normalizeISO8601(string)
    {
      var dateArray = string.match(/(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d)(?:[T ](\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(?:([-+Z])(?:(\d\d)(?::?(\d\d))?)?)?)?)?)?/);

      var dateString;
      var tzOffset = 0;
      if (!dateArray) {
        return;
      }
      if (dateArray[1]) {
        dateString = dateArray[1];
        if (dateArray[2]) {
          dateString += "-" + dateArray[2];
          if (dateArray[3]) {
            dateString += "-" + dateArray[3];
            if (dateArray[4]) {
              dateString += "T" + dateArray[4];
              if (dateArray[5]) {
                dateString += ":" + dateArray[5];
              } else {
                dateString += ":" + "00";
              }
              if (dateArray[6]) {
                dateString += ":" + dateArray[6];
              } else {
                dateString += ":" + "00";
              }
              if (dateArray[7]) {
                dateString += "." + dateArray[7];
              }
              if (dateArray[8]) {
                dateString += dateArray[8];
                if ((dateArray[8] == "+") || (dateArray[8] == "-")) {
                  if (dateArray[9]) {
                    dateString += dateArray[9];
                    if (dateArray[10]) {
                      dateString += dateArray[10];
                    }
                  }
                }
              }
            }
          }
        }
      }
      return dateString;
    }
  },
  /**
   * Converts an ISO8601 date into a JavaScript date object, honoring the TZ
   * offset and Z if present to convert the date to local time
   * NOTE: I'm using an extra parameter on the date object for this function.
   * I set date.time to true if there is a date, otherwise date.time is false.
   *
   * @param  string ISO8601 formatted date
   * @return JavaScript date object that represents the ISO date.
   */
  dateFromISO8601: function dateFromISO8601(string) {
    var dateArray = string.match(/(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d)(?:[T ](\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(?:([-+Z])(?:(\d\d)(?::?(\d\d))?)?)?)?)?)?/);

    var date = new Date(dateArray[1], 0, 1);
    date.time = false;

    if (dateArray[2]) {
      date.setMonth(dateArray[2] - 1);
    }
    if (dateArray[3]) {
      date.setDate(dateArray[3]);
    }
    if (dateArray[4]) {
      date.setHours(dateArray[4]);
      date.time = true;
      if (dateArray[5]) {
        date.setMinutes(dateArray[5]);
        if (dateArray[6]) {
          date.setSeconds(dateArray[6]);
          if (dateArray[7]) {
            date.setMilliseconds(Number("0." + dateArray[7]) * 1000);
          }
        }
      }
    }
    if (dateArray[8]) {
      if (dateArray[8] == "-") {
        if (dateArray[9] && dateArray[10]) {
          date.setHours(date.getHours() + parseInt(dateArray[9], 10));
          date.setMinutes(date.getMinutes() + parseInt(dateArray[10], 10));
        }
      } else if (dateArray[8] == "+") {
        if (dateArray[9] && dateArray[10]) {
          date.setHours(date.getHours() - parseInt(dateArray[9], 10));
          date.setMinutes(date.getMinutes() - parseInt(dateArray[10], 10));
        }
      }
      /* at this point we have the time in gmt */
      /* convert to local if we had a Z - or + */
      if (dateArray[8]) {
        var tzOffset = date.getTimezoneOffset();
        if (tzOffset < 0) {
          date.setMinutes(date.getMinutes() + tzOffset);
        } else if (tzOffset > 0) {
          date.setMinutes(date.getMinutes() - tzOffset);
        }
      }
    }
    return date;
  },
  /**
   * Converts a Javascript date object into an ISO 8601 formatted date
   * NOTE: I'm using an extra parameter on the date object for this function.
   * If date.time is NOT true, this function only outputs the date.
   *
   * @param  date        Javascript Date object
   * @param  punctuation true if the date should have -/:
   * @return string with the ISO date.
   */
  iso8601FromDate: function iso8601FromDate(date, punctuation) {
    var string = date.getFullYear().toString();
    if (punctuation) {
      string += "-";
    }
    string += (date.getMonth() + 1).toString().replace(/\b(\d)\b/g, '0$1');
    if (punctuation) {
      string += "-";
    }
    string += date.getDate().toString().replace(/\b(\d)\b/g, '0$1');
    if (date.time) {
      string += "T";
      string += date.getHours().toString().replace(/\b(\d)\b/g, '0$1');
      if (punctuation) {
        string += ":";
      }
      string += date.getMinutes().toString().replace(/\b(\d)\b/g, '0$1');
      if (punctuation) {
        string += ":";
      }
      string += date.getSeconds().toString().replace(/\b(\d)\b/g, '0$1');
      if (date.getMilliseconds() > 0) {
        if (punctuation) {
          string += ".";
        }
        string += date.getMilliseconds().toString();
      }
    }
    return string;
  },
  simpleEscape: function simpleEscape(s)
  {
    s = s.replace(/\&/g, '%26');
    s = s.replace(/\#/g, '%23');
    s = s.replace(/\+/g, '%2B');
    s = s.replace(/\-/g, '%2D');
    s = s.replace(/\=/g, '%3D');
    s = s.replace(/\'/g, '%27');
    s = s.replace(/\,/g, '%2C');
//    s = s.replace(/\r/g, '%0D');
//    s = s.replace(/\n/g, '%0A');
    s = s.replace(/ /g, '+');
    return s;
  },
  /**
   * Not intended for external consumption. Microformat implementations might use it.
   *
   * Retrieve elements matching all classes listed in a space-separated string.
   * I had to implement my own because I need an Array, not an nsIDomNodeList
   *
   * @param  rootElement      The DOM element at which to start searching (optional)
   * @param  className        A space separated list of classenames
   * @return microformatNodes An array of DOM Nodes, each representing a
                              microformat in the document.
   */
  getElementsByClassName: function getElementsByClassName(rootNode, className)
  {
    var returnElements = [];

    if ((rootNode.ownerDocument || rootNode).getElementsByClassName) {
    /* Firefox 3 - native getElementsByClassName */
      var col = rootNode.getElementsByClassName(className);
      for (let i = 0; i < col.length; i++) {
        returnElements[i] = col[i];
      }
    } else if ((rootNode.ownerDocument || rootNode).evaluate) {
    /* Firefox 2 and below - XPath */
      var xpathExpression;
      xpathExpression = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
      var xpathResult = (rootNode.ownerDocument || rootNode).evaluate(xpathExpression, rootNode, null, 0, null);

      var node;
      while (node = xpathResult.iterateNext()) {
        returnElements.push(node);
      }
    } else {
    /* Slow fallback for testing */
      className = className.replace(/\-/g, "\\-");
      var elements = rootNode.getElementsByTagName("*");
      for (let i=0;i<elements.length;i++) {
        if (elements[i].className.match("(^|\\s)" + className + "(\\s|$)")) {
          returnElements.push(elements[i]);
        }
      }
    }
    return returnElements;
  },
  /**
   * Not intended for external consumption. Microformat implementations might use it.
   *
   * Retrieve elements matching an attribute and an attribute list in a space-separated string.
   *
   * @param  rootElement      The DOM element at which to start searching (optional)
   * @param  atributeName     The attribute name to match against
   * @param  attributeValues  A space separated list of attribute values
   * @return microformatNodes An array of DOM Nodes, each representing a
                              microformat in the document.
   */
  getElementsByAttribute: function getElementsByAttribute(rootNode, attributeName, attributeValues)
  {
    var attributeList = attributeValues.split(" ");

    var returnElements = [];

    if ((rootNode.ownerDocument || rootNode).evaluate) {
    /* Firefox 3 and below - XPath */
      /* Create an XPath expression based on the attribute list */
      var xpathExpression = ".//*[";
      for (let i = 0; i < attributeList.length; i++) {
        if (i != 0) {
          xpathExpression += " or ";
        }
        xpathExpression += "contains(concat(' ', @" + attributeName + ", ' '), ' " + attributeList[i] + " ')";
      }
      xpathExpression += "]";

      var xpathResult = (rootNode.ownerDocument || rootNode).evaluate(xpathExpression, rootNode, null, 0, null);

      var node;
      while (node = xpathResult.iterateNext()) {
        returnElements.push(node);
      }
    } else {
    /* Need Slow fallback for testing */
    }
    return returnElements;
  },
  matchClass: function matchClass(node, className) {
    var classValue = node.getAttribute("class");
    return (classValue && classValue.match("(^|\\s)" + className + "(\\s|$)"));
  }
};

/* MICROFORMAT DEFINITIONS BEGIN HERE */

function adr(node, validate) {
  if (node) {
    Microformats.parser.newMicroformat(this, node, "adr", validate);
  }
}

adr.prototype.toString = function() {
  var address_text = "";
  var start_parens = false;
  if (this["street-address"]) {
    address_text += this["street-address"][0];
  } else if (this["extended-address"]) {
    address_text += this["extended-address"];
  }
  if (this["locality"]) {
    if (this["street-address"] || this["extended-address"]) {
      address_text += " (";
      start_parens = true;
    }
    address_text += this["locality"];
  }
  if (this["region"]) {
    if ((this["street-address"] || this["extended-address"]) && (!start_parens)) {
      address_text += " (";
      start_parens = true;
    } else if (this["locality"]) {
      address_text += ", ";
    }
    address_text += this["region"];
  }
  if (this["country-name"]) {
    if ((this["street-address"] || this["extended-address"]) && (!start_parens)) {
      address_text += " (";
      start_parens = true;
      address_text += this["country-name"];
    } else if ((!this["locality"]) && (!this["region"])) {
      address_text += this["country-name"];
    } else if (((!this["locality"]) && (this["region"])) || ((this["locality"]) && (!this["region"]))) {
      address_text += ", ";
      address_text += this["country-name"];
    }
  }
  if (start_parens) {
    address_text += ")";
  }
  return address_text;
}

var adr_definition = {
  mfObject: adr,
  className: "adr",
  properties: {
    "type" : {
      plural: true,
      values: ["work", "home", "pref", "postal", "dom", "intl", "parcel"]
    },
    "post-office-box" : {
    },
    "street-address" : {
      plural: true
    },
    "extended-address" : {
    },
    "locality" : {
    },
    "region" : {
    },
    "postal-code" : {
    },
    "country-name" : {
    }
  },
  validate: function(node) {
    var xpathExpression = "count(descendant::*[" +
                                              "contains(concat(' ', @class, ' '), ' post-office-box ')" +
                                              " or contains(concat(' ', @class, ' '), ' street-address ')" +
                                              " or contains(concat(' ', @class, ' '), ' extended-address ')" +
                                              " or contains(concat(' ', @class, ' '), ' locality ')" +
                                              " or contains(concat(' ', @class, ' '), ' region ')" +
                                              " or contains(concat(' ', @class, ' '), ' postal-code ')" +
                                              " or contains(concat(' ', @class, ' '), ' country-name')" +
                                              "])";
    var xpathResult = (node.ownerDocument || node).evaluate(xpathExpression, node, null,  Components.interfaces.nsIDOMXPathResult.ANY_TYPE, null).numberValue;
    if (xpathResult == 0) {
      throw("Unable to create microformat");
    }
    return true;
  }
};

Microformats.add("adr", adr_definition);

function hCard(node, validate) {
  if (node) {
    Microformats.parser.newMicroformat(this, node, "hCard", validate);
  }
}
hCard.prototype.toString = function() {
  if (this.resolvedNode) {
    /* If this microformat has an include pattern, put the */
    /* organization-name in parenthesis after the fn to differentiate */
    /* them. */
    var fns = Microformats.getElementsByClassName(this.node, "fn");
    if (fns.length === 0) {
      if (this.fn) {
        if (this.org && this.org[0]["organization-name"] && (this.fn != this.org[0]["organization-name"])) {
          return this.fn + " (" + this.org[0]["organization-name"] + ")";
        }
      }
    }
  }
  return this.fn;
}

var hCard_definition = {
  mfObject: hCard,
  className: "vcard",
  required: ["fn"],
  properties: {
    "adr" : {
      plural: true,
      datatype: "microformat",
      microformat: "adr"
    },
    "agent" : {
      plural: true,
      datatype: "microformat",
      microformat: "hCard"
    },
    "bday" : {
      datatype: "dateTime"
    },
    "class" : {
    },
    "category" : {
      plural: true,
      datatype: "microformat",
      microformat: "tag",
      microformat_property: "tag"
    },
    "email" : {
      subproperties: {
        "type" : {
          plural: true,
          values: ["internet", "x400", "pref"]
        },
        "value" : {
          datatype: "email",
          virtual: true
        }
      },
      plural: true
    },
    "fn" : {
      required: true
    },
    "geo" : {
      datatype: "microformat",
      microformat: "geo"
    },
    "key" : {
      plural: true
    },
    "label" : {
      plural: true
    },
    "logo" : {
      plural: true,
      datatype: "anyURI"
    },
    "mailer" : {
      plural: true
    },
    "n" : {
      subproperties: {
        "honorific-prefix" : {
          plural: true
        },
        "given-name" : {
          plural: true
        },
        "additional-name" : {
          plural: true
        },
        "family-name" : {
          plural: true
        },
        "honorific-suffix" : {
          plural: true
        }
      },
      virtual: true,
      /*  Implied "n" Optimization */
      /* http://microformats.org/wiki/hcard#Implied_.22n.22_Optimization */
      virtualGetter: function(mfnode) {
        var fn = Microformats.parser.getMicroformatProperty(mfnode, "hCard", "fn");
        var orgs = Microformats.parser.getMicroformatProperty(mfnode, "hCard", "org");
        var given_name = [];
        var family_name = [];
        if (fn && (!orgs || (orgs.length > 1) || (fn != orgs[0]["organization-name"]))) {
          var fns = fn.split(" ");
          if (fns.length === 2) {
            if (fns[0].charAt(fns[0].length-1) == ',') {
              given_name[0] = fns[1];
              family_name[0] = fns[0].substr(0, fns[0].length-1);
            } else if (fns[1].length == 1) {
              given_name[0] = fns[1];
              family_name[0] = fns[0];
            } else if ((fns[1].length == 2) && (fns[1].charAt(fns[1].length-1) == '.')) {
              given_name[0] = fns[1];
              family_name[0] = fns[0];
            } else {
              given_name[0] = fns[0];
              family_name[0] = fns[1];
            }
            return {"given-name" : given_name, "family-name" : family_name};
          }
        }
      }
    },
    "nickname" : {
      plural: true,
      virtual: true,
      /* Implied "nickname" Optimization */
      /* http://microformats.org/wiki/hcard#Implied_.22nickname.22_Optimization */
      virtualGetter: function(mfnode) {
        var fn = Microformats.parser.getMicroformatProperty(mfnode, "hCard", "fn");
        var orgs = Microformats.parser.getMicroformatProperty(mfnode, "hCard", "org");
        var given_name;
        var family_name;
        if (fn && (!orgs || (orgs.length) > 1 || (fn != orgs[0]["organization-name"]))) {
          var fns = fn.split(" ");
          if (fns.length === 1) {
            return [fns[0]];
          }
        }
        return;
      }
    },
    "note" : {
      plural: true,
      datatype: "HTML"
    },
    "org" : {
      subproperties: {
        "organization-name" : {
          virtual: true
        },
        "organization-unit" : {
          plural: true
        }
      },
      plural: true
    },
    "photo" : {
      plural: true,
      datatype: "anyURI"
    },
    "rev" : {
      datatype: "dateTime"
    },
    "role" : {
      plural: true
    },
    "sequence" : {
    },
    "sort-string" : {
    },
    "sound" : {
      plural: true
    },
    "title" : {
      plural: true
    },
    "tel" : {
      subproperties: {
        "type" : {
          plural: true,
          values: ["msg", "home", "work", "pref", "voice", "fax", "cell", "video", "pager", "bbs", "car", "isdn", "pcs"]
        },
        "value" : {
          datatype: "tel",
          virtual: true
        }
      },
      plural: true
    },
    "tz" : {
    },
    "uid" : {
      datatype: "anyURI"
    },
    "url" : {
      plural: true,
      datatype: "anyURI"
    }
  }
};

Microformats.add("hCard", hCard_definition);

function hCalendar(node, validate) {
  if (node) {
    Microformats.parser.newMicroformat(this, node, "hCalendar", validate);
  }
}
hCalendar.prototype.toString = function() {
  if (this.resolvedNode) {
    /* If this microformat has an include pattern, put the */
    /* dtstart in parenthesis after the summary to differentiate */
    /* them. */
    var summaries = Microformats.getElementsByClassName(this.node, "summary");
    if (summaries.length === 0) {
      if (this.summary) {
        if (this.dtstart) {
          return this.summary + " (" + Microformats.dateFromISO8601(this.dtstart).toLocaleString() + ")";
        }
      }
    }
  }
  if (this.dtstart) {
    return this.summary;
  }
  return;
}

var hCalendar_definition = {
  mfObject: hCalendar,
  className: "vevent",
  required: ["summary", "dtstart"],
  properties: {
    "category" : {
      plural: true,
      datatype: "microformat",
      microformat: "tag",
      microformat_property: "tag"
    },
    "class" : {
      values: ["public", "private", "confidential"]
    },
    "description" : {
      datatype: "HTML"
    },
    "dtstart" : {
      datatype: "dateTime"
    },
    "dtend" : {
      datatype: "dateTime"
    },
    "dtstamp" : {
      datatype: "dateTime"
    },
    "duration" : {
    },
    "geo" : {
      datatype: "microformat",
      microformat: "geo"
    },
    "location" : {
      datatype: "microformat",
      microformat: "hCard"
    },
    "status" : {
      values: ["tentative", "confirmed", "cancelled"]
    },
    "summary" : {},
    "transp" : {
      values: ["opaque", "transparent"]
    },
    "uid" : {
      datatype: "anyURI"
    },
    "url" : {
      datatype: "anyURI"
    },
    "last-modified" : {
      datatype: "dateTime"
    },
    "rrule" : {
      subproperties: {
        "interval" : {
          virtual: true,
          /* This will only be called in the virtual case */
          virtualGetter: function(mfnode) {
            return Microformats.hCalendar.properties.rrule.retrieve(mfnode, "interval");
          }
        },
        "freq" : {
          virtual: true,
          /* This will only be called in the virtual case */
          virtualGetter: function(mfnode) {
            return Microformats.hCalendar.properties.rrule.retrieve(mfnode, "freq");
          }
        },
        "bysecond" : {
          virtual: true,
          /* This will only be called in the virtual case */
          virtualGetter: function(mfnode) {
            return Microformats.hCalendar.properties.rrule.retrieve(mfnode, "bysecond");
          }
        },
        "byminute" : {
          virtual: true,
          /* This will only be called in the virtual case */
          virtualGetter: function(mfnode) {
            return Microformats.hCalendar.properties.rrule.retrieve(mfnode, "byminute");
          }
        },
        "byhour" : {
          virtual: true,
          /* This will only be called in the virtual case */
          virtualGetter: function(mfnode) {
            return Microformats.hCalendar.properties.rrule.retrieve(mfnode, "byhour");
          }
        },
        "bymonthday" : {
          virtual: true,
          /* This will only be called in the virtual case */
          virtualGetter: function(mfnode) {
            return Microformats.hCalendar.properties.rrule.retrieve(mfnode, "bymonthday");
          }
        },
        "byyearday" : {
          virtual: true,
          /* This will only be called in the virtual case */
          virtualGetter: function(mfnode) {
            return Microformats.hCalendar.properties.rrule.retrieve(mfnode, "byyearday");
          }
        },
        "byweekno" : {
          virtual: true,
          /* This will only be called in the virtual case */
          virtualGetter: function(mfnode) {
            return Microformats.hCalendar.properties.rrule.retrieve(mfnode, "byweekno");
          }
        },
        "bymonth" : {
          virtual: true,
          /* This will only be called in the virtual case */
          virtualGetter: function(mfnode) {
            return Microformats.hCalendar.properties.rrule.retrieve(mfnode, "bymonth");
          }
        },
        "byday" : {
          virtual: true,
          /* This will only be called in the virtual case */
          virtualGetter: function(mfnode) {
            return Microformats.hCalendar.properties.rrule.retrieve(mfnode, "byday");
          }
        },
        "until" : {
          virtual: true,
          /* This will only be called in the virtual case */
          virtualGetter: function(mfnode) {
            return Microformats.hCalendar.properties.rrule.retrieve(mfnode, "until");
          }
        },
        "count" : {
          virtual: true,
          /* This will only be called in the virtual case */
          virtualGetter: function(mfnode) {
            return Microformats.hCalendar.properties.rrule.retrieve(mfnode, "count");
          }
        }
      },
      retrieve: function(mfnode, property) {
        var value = Microformats.parser.textGetter(mfnode);
        var rrule;
        rrule = value.split(';');
        for (let i=0; i < rrule.length; i++) {
          if (rrule[i].match(property)) {
            return rrule[i].split('=')[1];
          }
        }
      }
    }
  }
};

Microformats.add("hCalendar", hCalendar_definition);

function geo(node, validate) {
  if (node) {
    Microformats.parser.newMicroformat(this, node, "geo", validate);
  }
}
geo.prototype.toString = function() {
  if (this.latitude != undefined) {
    if (!isFinite(this.latitude) || (this.latitude > 360) || (this.latitude < -360)) {
      return;
    }
  }
  if (this.longitude != undefined) {
    if (!isFinite(this.longitude) || (this.longitude > 360) || (this.longitude < -360)) {
      return;
    }
  }

  if ((this.latitude != undefined) && (this.longitude != undefined)) {
    var s;
    if ((this.node.localName.toLowerCase() == "abbr") || (this.node.localName.toLowerCase() == "html:abbr")) {
      s = this.node.textContent;
    }

    if (s) {
      return s;
    }

    /* check if geo is contained in a vcard */
    var xpathExpression = "ancestor::*[contains(concat(' ', @class, ' '), ' vcard ')]";
    var xpathResult = this.node.ownerDocument.evaluate(xpathExpression, this.node, null,  Components.interfaces.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE, null);
    if (xpathResult.singleNodeValue) {
      var hcard = new hCard(xpathResult.singleNodeValue);
      if (hcard.fn) {
        return hcard.fn;
      }
    }
    /* check if geo is contained in a vevent */
    xpathExpression = "ancestor::*[contains(concat(' ', @class, ' '), ' vevent ')]";
    xpathResult = this.node.ownerDocument.evaluate(xpathExpression, this.node, null,  Components.interfaces.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE, xpathResult);
    if (xpathResult.singleNodeValue) {
      var hcal = new hCalendar(xpathResult.singleNodeValue);
      if (hcal.summary) {
        return hcal.summary;
      }
    }
    if (s) {
      return s;
    } else {
      return this.latitude + ", " + this.longitude;
    }
  }
}

var geo_definition = {
  mfObject: geo,
  className: "geo",
  required: ["latitude","longitude"],
  properties: {
    "latitude" : {
      datatype: "float",
      virtual: true,
      /* This will only be called in the virtual case */
      virtualGetter: function(mfnode) {
        var value = Microformats.parser.textGetter(mfnode);
        var latlong;
        if (value.match(';')) {
          latlong = value.split(';');
          if (latlong[0]) {
            if (!isNaN(latlong[0])) {
              return parseFloat(latlong[0]);
            }
          }
        }
      }
    },
    "longitude" : {
      datatype: "float",
      virtual: true,
      /* This will only be called in the virtual case */
      virtualGetter: function(mfnode) {
        var value = Microformats.parser.textGetter(mfnode);
        var latlong;
        if (value.match(';')) {
          latlong = value.split(';');
          if (latlong[1]) {
            if (!isNaN(latlong[1])) {
              return parseFloat(latlong[1]);
            }
          }
        }
      }
    }
  },
  validate: function(node) {
    var latitude = Microformats.parser.getMicroformatProperty(node, "geo", "latitude");
    var longitude = Microformats.parser.getMicroformatProperty(node, "geo", "longitude");
    if (latitude != undefined) {
      if (!isFinite(latitude) || (latitude > 360) || (latitude < -360)) {
        throw("Invalid latitude");
      }
    } else {
      throw("No latitude specified");
    }
    if (longitude != undefined) {
      if (!isFinite(longitude) || (longitude > 360) || (longitude < -360)) {
        throw("Invalid longitude");
      }
    } else {
      throw("No longitude specified");
    }
    return true;
  }
};

Microformats.add("geo", geo_definition);

function tag(node, validate) {
  if (node) {
    Microformats.parser.newMicroformat(this, node, "tag", validate);
  }
}
tag.prototype.toString = function() {
  return this.tag;
}

var tag_definition = {
  mfObject: tag,
  attributeName: "rel",
  attributeValues: "tag",
  properties: {
    "tag" : {
      virtual: true,
      virtualGetter: function(mfnode) {
        if (mfnode.href) {
          var ioService = Components.classes["@mozilla.org/network/io-service;1"].
                                     getService(Components.interfaces.nsIIOService);
          var uri = ioService.newURI(mfnode.href, null, null);
          var url_array = uri.path.split("/");
          for(let i=url_array.length-1; i > 0; i--) {
            if (url_array[i] !== "") {
              var tag
              if (tag = Microformats.tag.validTagName(url_array[i].replace(/\+/g, ' '))) {
                try {
                  return decodeURIComponent(tag);
                } catch (ex) {
                  return unescape(tag);
                }
              }
            }
          }
        }
        return null;
      }
    },
    "link" : {
      virtual: true,
      datatype: "anyURI"
    },
    "text" : {
      virtual: true
    }
  },
  validTagName: function(tag)
  {
    var returnTag = tag;
    if (tag.indexOf('?') != -1) {
      if (tag.indexOf('?') === 0) {
        return false;
      } else {
        returnTag = tag.substr(0, tag.indexOf('?'));
      }
    }
    if (tag.indexOf('#') != -1) {
      if (tag.indexOf('#') === 0) {
        return false;
      } else {
        returnTag = tag.substr(0, tag.indexOf('#'));
      }
    }
    if (tag.indexOf('.html') != -1) {
      if (tag.indexOf('.html') == tag.length - 5) {
        return false;
      }
    }
    return returnTag;
  },
  validate: function(node) {
    var tag = Microformats.parser.getMicroformatProperty(node, "tag", "tag");
    if (!tag) {
      if (node.href) {
        var url_array = node.getAttribute("href").split("/");
        for(let i=url_array.length-1; i > 0; i--) {
          if (url_array[i] !== "") {
            throw("Invalid tag name (" + url_array[i] + ")");
          }
        }
      } else {
        throw("No href specified on tag");
      }
    }
    return true;
  }
};

Microformats.add("tag", tag_definition);


"This would effectually kill in us all the little seeds of pride, vanity and self-conceit, which are apt to shoot up in the minds of such whose thoughts turn more on those comparative advantages which they enjoy over some of their fellow-creatures, than on that infinite distance which is placed between them and the supreme model of all perfection."
This would effectually kill in us all the little seeds of pride, vanity and self-conceit, which are apt to shoot up in the minds of such whose thoughts turn more on those comparative advantages which they enjoy over some of their fellow-creatures, than on that infinite distance which is placed between them and the supreme model of all perfection. It would likewise quicken our desires and endeavours of uniting our selves to him by all the acts of religion and virtue.


text:
"use strict";

var possel = {
  users: [],
  buffers: [],
  get_user: function(id){
    return $.get("/user/" + id);
  },
  events: {
    submit_event: function(node) {
      $(node).submit(function(event) {
        event.preventDefault();
        var message = $('#message-input').val();
        var buffer_id = $('.buffer.active')[0].id;
        possel.send_line(buffer_id, message).then(function(){
          $('#message-input').val('');
        });
      });
    }
  },
  get_buffer: function(id){
    return $.get("/buffer/" + id);
  },
  get_line_by_id: function(id){
    return $.get("/line?id=" + id);
  },
  get_last_line: function(){
    return $.get("/line?last=1");
  },
  send_line: function(buffer, content){
    return $.ajax({
      type: 'POST',
      url: '/line',
      data: JSON.stringify({ buffer: buffer,
                             content: content
                           }),
      contentType: 'application/json'
    });
  },
  login: function(username, password){
    var data = JSON.stringify({username: username, password: password});
    return $.ajax({
      type: 'POST',
      url: '/session',
      data: data,
      contentType: 'application/json'
    });
  },
  verify_token: function(){
    return $.ajax({
      type: 'GET',
      url: '/session',
    });
  },
};

var PosselTemplate = {
  templates: {},
  orange: '#C9952E',
  load: function(url){
    var that = this;
    return $.get(url, function(html, textStatus, jqXhr){
      var obj = $('<div/>').html(html).contents().filter('div');
      obj.each(function(index, template){
        that.templates[template.id] = Handlebars.compile(template.innerHTML);
      });
    });
  },
}

$(function(){
  var users = [], buffers = [];

  function scroll_to_bottom(element){
    element.scrollTop(element.prop('scrollHeight'));
  }

  function new_user(user){
    users[user.id] = user;
    user.color = Please.make_color();
  }

  function prepopulate_line_buffer(line_id, buffer_id){
    $('#' + buffer_id).append(PosselTemplate.templates.prepopulate_line({line_id: line_id}));
  }

  function new_line(line){
    var buffer = buffers[line.buffer], user = users[line.user], use_user, line_element;
    use_user = user;
    if(user == null){
      use_user = {
        color: PosselTemplate.orange,
      }
    }
    switch(line.kind){
      case 'action':
      case 'join':
      case 'quit':
      case 'part':
        use_user = {
          color: PosselTemplate.orange,
        };
        line.content = line.nick + ' ' + line.content;
        line.nick = '-*-';
        break;
    }

    line_element = $('#line-' + line.id);
    line_element.addClass('buffer-line-' + line.kind);

    line_element.append(PosselTemplate.templates.line({
      line: line,
      user: use_user,
      timestamp: moment.unix(line.timestamp).format('HH:mm:ss'),
    }));

    // Do some colouring
    switch(line.kind){
      case 'action':
        line_element.attr('style', 'color: ' + user.color + ';');
        break;
      case 'notice':
        line_element.attr('style', 'color: ' + PosselTemplate.orange + ';');
        break;
      case 'join':
      case 'part':
      case 'quit':
        line_element.attr('style', 'color: gray;');
        break;
    }
    line_element.linkify({target: '_blank'});
    scroll_to_bottom($('#message-pane'));
  }

  function new_buffer(buffer){
      var buffer_link, nav_item = PosselTemplate.templates.nav_item;
      buffers[buffer.id] = buffer;
      switch(buffer.kind){
        case "system":
          $('#bufferlist').append(nav_item({
            buffer: buffer,
            system: true,
          }));
          break;
        case "normal":
          $('#server-buffer-link-' + buffer.server).after(nav_item({
            buffer: buffer,
            system: false,
          }));
          break;
      }
      $("#message-pane").append(PosselTemplate.templates.buffer_pane({buffer: buffer}));
      buffer_link = $('#bufferlist a[href="#' + buffer.id + '"]');
      buffer_link.on('shown.bs.tab', function(event){
        scroll_to_bottom($('#message-pane'));
      });
      buffer_link.tab('show');
  }

  function prepopulate_lines(last_line_data, nlines){
    if (last_line_data.length == 0) {
      console.warn("no lines found.");
      return 0;
    }
    var last_line = last_line_data[0];
    $.get("/line?after=" + (last_line.id - nlines)).then(function(lines){
      lines.forEach(function(line){
        prepopulate_line_buffer(line.id, line.buffer);
        new_line(line);
      });
    });
  }

  function handle_push(event){
    var msg = JSON.parse(event.data);
    switch(msg.type){
    case "line":
      prepopulate_line_buffer(msg.line, msg.buffer);
      possel.get_line_by_id(msg.line).then(function(data) {
        var line = data[0];
        new_line(line);
      });
      break;
    case "buffer":
      possel.get_buffer(msg.buffer).then(function(buffer_data){
        new_buffer(buffer_data[0]);
      });
      break;
    case "user":
      possel.get_user(msg.user).then(function(user_data){
        new_user(user_data[0]);
      });
    }
  }

  function init(){
    console.log('Initializing');
    possel.events.submit_event('#message-input-form');
    $(document).keypress(function(e){
      $('#message-input').focus();
    });
    $.when(possel.get_user("all"),
        possel.get_buffer("all"),
        possel.get_last_line(),
        PosselTemplate.load('/static/templates.html')
        )
      .done(function(user_data, buffer_data, last_line_data){
        console.log('done preparing');
        user_data[0].forEach(function(user){
          new_user(user);
        });
        buffer_data[0].forEach(function(buffer) {
          new_buffer(buffer);
        });
        var ws = new ReconnectingWebSocket(ws_url);
        ws.onopen = function() {
          console.log("connected");
        };
        ws.onclose = function() {
          console.log("disconnected");
        };
        ws.onmessage = handle_push;
        prepopulate_lines(last_line_data[0], 3000);
      });
  }

  function do_login(){
    $('#login-modal').modal('show');
    $('#login-submit').on('click', function(event){
        var username = $('#login-username').val(), password = $('#login-password').val();
        possel.login(username, password).done(init);
    });
  }

  if(Cookies.get('token')){
    possel.verify_token().done(init).fail(do_login);
  }else{
    do_login();
  }
});

redpajama_set_name: RedPajamaGithub


Mentor Graphics, Inc was a US-based multinational corporation dealing in electronic design automation (EDA) for electrical engineering and electronics, and is now a subsidiary of Germany industrial giant Siemens. Founded in 1981, the company is headquartered in Wilsonville, Oregon, and employs roughly 5,200 people worldwide with annual revenues of around $1 billion.
In 1981, the idea of computer-aided design for electronics as the foundation of a company occurred to several groups - those who founded Mentor, Valid Logic Systems, and Daisy Systems. One of the main distinctions between these groups was that the founding engineers of Mentor, whose backgrounds were in software development at Tektronix, ruled out designing and manufacturing proprietary computers to run their software applications. They felt that hardware was going to become a commodity owned by big computer companies, so instead they would select an existing computer system as the hardware platform for the Computer Aided Engineering (CAE) programs they would build.
By February 1981, most of the start-up team had been identified; by March, the three executive founders, Tom Bruggere, Gerry Langeler and Dave Moffenbeier had left Tektronix, and by May the business plan was complete. The first round of money, $1 million, came from Sutter Hill, Greylock, and Venrock Associates. The next round was $2 million from five venture capital firms, and in April 1983 a third round raised $7 million more. Mentor Graphics was one of the first companies to attract venture capital to Oregon.
Apollo Computer workstations were chosen as the initial hardware platform. Based in Chelmsford, Apollo was less than a year old and had only announced itself to the public a few weeks prior to when the founders of Mentor Graphics began their initial meetings.
When Mentor entered the CAE market the company had two technical differentiators: the first was the software - Mentor, Valid, and Daisy each had software with different strengths and weaknesses. The second, was the hardware - Mentor ran all programs on the Apollo workstation, while Daisy and Valid each built their own hardware. By the late 1980s, all EDA companies abandoned proprietary hardware in favor of workstations manufactured by companies such as Apollo and Sun Microsystems.
After a frenzied development, the IDEA 1000 product was introduced at the 1982 Design Automation Conference, though in a suite and not on the floor.
In June 2008, Cadence Design Systems offered to acquire Mentor Graphics in a leveraged buyout. On 15 August 2008, Cadence withdrew this offer quoting an inability to raise the necessary capital and the unwillingness of Mentor Graphics' Board and management to discuss the offer. Mentor acquired Flomerics Group plc for $60 million in cash in October 2008, and in August 2009, Mentor completed the acquisition of silicon manufacturing testing company LogicVision for $13 million in an all-stock deal. Mentor completed the acquisition of Valor Computerized Systems in March 2010 in a cash and stock deal valued at $50 million.
On 22 February 2011, Carl Icahn, an activist investor, made an offer to buy the company for about $1.86 billion in cash.
As of 2012, Mentor's major competitors are: Cadence Design Systems, Synopsys, Altium, and Zuken.
On March 3, 2015 Mentor Graphics announced it had acquired the business assets of Tanner EDA.
On 14 November 2016, Mentor Graphics announced that it was to be acquired by Siemens for $4.5 billion, at $37.25 per share, a 21% premium on Mentor's closing price on the previous Friday. The acquisition was completed in March 2017.
Mentor Graphics product development takes place in the USA, Poland, Hungary, Japan, Pakistan, India and Egypt. James "Jim" Ready, left Mentor in 1999 to form the embedded Linux company MontaVista. Neil Henderson joined Mentor Graphics in 2002 with the acquisition of Accelerated Technology Inc. Stephen Mellor, a leader in the UML space and co-originator of the Shlaer-Mellor design methodology, joined Mentor Graphics in 2004 following the acquisition of Project Technology.
Walden C. Rhines is the company's chairman of the board and chief executive officer whereas Gregory K. Hinckley serves as the president of the corporation.
QuestaSim is a Simulator with additional Debug capabilities targeted at complex FPGA's and SoC's. QuestaSim can be used by users who have experience with ModelSim as it shares most of the common debug features and capabilities. One of the main differences between QuestaSim and Modelsim (besides performance/capacity) is that QuestaSim is the simulation engine for the Questa Platform which includes integration of Verification Management, Formal based technologies, Questa Verification IP, Low Power Simulation and Accelerated Coverage Closure technologies. QuestaSim natively supports SystemVerilog for Testbench, UPF, UCIS, OVM/UVM where ModelSim does not.
FloTHERM XT is a electronics cooling CFD tool incorporating a solid modeler for manipulating MCAD parts.
TeraLED provides automation of the CIE 127:2007 standard providing total flux, chromaticity and correlated color temperature (CCT) for power LEDs. With T3Ster it provides thermal resistance metrics for LEDs based on the real dissipated heating power.
DynTIM extends T3Ster, providing a dynamic thermal test station for thermal conductivity measurements of thermal interface materials (TIMs), thermal greases and gap pads.
FloMASTER is a 1D or system-level CFD solution for analyzing fluid mechanics in complex pipe flow systems (from the acquisition of Flowmaster Ltd in 2012).
CADRA Design Drafting is a 2-1/2D mechanical drafting and documentation package specifically designed for drafting professionals. It provides the tools needed to develop complex drawings quickly and easily (from the acquisition of the CADRA product in 2013).
The Veloce product family enables SoC emulation and transaction-based acceleration.


text:
vulture lists June 3, 2015
8 New Offerings From Dead Authors
By David Marchese
It's shaping up to be a fruitful summer for these dead authors.
What Pet Should I Get?, by Dr. Seuss (1904–1991)
Oh, who knows the places you'll go! The publishers, anyway, are planning a bank trip — Random House ordered a first printing of a million copies for WPSIG, believed to have been created by Seuss between 1958 and 1962 and then discovered, lost, and rediscovered by his widow. It features the kids from One Fish Two Fish Red Fish Blue Fish and couplets that — you bet — rhyme pet with get.
July 28, Random House; 48 pages; $18
Meanwhile There Are Letters, by Eudora Welty (1909–2001) and Ross Macdonald (1915–83)
The odd-couple correspondence between southern novelist Welty and Canadian crime writer Macdonald amounts to an epistolary meet-cute, one touched with what if — Welty never wed, and Macdonald's marriage was mild, facts hinted at in these letters' gentle swings between platonic and romantic love.
July 7, Arcade; 568 pages; $35
Let Me Tell You, by Shirley Jackson (1916–1965)
A master of uncanny suspense, Jackson wrote sentences that crept up on the reader, knife in hand. Throughout these previously unpublished pieces, whether short stories about Main Street murders or Jackson's description of her own eerie writing process (sleepwalking and ghosts helped), the author's mordant wit and nuanced prose are often shiver-inducing.
August 4, Random House; 448 pages; $30
33 Days, by Léon Werth (1878–1955)
If English-language readers know Werth, it's likely as the man to whom Antoine de Saint-Exupéry dedicated his deathless classic The Little Prince. A nonfiction account of the Jewish Werth's flight from Paris after the Nazi invasion, the riveting 33 Days, now in its first English translation, proves that the author was no mere footnote.
Available now, Melville House; 144 pages; $16
Ideal, by Ayn Rand (1905–1982)
Some novels hold the power to shape lives. Objectivist goddess Rand's Hollywood allegory Ideal is not one of them. Troubled starlet Kay Gonda goes on the lam and shows up at the homes of six fans who have written to her. People say stuff like "The doctor's bills is something fierce." Even Howard Roark might've advised letting an editor take another pass.
July 7, New American Library; 256 pages; $27
My Generation: Collected Nonfiction, by William Styron (1925–2006)
A problem with being successful is that people will pay you to do things other than what you did to become a success. Styron was a great novelist; My Generation suggests that he was only a pretty good nonfiction writer. He's best when he goes hard — e.g., his essay defending Fitzgerald — but much of this material has the vibe of well-wrought job work.
June 2, Random House; 656 pages; $35
Our Souls at Night, by Kent Haruf (1943–2014)
Haruf passed away this past November at 71, but not before finishing Our Souls at Night, a glowing sunset of a novel. Returning to his fictional Colorado town of Holt, Haruf traces, with unsentimental grace, the tentative romance of 70-something widowers Addie and Louis as they navigate small-town gossip, confused grandkids, and their own cautious hearts.
Available now, Knopf; 192 pages; $24
The Girl in the Spider's Web, by David Lagercrantz
Okay, here's a bit of a fudge: Lagercrantz is alive. But Stieg Larsson, who wrote the megaselling series of which this novel is a continuation, passed away in 2004. Larsson's literary estate tapped Lagercrantz to further the story of goth-hacker Lisbeth Salander and journalist Mikael Blomkvist, who again deal with cybercrime and lurid corruption.
September 1, Knopf; 400 pages; $28
*This article appears in the June 1, 2015 issue of New York Magazine.
leon werth

redpajama_set_name: RedPajamaCommonCrawl


For an elegant floral that will add a pop of colour to your looks. The Reign Skirt is our new favourite style of the season, thanks to its graceful, flowing shape, and hand painted poppy floral print. Completely feminine and utterly chic, this is the perfect skirt to wear for summer days with your favourite tees and sandals.


text:
package org.oss.jstub;

import org.junit.Test;
import org.oss.jstub.pojo.SimplePojo;

import java.util.Arrays;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

public class StubFactoryWithBuilderTest {

    @Test
    public void testWithIgnoreSetters() {
        StubFactory stubFactory = StubFactory.builder()
                .addIgnoredSetter("setName")
                .build();
        SimplePojo pojo = stubFactory.createStub(SimplePojo.class);
        assertNull(pojo.getName());
        assertTrue(pojo.getAnInt() != 0);
    }

    @Test
    public void testWithCustomValue() {
        String[] customValues = {"a", "b"};
        StubFactory stubFactory = StubFactory.builder()
                .addCustomValue("setName", customValues)
                .build();
        SimplePojo pojo = stubFactory.createStub(SimplePojo.class);
        assertTrue(Arrays.asList(customValues).contains(pojo.getName()));
    }

    @Test
    public void testCustomSupplier() {
        StubFactory stubFactory = StubFactory.builder()
                .addCustomSupplier("setName", this::getValue)
                .build();
        SimplePojo pojo = stubFactory.createStub(SimplePojo.class);
        assertEquals(getValue(), pojo.getName());
    }

    private String getValue() {
        return "I kent bă Liviu";
    }

}


text:
Jason Newsted Suffers Shoulder Injury In Accident
By Jackamo!
October 25, 2006 in MY WORLD
Jackamo!
Location:Cape Breton Island, Canada
ROCK STAR SUPERNOVA BASSIST JASON NEWSTED SUFFERS SHOULDER INJURY IN ACCIDENT: As they gear up for the November 21st release of their highly anticipated Epic debut and the New Year's Eve launch of their much-buzzed-about national tour, ROCK STAR SUPERNOVA have suffered a major setback with the loss of all-star bassist Jason Newsted.
The former Metallica member is scheduled for immediate surgery to repair a torn anterior labrum in his left shoulder and a rotator cuff and bicep tear in the right. Newsted suffered the injuries while trying to catch a 90-lb bass head that had fallen from atop his amp. The surgery will be followed by a lengthy rehab assignment that could leave him sidelined for up to nine months.
"I'm freaking out," Says Newsted, "My heart was set on finally getting on the road with these guys, but my main focus now is to build myself back to 100%. The stage is set for the band, I wish them the best of luck."
The band - rounded out by vocalist Lukas Rossi, drummer Tommy Lee and guitarist Gilby Clarke - is currently searching for a suitable replacement to handle touring duties while Newsted recovers.
"When we started this project, I was handed a list of names--guys who could potentially anchor our rhythm section," says Lee. "I responded by crumpling up the paper and asking, 'Where's Newsted?' Jason was always the right guy for this band and we'll miss having him with us as we kick off our album and tour, but we know he'll be back as soon as he can pick up and play. As for who will handle bass duties until then, we've got a few monster guys in mind, any one of which can hit the ground running. Stay tuned."
VISIT TOMMYLEE.TV FOR UPDATES ON THIS
(It's from Lukas' myspace)
That sucks. Nothing is going well for (Rock Star) Supernova.
JONEZY
Location:ILLINOIS
Michael Anthony (Van Halen) is available.
bass71player
Location:New Paltz, NY for school... Hauppauge, NY is my home
man, eddie's such a dick...
I can just see Michael Anthony going..."Rockstar Supernova?...uh...thanks...but...no".
True. But a few years ago, I never thought Tommy Lee/Gilby Clark or Jason Newstead would be in a reality show. Same with Ted Nugent/Sebastian Bach...etc
Money talks, I guess.
I wish money would talk to me, I would definitely listen.
moreblack
What does this mean for Voivod also?
anyways, just get Robert Trujillo
Location:Chicago, Illinois USA
You should've just let it fall Jason, you know damn well you've got more than enough money to replace or repair it.


text:
The Funny & Amusing
Pro Boxing
Fight card preview
Updated Schedule
Top 100 Ring Card Girls
Amateur Boxing
Battle of the Badges
Photos from the thrilling Matthysee vs. Molina fight
Between rounds, both Lucas Matthysse (l) and John Molina (r) listen intently to the instructions from their trainers. Photo: Joe Scarnici/Getty Images
On Saturday, April 26, 2014, the 5'6½ inch, #1 ranked welterweight, Lucas "La Máquina" Matthysse rose from the ashes, a victim of two early knockdowns, one in the second round, another in the fifth, to eventually out trump the 5'10½ inch John Molina with three knockdowns of his own on his way to an 11th round stoppage at the StubHub Center in Carson, CA.
Matthysse dropped Molina once each in the 8th, 10th and 11th rounds before referee Pat Russell finally waved an end to a contest that had most patrons on the edge of their seats from start to finish.
Even though Matthysse was the busier and more accurate of the two, you always had the feeling Molina could still pull out a late victory. How so? Reputation. The Covina, CA native entered this contest after knocking out his two previous opponents, the unbeaten Mickey Bey and veteran Jorge Pimentel.
In summation, Matthysse, the better schooled boxer, held an advantage in punches thrown 276-to-104, power shots 204-to-86, and jabs 71-18. With his win, the 31-year-old from Junin, Buenos Aires, Argentina, improves his record to 35 wins with 3 losses and 33 knockouts. Molina's record drops to 27 wins with 4 losses and 22 KOs.
After establishing a record of 4 wins, 3 losses, and 4 KOs, against six current or former titleholders, having floored all of them, Matthysse is without a doubt a real crowd pleaser.
The most telling rounds
Round 2. Molina dropped Matthysse with a solid overhand right to the temple with 26 seconds left in the round. This was only the second time in Matthysse's career that someone has knocked him off his feet. He then held on to get out of the round.
Round 3. Matthysse looked sharp and landed both to the head and body while Molina appeared to be waiting for another opportunity to land that big punch. Then came a clash of heads and Matthysse started bleeding from the resulting cut over his left eye.
Round 5. Matthysse became the victim of another overhand right, this one nailing him behind the head, and he went down. The round ended with both boxers blasting away in a neutral corner.
Here we see John Molina (c) knocking Lucas Matthysse off his feet in round 5 at the StubHub Center in Carson, CA. Photo: Joe Scarnici/Getty Images
Round 6. Matthysse continued to carry the action and had a sizable advantage in power shots of 63-31 over the first five rounds. Still, another hard right by Molina at the close of round six appeared to hurt Matthysee.
Round 7 was another hotly contested round with Matthysse landing the majority of the cleaner shots.
Round 8. Matthysse had Molina cornered against the ropes and kept pounding away. A hard right followed by a doubling up of the jab preceded this devastating left uppercut that dropped Molina. A true warrior, Molina somehow survived this onslaught and finished the round.
Referee Pat Russell stands over the fallen John Molina after he was knocked down in the 8th round by Lucas Matthysse. Photo: Joe Scarnici/Getty Images
Round 9. Once again, Matthysse dominated and appeared much peppier in comparison to the now lumbering Molina.
Round 10. The beat down continued until Molina finally went down. Back up at the count of seven, the resilient Molina survived the round which at one point consisted of 14 unanswered blows.
Lucas Matthysse continues to deliver the heavy blows to John Molina in both the 10th and 11th rounds until the final stoppage. Photo: Joe Scarnici/Getty Images
Round 11. With both the referee and fight doctor close to stopping the match between rounds, the end came just 22 seconds into round 11, just moments after Molina went down from another solid right. At this point, it appeared Molina had no chance of continuing and the bout was justifiably stopped.
(left) At the conclusion of their memorable bout, both John Molina (l) and Lucas Matthysse (r) congratulate one another on their fine performance. Photo: Joe Scarnici/Getty Images
With all the excitement surrounding the Matthysse/Molina fight, it's as if the other matches didn't even exist. The Main Event, which featured the unbeaten WBA Interim Welterweight Champ Keith "One Time" Thurman (23-0, 21 KOs) of Clearwater, Fla., ended early with a third-round TKO of the former world champion Julio "The Kidd" Diaz (40-10-1, 29 KOs) of Coachella, Ca. After getting hit with a body shot in round three, Diaz, upon the advice of his corner, stayed on his stool and did not come out for the fourth round.
Up until that left hook to the midsection, Julio Diaz (red trunks) was giving a good account of himself. The reason Diaz's corner decided to throw in the towel was the belief that Keith Thurman's powerful punch may have broken a rib.
Keith Thurman has his arm raised in victory by referee Jack Reiss after he stopped Julio Diaz to win the interim WBA Welterweight Championship at the StubHub Center on April 26, 2014 in Carson, CA. Photo: Joe Scarnici/Getty Images
Next, you had the undefeated Omar "Panterita" Figueroa successfully defending his WBC lightweight crown in a ho-hum 12-round split decision bout over a former rival in the Amateur ranks, Jerry Belmontes.
After losing all five of his amateur bouts against Belmontes, Figueroa (23-0-1, 17 KOs) of Weslaco, Texas, got his revenge in his first world title defense, outpointing Belmontes (19-4, 5 KOs), of Corpus Christi, Texas, by scores of 118-110, 116-112 and 113-115.
(top, left) Jerry Belmontes makes his ring entrance at the StubHub Center. (top, right) Omar Figueroa Jr. looks across at his arch nemesis, a gentleman who had beaten him five times in the Amateur ranks. Photo: Joe Scarnici/Getty Images
(bottom, right) Omar Figueroa (c) poses for a photo with his trainer Joel Diaz (l) after the split decision victory over Jerry Belmontes.
One of those priceless Father, Daughter moments for the WBC World Lightweight Champion Omar Figueroa Jr. from Weslaco, Texas.
In the featured match on Showtime Extreme, world-ranked junior middleweight Jermall Charlo (18-0, 14 KOs), of Houston, dominated Albuquerque's Hector Munoz (22-13-1, 14 KOs) en route to a fourth-round TKO. With Munoz's record being 4-12-1 over the past six years, it's difficult to get excited about this win.
Undefeated Joseph Diaz Jr. (10-0, 7 KOs) won all six rounds in his decision victory over veteran Luis Maldonado (38-12-1, 29 KOs) of Calexico, CA, and unbeaten super welterweight Terrell Gausha of Cleveland improved to (9-0-0, 5 KOs) with an eight-round shutout over Charles Whittaker (40-15-2), of Winter Haven, Fla.
The Showtime Championship Boxing triple header will re-air on Tuesday, April 29th, at 10 p.m.
Copyright © 2021 SportofBoxing.com - All Rights Reserved. | Disclaimers & Privacy


Nooyi exhibits some characteristics that have enabled her to be effective in her role as a manager. One of her utmost characteristic was that she accepted employees and regarded them positively; this was seen as she tried to find a favorable balance between her intensity and what she wanted done. This made all employees feel valued and which in turn, enhance their performance. The performance of a worker is influenced by his or her personal life. Therefore, she was concerned about the personal life of all workers, as well as their families.
Moreover, she had the ability to treat workers as individuals; she tried to understand the behaviors of different employees and that enabled her to influence their behaviors so that all employees could follow her directives willingly.
Additionally, she was helpful and polite person when providing explanations and instructions to employees. She applied a mother like approach to all workers, and this helped her to add a nurturing touch to her work. Workers felt not under intense pressure to perform, but still felt the urge to grow due to her high expectations for every member of the organization's workforce. Lastly, she was patient and always willing to deliver any kind of help to all employees as well as any explanations useful in getting the work done. This was essential in achieving the goals of the organization. Nooyi's workforce was extremely diverse at various aspects since employees came from different backgrounds. The greatest organizational practice she applied to deal with diversity was to create a common motto for all employees.
Leadership involves giving direction or leading, and it seems she had made a goal focusing on the company's growth in the international market. She articulated the specific approaches such as balancing profit with healthier products for customers, as well as engaging in production of more environmentally friendly products. Those approaches were to be used by the company in the realization of its goals. As a leader, she had provided guidance to the company with regard to the company's income as well as the society in which the firm was operating. The channel in which the instructions follow in a firm is extremely crucial to any company, and that is why her setting of goals and the motto were both preceded by restructuring. This was important because instructions can flow smoothly to all employees at different levels for them to work together in the attainment of a common goal.
Leadership is all about being able to influence how other people behave so that they can follow the directives willingly and work towards attaining common goals. She understood her employees and always tried to balance work and the social aspects of her employees and this had a motivating effect. Working continuously can reduce productivity, but she allowed occasional breaks. The families of employees are also taken care of, and this motivated them further.