<commit_before>//     postscribe.js 1.0.5
//     (c) Copyright 2012 to the present, Krux
//     postscribe is freely distributable under the MIT license.
//     For all details and documentation:
//     http://krux.github.com/postscribe

(function() {

  var globals = this;

  if(globals.postscribe) {
    return;
  }

  // Debug write tasks.
  var DEBUG = true;

  // Turn on to debug how each chunk affected the DOM.
  var DEBUG_CHUNK = false;

  // # Helper Functions

  var slice = Array.prototype.slice;

  // A function that intentionally does nothing.
  function doNothing() {}

  // Is this a function?
  function isFunction(x) {
    return "function" == typeof x;
  }

  // Loop over each item in an array-like value.
  function each(arr, fn, _this) {
    var i, len = (arr && arr.length) || 0;
    for(i = 0; i < len; i++) {
      fn.call(_this, arr[i], i);
    }
  }

  // Loop over each key/value pair in a hash.
  function eachKey(obj, fn, _this) {
    var key;
    for(key in obj) {
      if(obj.hasOwnProperty(key)) {
        fn.call(_this, key, obj[key]);
      }
    }
  }

  // Set properties on an object.
  function set(obj, props) {
    eachKey(props, function(key, value) {
      obj[key] = value;
    });
    return obj;
  }

  // Set default options where some option was not specified.
  function defaults(options, _defaults) {
    options = options || {};
    eachKey(_defaults, function(key, val) {
      if(options[key] == null) {
        options[key] = val;
      }
    });
    return options;
  }

  // Convert value (e.g., a NodeList) to an array.
  function toArray(obj) {
    try {
      return slice.call(obj);
    } catch(e) {
      var ret = [];
      each(obj, function(val) {
        ret.push(val);
      });
      return ret;
    }
  }

  // Test if token is a script tag.
  function isScript(tok) {
    return (/^script$/i).test(tok.tagName);
  }

  // # Class WriteStream

  // Stream static html to an element, where "static html" denotes "html without scripts".

  // This class maintains a *history of writes devoid of any attributes* or "proxy history".
  // Injecting the proxy history into a temporary div has no side-effects,
  // other than to create proxy elements for previously written elements.

  // Given the `staticHtml` of a new write, a `tempDiv`'s innerHTML is set to `proxy_history + staticHtml`.
  // The *structure* of `tempDiv`'s contents, (i.e., the placement of new nodes beside or inside of proxy elements),
  // reflects the DOM structure that would have resulted if all writes had been squashed into a single write.

  // For each descendent `node` of `tempDiv` whose parentNode is a *proxy*, `node` is appended to the corresponding *real* element within the DOM.

  // Proxy elements are mapped to *actual* elements in the DOM by injecting a data-id attribute into each start tag in `staticHtml`.
  var WriteStream = (function(){

    // Prefix for data attributes on DOM elements.
    var BASEATTR = 'data-ps-';

    // get / set data attributes
    function data(el, name, value) {
      var attr = BASEATTR + name;

      if(arguments.length === 2) {
        // Get
        var val = el.getAttribute(attr);

        // IE 8 returns a number if it's a number
        return val == null ? val : String(val);

      } else if( value != null && value !== '') {
        // Set
        el.setAttribute(attr, value);

      } else {
        // Remove
        el.removeAttribute(attr);
      }
    }

    function WriteStream(root, options) {
      var doc = root.ownerDocument;

      set(this, {
        root: root,

        options: options,

        doc: doc,

        parser: globals.htmlParser('', { autoFix: true }),

        // Actual elements by id.
        actuals: [root],

        // Embodies the "structure" of what's been written so far, devoid of attributes.
        proxyHistory: '',

        // Create a proxy of the root element.
        proxyRoot: doc.createElement(root.nodeName),

        scriptStack: [],

        writeQueue: []
      });

      data(this.proxyRoot, 'proxyof', 0);

    }

    WriteStream.prototype.write = function() {
      [].push.apply(this.writeQueue, arguments);
      this.processWriteQueue();
    };

    WriteStream.prototype.processWriteQueue = function() {
      // Check for pending writes
      // When new script gets pushed or pending this will stop
      // because new writeQueue gets pushed
      while(!this.deferredRemote &&
            this.writeQueue.length) {

        this.writeImpl(this.writeQueue.shift());
      }

    };

    WriteStream.prototype.writeImpl = function(arg) {
      if(isFunction(arg)) {
        // Callback
        return arg();
      }

      this.parser.append(arg);

      var tok, tokens = [];

      // stop if we see a script token
      while((tok = this.parser.readToken()) && !isScript(tok)) {
        tokens.push(tok);
      }

      this.writeStaticTokens(tokens);

      if(tok) {
        this.handleScriptToken(tok);
      }
    };

    // ## Contiguous non-script tokens (a chunk)
    WriteStream.prototype.writeStaticTokens = function(tokens) {

      var chunk = this.buildChunk(tokens);

      if(!chunk.actual) {
        // e.g., no tokens, or a noscript that got ignored
        return;
      }
      chunk.html = this.proxyHistory + chunk.actual;
      this.proxyHistory += chunk.proxy;

      this.proxyRoot.innerHTML = chunk.html;

      if(DEBUG_CHUNK) {
        chunk.proxyInnerHTML = this.proxyRoot.innerHTML;
      }

      this.walkNodes();

      if(DEBUG_CHUNK) {
        chunk.actualInnerHTML = this.root.innerHTML; //root
      }

      return chunk;
    };

    WriteStream.prototype.buildChunk = function (tokens) {
      var nextId = this.actuals.length,

          // The raw html of this chunk.
          raw = [],

          // The html to create the nodes in the tokens (with id's injected).
          actual = [],

          // Html that can later be used to proxy the nodes in the tokens.
          proxy = [];

      each(tokens, function(tok) {

        raw.push(tok.text);

        if(tok.attrs) { // tok.attrs <==> startTag or atomicTag or cursor
          // Ignore noscript tags. They are atomic, so we don't have to worry about children.
          if(!(/^noscript$/i).test(tok.tagName)) {
            var id = nextId++;

            // Actual: inject id attribute: replace '>' at end of start tag with id attribute + '>'
            actual.push(
              tok.text.replace(/(\/?>)/, ' '+BASEATTR+'id='+id+' $1')
            );

            // Don't proxy scripts: they have no bearing on DOM structure.
            if(tok.attrs.id !== "ps-script") {
              // Proxy: strip all attributes and inject proxyof attribute
              proxy.push(
                // ignore atomic tags (e.g., style): they have no "structural" effect
                tok.type === 'atomicTag' ? '' :
                  '<'+tok.tagName+' '+BASEATTR+'proxyof='+id+(tok.unary ? '/>' : '>')
              );
            }
          }

        } else {
          // Visit any other type of token
          // Actual: append.
          actual.push(tok.text);
          // Proxy: append endTags. Ignore everything else.
          proxy.push(tok.type === 'endTag' ? tok.text : '');
        }
      });

      return {
        tokens: tokens,
        raw: raw.join(''),
        actual: actual.join(''),
        proxy: proxy.join('')
      };
    };

    WriteStream.prototype.walkNodes = function() {
      var node, stack = [this.proxyRoot];

      // use shift/unshift so that children are walked in document order

      while((node = stack.shift()) != null) {

        var isElement = node.nodeType === 1;
        var isProxy = isElement && data(node, 'proxyof');

        // Ignore proxies
        if(!isProxy) {

          if(isElement) {
            // New actual element: register it and remove the the id attr.
            this.actuals[data(node, 'id')] = node;
            data(node, 'id', null);
          }

          // Is node's parent a proxy?
          var parentIsProxyOf = node.parentNode && data(node.parentNode, 'proxyof');
          if(parentIsProxyOf) {
            // Move node under actual parent.
            this.actuals[parentIsProxyOf].appendChild(node);
          }
        }
        // prepend childNodes to stack
        stack.unshift.apply(stack, toArray(node.childNodes));
      }
    };

    // ### Script tokens

    WriteStream.prototype.handleScriptToken = function(tok) {
      var remainder = this.parser.clear();

      if(remainder) {
        // Write remainder immediately behind this script.
        this.writeQueue.unshift(remainder);
      }

      tok.src = tok.attrs.src || tok.attrs.SRC;

      if(tok.src && this.scriptStack.length) {
        // Defer this script until scriptStack is empty.
        // Assumption 1: This script will not start executing until
        // scriptStack is empty.
        this.deferredRemote = tok;
      } else {
        this.onScriptStart(tok);
      }

      // Put the script node in the DOM.
      var _this = this;
      this.writeScriptToken(tok, function(e) {
        _this.onScriptDone(e, tok);
      });

    };

    WriteStream.prototype.onScriptStart = function(tok) {
      tok.outerWrites = this.writeQueue;
      this.writeQueue = [];
      this.scriptStack.unshift(tok);
    };

    WriteStream.prototype.onScriptDone = function(e, tok) {
      if(e) {
        // TODO: handle error
        throw this.options.error(e);
      }
      // Pop script and check nesting.
      if(tok !== this.scriptStack.shift()) {
        this.options.error({ message: "Improperly nested script execution" });
      };
      // Append outer writes to queue.
      [].push.apply(this.writeQueue, tok.outerWrites);
      delete tok.writeQueue;

      // Check for pending remote

      // Assumption 2: if remote_script1 writes remote_script2 then
      // the we notice remote_script1 finishes before remote_script2 starts.
      // I think this is equivalent to assumption 1
      if(!this.scriptStack.length) {
        if(this.deferredRemote) {
          this.onScriptStart(this.deferredRemote);
          this.deferredRemote = null;
        } else {
          this.processWriteQueue();
        }
      }
    };

    // Build a script and insert it into the DOM.
    // Done is called once script has executed.
    WriteStream.prototype.writeScriptToken = function(tok, done) {
      var el = this.buildScript(tok);

      if(tok.src) {
        // Fix for attribute "SRC" (capitalized). IE does not recognize it.
        el.src = tok.src;
        this.scriptLoadHandler(el, done);
      }

      try {
        this.insertScript(el);
        if(!tok.src) {
          done();
        }
      } catch(e) {
        done({ message: "Could not insert script: " + e.message });
      }

    };

    // Build a script element from an atomic script token.
    WriteStream.prototype.buildScript = function(tok) {
      var el = this.doc.createElement(tok.tagName);

      // Set attributes
      eachKey(tok.attrs, function(name, value) {
        el.setAttribute(name, value);
      });

      // Set content
      if(tok.content) {
        el.text = tok.content;
      }

      return el;
    };

    // Insert script into DOM where it would naturally be written.
    WriteStream.prototype.insertScript = function(el) {
      // Append a span to the stream. That span will act as a cursor
      // (i.e. insertion point) for the script.
      this.writeImpl('<span id="ps-script"/>');

      // Grab that span from the DOM.
      var cursor = this.doc.getElementById("ps-script");

      // Replace cursor with script.
      cursor.parentNode.replaceChild(el, cursor);
    };

    WriteStream.prototype.scriptLoadHandler = function(el, done) {
      function cleanup(e) {
        el = el.onload = el.onreadystatechange = el.onerror = null;
        done(e);
      }

      // Set handlers
      set(el, {
        onload: function() { cleanup(); },

        onreadystatechange: function() {
          if(/^(loaded|complete)$/.test( el.readyState )) {
            cleanup();
          }
        },
        onerror: function() {
          done({ message: 'remote script failed ' + task.src });
        }
      });
    };

    return WriteStream;

  }());

  // Public-facing interface and queuing
  var postscribe = (function() {
    var nextId = 0;

    var queue = [];

    var active = null;

    function nextStream() {
      var args;
      if(args = queue.shift()) {
        args.stream = runStream.apply(null, args);
      }
    }

    function runStream(el, html, options) {
      active = new WriteStream(el, options);

      // Identify this stream.
      active.id = nextId++;
      active.name = options.name || active.id;
      postscribe.streams[active.name] = active;

      // Override document.write.
      var doc = el.ownerDocument;

      var stash = { write: doc.write, writeln: doc.writeln };

      function write(str) {
        if(options.beforeWrite) {
          str = options.beforeWrite(str);
        }
        active.write(str);
        options.afterWrite(str);
      }

      set(doc, { write: write, writeln: function(str) { write(str + '\n'); } });

      // Write to the stream
      active.write(html, function streamDone() {
        // restore document.write
        set(doc, stash);

        options.done();
        active = null;
        nextStream();
      });

      return active;
    }

    function postscribe(el, html, options) {
      options = defaults(options, {
        beforeWrite: null,
        afterWrite: doNothing,
        done: doNothing,
        error: doNothing
      });

      el =
        // id selector
        (/^#/).test(el) ? globals.document.getElementById(el.substr(1)) :
        // jquery object. TODO: loop over all elements.
        el.jquery ? el[0] : el;

      var args = [el, html, options];

      el.postscribe = {
        cancel: function() {
          if(args.stream) {
            args.stream.abort();
          } else {
            args[1] = doNothing;
          }
        }
      };

      queue.push(args);
      if(!active) {
        nextStream();
      }

      return el.postscribe;
    }

    return set(postscribe, {
      // Streams by name.
      streams: {},
      // Queue of streams.
      queue: queue,
      // Expose internal classes.
      WriteStream: WriteStream
    });

  }());

  // export postscribe
  globals.postscribe = postscribe;

}());
<commit_msg>use stream::write and embed processWriteQueue<commit_after>//     postscribe.js 1.0.5
//     (c) Copyright 2012 to the present, Krux
//     postscribe is freely distributable under the MIT license.
//     For all details and documentation:
//     http://krux.github.com/postscribe

(function() {

  var globals = this;

  if(globals.postscribe) {
    return;
  }

  // Debug write tasks.
  var DEBUG = true;

  // Turn on to debug how each chunk affected the DOM.
  var DEBUG_CHUNK = false;

  // # Helper Functions

  var slice = Array.prototype.slice;

  // A function that intentionally does nothing.
  function doNothing() {}

  // Is this a function?
  function isFunction(x) {
    return "function" == typeof x;
  }

  // Loop over each item in an array-like value.
  function each(arr, fn, _this) {
    var i, len = (arr && arr.length) || 0;
    for(i = 0; i < len; i++) {
      fn.call(_this, arr[i], i);
    }
  }

  // Loop over each key/value pair in a hash.
  function eachKey(obj, fn, _this) {
    var key;
    for(key in obj) {
      if(obj.hasOwnProperty(key)) {
        fn.call(_this, key, obj[key]);
      }
    }
  }

  // Set properties on an object.
  function set(obj, props) {
    eachKey(props, function(key, value) {
      obj[key] = value;
    });
    return obj;
  }

  // Set default options where some option was not specified.
  function defaults(options, _defaults) {
    options = options || {};
    eachKey(_defaults, function(key, val) {
      if(options[key] == null) {
        options[key] = val;
      }
    });
    return options;
  }

  // Convert value (e.g., a NodeList) to an array.
  function toArray(obj) {
    try {
      return slice.call(obj);
    } catch(e) {
      var ret = [];
      each(obj, function(val) {
        ret.push(val);
      });
      return ret;
    }
  }

  // Test if token is a script tag.
  function isScript(tok) {
    return (/^script$/i).test(tok.tagName);
  }

  // # Class WriteStream

  // Stream static html to an element, where "static html" denotes "html without scripts".

  // This class maintains a *history of writes devoid of any attributes* or "proxy history".
  // Injecting the proxy history into a temporary div has no side-effects,
  // other than to create proxy elements for previously written elements.

  // Given the `staticHtml` of a new write, a `tempDiv`'s innerHTML is set to `proxy_history + staticHtml`.
  // The *structure* of `tempDiv`'s contents, (i.e., the placement of new nodes beside or inside of proxy elements),
  // reflects the DOM structure that would have resulted if all writes had been squashed into a single write.

  // For each descendent `node` of `tempDiv` whose parentNode is a *proxy*, `node` is appended to the corresponding *real* element within the DOM.

  // Proxy elements are mapped to *actual* elements in the DOM by injecting a data-id attribute into each start tag in `staticHtml`.
  var WriteStream = (function(){

    // Prefix for data attributes on DOM elements.
    var BASEATTR = 'data-ps-';

    // get / set data attributes
    function data(el, name, value) {
      var attr = BASEATTR + name;

      if(arguments.length === 2) {
        // Get
        var val = el.getAttribute(attr);

        // IE 8 returns a number if it's a number
        return val == null ? val : String(val);

      } else if( value != null && value !== '') {
        // Set
        el.setAttribute(attr, value);

      } else {
        // Remove
        el.removeAttribute(attr);
      }
    }

    function WriteStream(root, options) {
      var doc = root.ownerDocument;

      set(this, {
        root: root,

        options: options,

        doc: doc,

        parser: globals.htmlParser('', { autoFix: true }),

        // Actual elements by id.
        actuals: [root],

        // Embodies the "structure" of what's been written so far, devoid of attributes.
        proxyHistory: '',

        // Create a proxy of the root element.
        proxyRoot: doc.createElement(root.nodeName),

        scriptStack: [],

        writeQueue: []
      });

      data(this.proxyRoot, 'proxyof', 0);

    }

    WriteStream.prototype.write = function() {
      [].push.apply(this.writeQueue, arguments);
      // Process writes
      // When new script gets pushed or pending this will stop
      // because new writeQueue gets pushed
      while(!this.deferredRemote &&
            this.writeQueue.length) {

        this.writeImpl(this.writeQueue.shift());
      }
    };

    WriteStream.prototype.writeImpl = function(arg) {
      if(isFunction(arg)) {
        // Callback
        return arg();
      }

      this.parser.append(arg);

      var tok, tokens = [];

      // stop if we see a script token
      while((tok = this.parser.readToken()) && !isScript(tok)) {
        tokens.push(tok);
      }

      this.writeStaticTokens(tokens);

      if(tok) {
        this.handleScriptToken(tok);
      }
    };

    // ## Contiguous non-script tokens (a chunk)
    WriteStream.prototype.writeStaticTokens = function(tokens) {

      var chunk = this.buildChunk(tokens);

      if(!chunk.actual) {
        // e.g., no tokens, or a noscript that got ignored
        return;
      }
      chunk.html = this.proxyHistory + chunk.actual;
      this.proxyHistory += chunk.proxy;

      this.proxyRoot.innerHTML = chunk.html;

      if(DEBUG_CHUNK) {
        chunk.proxyInnerHTML = this.proxyRoot.innerHTML;
      }

      this.walkNodes();

      if(DEBUG_CHUNK) {
        chunk.actualInnerHTML = this.root.innerHTML; //root
      }

      return chunk;
    };

    WriteStream.prototype.buildChunk = function (tokens) {
      var nextId = this.actuals.length,

          // The raw html of this chunk.
          raw = [],

          // The html to create the nodes in the tokens (with id's injected).
          actual = [],

          // Html that can later be used to proxy the nodes in the tokens.
          proxy = [];

      each(tokens, function(tok) {

        raw.push(tok.text);

        if(tok.attrs) { // tok.attrs <==> startTag or atomicTag or cursor
          // Ignore noscript tags. They are atomic, so we don't have to worry about children.
          if(!(/^noscript$/i).test(tok.tagName)) {
            var id = nextId++;

            // Actual: inject id attribute: replace '>' at end of start tag with id attribute + '>'
            actual.push(
              tok.text.replace(/(\/?>)/, ' '+BASEATTR+'id='+id+' $1')
            );

            // Don't proxy scripts: they have no bearing on DOM structure.
            if(tok.attrs.id !== "ps-script") {
              // Proxy: strip all attributes and inject proxyof attribute
              proxy.push(
                // ignore atomic tags (e.g., style): they have no "structural" effect
                tok.type === 'atomicTag' ? '' :
                  '<'+tok.tagName+' '+BASEATTR+'proxyof='+id+(tok.unary ? '/>' : '>')
              );
            }
          }

        } else {
          // Visit any other type of token
          // Actual: append.
          actual.push(tok.text);
          // Proxy: append endTags. Ignore everything else.
          proxy.push(tok.type === 'endTag' ? tok.text : '');
        }
      });

      return {
        tokens: tokens,
        raw: raw.join(''),
        actual: actual.join(''),
        proxy: proxy.join('')
      };
    };

    WriteStream.prototype.walkNodes = function() {
      var node, stack = [this.proxyRoot];

      // use shift/unshift so that children are walked in document order

      while((node = stack.shift()) != null) {

        var isElement = node.nodeType === 1;
        var isProxy = isElement && data(node, 'proxyof');

        // Ignore proxies
        if(!isProxy) {

          if(isElement) {
            // New actual element: register it and remove the the id attr.
            this.actuals[data(node, 'id')] = node;
            data(node, 'id', null);
          }

          // Is node's parent a proxy?
          var parentIsProxyOf = node.parentNode && data(node.parentNode, 'proxyof');
          if(parentIsProxyOf) {
            // Move node under actual parent.
            this.actuals[parentIsProxyOf].appendChild(node);
          }
        }
        // prepend childNodes to stack
        stack.unshift.apply(stack, toArray(node.childNodes));
      }
    };

    // ### Script tokens

    WriteStream.prototype.handleScriptToken = function(tok) {
      var remainder = this.parser.clear();

      if(remainder) {
        // Write remainder immediately behind this script.
        this.writeQueue.unshift(remainder);
      }

      tok.src = tok.attrs.src || tok.attrs.SRC;

      // TODO: test where remote script is in root
      if(tok.src && this.scriptStack.length) {
        // Defer this script until scriptStack is empty.
        // Assumption 1: This script will not start executing until
        // scriptStack is empty.
        this.deferredRemote = tok;
      } else {
        this.onScriptStart(tok);
      }

      // Put the script node in the DOM.
      var _this = this;
      this.writeScriptToken(tok, function(e) {
        _this.onScriptDone(e, tok);
      });

    };

    WriteStream.prototype.onScriptStart = function(tok) {
      tok.outerWrites = this.writeQueue;
      this.writeQueue = [];
      this.scriptStack.unshift(tok);
    };

    WriteStream.prototype.onScriptDone = function(e, tok) {
      if(e) {
        this.options.error(e);
      }
      // Pop script and check nesting.
      if(tok !== this.scriptStack.shift()) {
        this.options.error({ message: "Improperly nested script execution" });
      };
      // Append outer writes to queue and process them.
      this.write.apply(this, tok.outerWrites);

      // Check for pending remote

      // Assumption 2: if remote_script1 writes remote_script2 then
      // the we notice remote_script1 finishes before remote_script2 starts.
      // I think this is equivalent to assumption 1
      if(!this.scriptStack.length && this.deferredRemote) {
        this.onScriptStart(this.deferredRemote);
        this.deferredRemote = null;
      }
    };

    // Build a script and insert it into the DOM.
    // Done is called once script has executed.
    WriteStream.prototype.writeScriptToken = function(tok, done) {
      var el = this.buildScript(tok);

      if(tok.src) {
        // Fix for attribute "SRC" (capitalized). IE does not recognize it.
        el.src = tok.src;
        this.scriptLoadHandler(el, done);
      }

      try {
        this.insertScript(el);
        if(!tok.src) {
          done();
        }
      } catch(e) {
        done({ message: "Could not insert script: " + e.message });
      }

    };

    // Build a script element from an atomic script token.
    WriteStream.prototype.buildScript = function(tok) {
      var el = this.doc.createElement(tok.tagName);

      // Set attributes
      eachKey(tok.attrs, function(name, value) {
        el.setAttribute(name, value);
      });

      // Set content
      if(tok.content) {
        el.text = tok.content;
      }

      return el;
    };

    // Insert script into DOM where it would naturally be written.
    WriteStream.prototype.insertScript = function(el) {
      // Append a span to the stream. That span will act as a cursor
      // (i.e. insertion point) for the script.
      this.writeImpl('<span id="ps-script"/>');

      // Grab that span from the DOM.
      var cursor = this.doc.getElementById("ps-script");

      // Replace cursor with script.
      cursor.parentNode.replaceChild(el, cursor);
    };

    WriteStream.prototype.scriptLoadHandler = function(el, done) {
      function cleanup(e) {
        el = el.onload = el.onreadystatechange = el.onerror = null;
        done(e);
      }

      // Set handlers
      set(el, {
        onload: function() { cleanup(); },

        onreadystatechange: function() {
          if(/^(loaded|complete)$/.test( el.readyState )) {
            cleanup();
          }
        },
        onerror: function() {
          done({ message: 'remote script failed ' + task.src });
        }
      });
    };

    return WriteStream;

  }());

  // Public-facing interface and queuing
  var postscribe = (function() {
    var nextId = 0;

    var queue = [];

    var active = null;

    function nextStream() {
      var args;
      if(args = queue.shift()) {
        args.stream = runStream.apply(null, args);
      }
    }

    function runStream(el, html, options) {
      active = new WriteStream(el, options);

      // Identify this stream.
      active.id = nextId++;
      active.name = options.name || active.id;
      postscribe.streams[active.name] = active;

      // Override document.write.
      var doc = el.ownerDocument;

      var stash = { write: doc.write, writeln: doc.writeln };

      function write(str) {
        if(options.beforeWrite) {
          str = options.beforeWrite(str);
        }
        active.write(str);
        options.afterWrite(str);
      }

      set(doc, { write: write, writeln: function(str) { write(str + '\n'); } });

      // Write to the stream
      active.write(html, function streamDone() {
        // restore document.write
        set(doc, stash);

        options.done();
        active = null;
        nextStream();
      });

      return active;
    }

    function postscribe(el, html, options) {
      options = defaults(options, {
        beforeWrite: null,
        afterWrite: doNothing,
        done: doNothing,
        error: doNothing
      });

      el =
        // id selector
        (/^#/).test(el) ? globals.document.getElementById(el.substr(1)) :
        // jquery object. TODO: loop over all elements.
        el.jquery ? el[0] : el;

      var args = [el, html, options];

      el.postscribe = {
        cancel: function() {
          if(args.stream) {
            args.stream.abort();
          } else {
            args[1] = doNothing;
          }
        }
      };

      queue.push(args);
      if(!active) {
        nextStream();
      }

      return el.postscribe;
    }

    return set(postscribe, {
      // Streams by name.
      streams: {},
      // Queue of streams.
      queue: queue,
      // Expose internal classes.
      WriteStream: WriteStream
    });

  }());

  // export postscribe
  globals.postscribe = postscribe;

}());
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
** Contact: http://www.qt.io/licensing
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

var Cpp = require("cpp.js");
var Environment = require("qbs.Environment");
var File = require("qbs.File");
var FileInfo = require("qbs.FileInfo");
var ModUtils = require("qbs.ModUtils");
var Process = require("qbs.Process");
var TemporaryDir = require("qbs.TemporaryDir");
var TextFile = require("qbs.TextFile");
var Utilities = require("qbs.Utilities");
var WindowsUtils = require("qbs.WindowsUtils");

function guessArchitecture(macros)
{
    if (macros["__ICCARM__"] === "1")
        return "arm";
}

function guessEndianness(macros)
{
    if (macros["__LITTLE_ENDIAN__"] === "1")
        return "little";
    return "big"
}

function dumpMacros(compilerFilePath, qbs, nullDevice) {
    var tempDir = new TemporaryDir();
    var inFilePath = FileInfo.fromNativeSeparators(tempDir.path() + "/empty-source.c");
    var inFile = new TextFile(inFilePath, TextFile.WriteOnly);
    var outFilePath = FileInfo.fromNativeSeparators(tempDir.path() + "/iar-macros.predef");
    var p = new Process();

    p.exec(compilerFilePath,
           [ inFilePath, "--predef_macros", outFilePath ],
           true);
    var outFile = new TextFile(outFilePath, TextFile.ReadOnly);
    var map = {};
    outFile.readAll().trim().split(/\r?\n/g).map(function (line) {
            var parts = line.split(" ", 3);
            map[parts[1]] = parts[2];
        });
    return map;
}

function collectLibraryDependencies(product) {
    var seen = {};
    var result = [];

    function addFilePath(filePath) {
        result.push({ filePath: filePath });
    }

    function addArtifactFilePaths(dep, artifacts) {
        if (!artifacts)
            return;
        var artifactFilePaths = artifacts.map(function(a) { return a.filePath; });
        artifactFilePaths.forEach(addFilePath);
    }

    function addExternalStaticLibs(obj) {
        if (!obj.cpp)
            return;
        function ensureArray(a) {
            return Array.isArray(a) ? a : [];
        }
        function sanitizedModuleListProperty(obj, moduleName, propertyName) {
            return ensureArray(ModUtils.sanitizedModuleProperty(obj, moduleName, propertyName));
        }
        var externalLibs = [].concat(
                    sanitizedModuleListProperty(obj, "cpp", "staticLibraries"));
        var staticLibrarySuffix = obj.moduleProperty("cpp", "staticLibrarySuffix");
        externalLibs.forEach(function(staticLibraryName) {
            if (!staticLibraryName.endsWith(staticLibrarySuffix))
                staticLibraryName += staticLibrarySuffix;
            addFilePath(staticLibraryName);
        });
    }

    function traverse(dep) {
        if (seen.hasOwnProperty(dep.name))
            return;
        seen[dep.name] = true;

        if (dep.parameters.cpp && dep.parameters.cpp.link === false)
            return;

        var staticLibraryArtifacts = dep.artifacts["staticlibrary"];
        if (staticLibraryArtifacts) {
            dep.dependencies.forEach(traverse);
            addArtifactFilePaths(dep, staticLibraryArtifacts);
            addExternalStaticLibs(dep);
        }
    }

    product.dependencies.forEach(traverse);
    addExternalStaticLibs(product);
    return result;
}

function compilerFlags(project, product, input, output, explicitlyDependsOn) {
    // Determine which C-language we"re compiling.
    var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(output.fileTags));

    var args = [];
    args.push(input.filePath);

    switch (input.cpp.optimization) {
    case "small":
        args.push("-Ohs");
        break;
    case "fast":
        args.push("-Ohz");
        break;
    case "none":
        args.push("-On");
        break;
    }

    if (input.cpp.debugInformation)
        args.push("--debug");

    var warnings = input.cpp.warningLevel;
    if (warnings === "none") {
        args.push("--no_warnings");
    } else if (warnings === "all") {
        args.push("--warnings_affect_exit_code");
        args.push("--deprecated_feature_warnings="
            +"+attribute_syntax,"
            +"+preprocessor_extensions,"
            +"+segment_pragmas");
        if (tag === "cpp")
            args.push("--warn_about_c_style_casts");
    }
    if (input.cpp.treatWarningsAsErrors) {
        args.push("--warnings_are_errors");
    }

    // Choose byte order.
    var endianness = input.cpp.endianness;
    if (endianness)
        args.push("--endian=" + endianness);

    if (tag === "c") {
        // Language version.
        if (input.cpp.cLanguageVersion === "c89")
            args.push("--c89");
    } else if (tag === "cpp") {
        args.push("--c++");
        if (!input.cpp.enableExceptions)
            args.push("--no_exceptions");
        if (!input.cpp.enableRtti)
            args.push("--no_rtti");
    }

    var allDefines = [];
    var platformDefines = input.cpp.platformDefines;
    if (platformDefines)
        allDefines = allDefines.uniqueConcat(platformDefines);
    var defines = input.cpp.defines;
    if (defines)
        allDefines = allDefines.uniqueConcat(defines);
    args = args.concat(allDefines.map(function(define) { return "-D" + define }));

    var allIncludePaths = [];
    var includePaths = input.cpp.includePaths;
    if (includePaths)
        allIncludePaths = allIncludePaths.uniqueConcat(includePaths);
    var systemIncludePaths = input.cpp.systemIncludePaths;
    if (systemIncludePaths)
        allIncludePaths = allIncludePaths.uniqueConcat(systemIncludePaths);
    var compilerIncludePaths = input.cpp.compilerIncludePaths;
    if (compilerIncludePaths)
        allIncludePaths = allIncludePaths.uniqueConcat(compilerIncludePaths);
    args = args.concat(allIncludePaths.map(function(include) { return "-I" + include }));

    args.push("-o", output.filePath);

    args.push("--silent"); // Silent operation.

    args = args.concat(ModUtils.moduleProperty(input, "platformFlags"),
                       ModUtils.moduleProperty(input, "flags"),
                       ModUtils.moduleProperty(input, "platformFlags", tag),
                       ModUtils.moduleProperty(input, "flags", tag),
                       ModUtils.moduleProperty(input, "driverFlags", tag));
    return args;
}

function assemblerFlags(project, product, input, output, explicitlyDependsOn) {
    // Determine which C-language we"re compiling
    var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(output.fileTags));

    var args = [];
    args.push(input.filePath);

    if (input.cpp.debugInformation)
        args.push("-r");

    var warnings = input.cpp.warningLevel;
    if (warnings === "none")
        args.push("-w-");
    else
        args.push("-w+");

    args.push("-o", output.filePath);

    args.push("-S"); // Silent operation.

    args = args.concat(ModUtils.moduleProperty(input, "platformFlags", tag),
                       ModUtils.moduleProperty(input, "flags", tag),
                       ModUtils.moduleProperty(input, "driverFlags", tag));
    return args;
}

function linkerFlags(project, product, input, outputs) {
    var i;
    var args = [];

    if (inputs.obj)
        args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));

    args.push("-o", outputs.application[0].filePath);

    if (product.cpp.generateMapFile)
        args.push("--map", outputs.map_file[0].filePath);

    var allLibraryPaths = [];
    var libraryPaths = product.cpp.libraryPaths;
    if (libraryPaths)
        allLibraryPaths = allLibraryPaths.uniqueConcat(libraryPaths);
    var distributionLibraryPaths = product.cpp.distributionLibraryPaths;
    if (distributionLibraryPaths)
        allLibraryPaths = allLibraryPaths.uniqueConcat(distributionLibraryPaths);
    args = args.concat(allLibraryPaths.map(function(path) { return '-L' + path }));

    var libraryDependencies = collectLibraryDependencies(product);
    if (libraryDependencies)
        args = args.concat(libraryDependencies.map(function(dep) { return dep.filePath }));

    var linkerScripts = inputs.linkerscript
            ? inputs.linkerscript.map(function(a) { return a.filePath; }) : [];
    for (i in linkerScripts)
        args.push("--config", linkerScripts[i]);

    if (product.cpp.entryPoint)
        args.push("--entry", product.cpp.entryPoint);

    args.push("--silent"); // Silent operation.

    args = args.concat(ModUtils.moduleProperty(product, "driverLinkerFlags"));
    return args;
}

function archiverFlags(project, product, input, outputs) {
    var args = [];

    if (inputs.obj)
        args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));

    args.push("--create");
    args.push("-o", outputs.staticlibrary[0].filePath);

    return args;
}

function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
    var args = compilerFlags(project, product, input, output, explicitlyDependsOn);
    var compilerPath = input.cpp.compilerPath;
    var cmd = new Command(compilerPath, args)
    cmd.description = "compiling " + input.fileName;
    cmd.highlight = "compiler";
    return [cmd];
}

function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
    var args = assemblerFlags(project, product, input, output, explicitlyDependsOn);
    var assemblerPath = input.cpp.assemblerPath;
    var cmd = new Command(assemblerPath, args)
    cmd.description = "assembling " + input.fileName;
    cmd.highlight = "compiler";
    return [cmd];
}

function prepareLinker(project, product, inputs, outputs, input, output) {
    var primaryOutput = outputs.application[0];
    var args = linkerFlags(project, product, input, outputs);
    var linkerPath = product.cpp.linkerPath;
    var cmd = new Command(linkerPath, args)
    cmd.description = "linking " + primaryOutput.fileName;
    cmd.highlight = "linker";
    return [cmd];
}

function prepareArchiver(project, product, inputs, outputs, input, output) {
    var args = archiverFlags(project, product, input, outputs);
    var archiverPath = product.cpp.archiverPath;
    var cmd = new Command(archiverPath, args)
    cmd.description = "linking " + output.fileName;
    cmd.highlight = "linker";
    cmd.stdoutFilterFunction = function(output) {
        return "";
    };
    return [cmd];
}
<commit_msg>bare-metal: Remove '--warnings_affect_exit_code' option from IAR compiler<commit_after>/****************************************************************************
**
** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
** Contact: http://www.qt.io/licensing
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

var Cpp = require("cpp.js");
var Environment = require("qbs.Environment");
var File = require("qbs.File");
var FileInfo = require("qbs.FileInfo");
var ModUtils = require("qbs.ModUtils");
var Process = require("qbs.Process");
var TemporaryDir = require("qbs.TemporaryDir");
var TextFile = require("qbs.TextFile");
var Utilities = require("qbs.Utilities");
var WindowsUtils = require("qbs.WindowsUtils");

function guessArchitecture(macros)
{
    if (macros["__ICCARM__"] === "1")
        return "arm";
}

function guessEndianness(macros)
{
    if (macros["__LITTLE_ENDIAN__"] === "1")
        return "little";
    return "big"
}

function dumpMacros(compilerFilePath, qbs, nullDevice) {
    var tempDir = new TemporaryDir();
    var inFilePath = FileInfo.fromNativeSeparators(tempDir.path() + "/empty-source.c");
    var inFile = new TextFile(inFilePath, TextFile.WriteOnly);
    var outFilePath = FileInfo.fromNativeSeparators(tempDir.path() + "/iar-macros.predef");
    var p = new Process();

    p.exec(compilerFilePath,
           [ inFilePath, "--predef_macros", outFilePath ],
           true);
    var outFile = new TextFile(outFilePath, TextFile.ReadOnly);
    var map = {};
    outFile.readAll().trim().split(/\r?\n/g).map(function (line) {
            var parts = line.split(" ", 3);
            map[parts[1]] = parts[2];
        });
    return map;
}

function collectLibraryDependencies(product) {
    var seen = {};
    var result = [];

    function addFilePath(filePath) {
        result.push({ filePath: filePath });
    }

    function addArtifactFilePaths(dep, artifacts) {
        if (!artifacts)
            return;
        var artifactFilePaths = artifacts.map(function(a) { return a.filePath; });
        artifactFilePaths.forEach(addFilePath);
    }

    function addExternalStaticLibs(obj) {
        if (!obj.cpp)
            return;
        function ensureArray(a) {
            return Array.isArray(a) ? a : [];
        }
        function sanitizedModuleListProperty(obj, moduleName, propertyName) {
            return ensureArray(ModUtils.sanitizedModuleProperty(obj, moduleName, propertyName));
        }
        var externalLibs = [].concat(
                    sanitizedModuleListProperty(obj, "cpp", "staticLibraries"));
        var staticLibrarySuffix = obj.moduleProperty("cpp", "staticLibrarySuffix");
        externalLibs.forEach(function(staticLibraryName) {
            if (!staticLibraryName.endsWith(staticLibrarySuffix))
                staticLibraryName += staticLibrarySuffix;
            addFilePath(staticLibraryName);
        });
    }

    function traverse(dep) {
        if (seen.hasOwnProperty(dep.name))
            return;
        seen[dep.name] = true;

        if (dep.parameters.cpp && dep.parameters.cpp.link === false)
            return;

        var staticLibraryArtifacts = dep.artifacts["staticlibrary"];
        if (staticLibraryArtifacts) {
            dep.dependencies.forEach(traverse);
            addArtifactFilePaths(dep, staticLibraryArtifacts);
            addExternalStaticLibs(dep);
        }
    }

    product.dependencies.forEach(traverse);
    addExternalStaticLibs(product);
    return result;
}

function compilerFlags(project, product, input, output, explicitlyDependsOn) {
    // Determine which C-language we"re compiling.
    var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(output.fileTags));

    var args = [];
    args.push(input.filePath);

    switch (input.cpp.optimization) {
    case "small":
        args.push("-Ohs");
        break;
    case "fast":
        args.push("-Ohz");
        break;
    case "none":
        args.push("-On");
        break;
    }

    if (input.cpp.debugInformation)
        args.push("--debug");

    var warnings = input.cpp.warningLevel;
    if (warnings === "none") {
        args.push("--no_warnings");
    } else if (warnings === "all") {
        args.push("--deprecated_feature_warnings="
            +"+attribute_syntax,"
            +"+preprocessor_extensions,"
            +"+segment_pragmas");
        if (tag === "cpp")
            args.push("--warn_about_c_style_casts");
    }
    if (input.cpp.treatWarningsAsErrors) {
        args.push("--warnings_are_errors");
    }

    // Choose byte order.
    var endianness = input.cpp.endianness;
    if (endianness)
        args.push("--endian=" + endianness);

    if (tag === "c") {
        // Language version.
        if (input.cpp.cLanguageVersion === "c89")
            args.push("--c89");
    } else if (tag === "cpp") {
        args.push("--c++");
        if (!input.cpp.enableExceptions)
            args.push("--no_exceptions");
        if (!input.cpp.enableRtti)
            args.push("--no_rtti");
    }

    var allDefines = [];
    var platformDefines = input.cpp.platformDefines;
    if (platformDefines)
        allDefines = allDefines.uniqueConcat(platformDefines);
    var defines = input.cpp.defines;
    if (defines)
        allDefines = allDefines.uniqueConcat(defines);
    args = args.concat(allDefines.map(function(define) { return "-D" + define }));

    var allIncludePaths = [];
    var includePaths = input.cpp.includePaths;
    if (includePaths)
        allIncludePaths = allIncludePaths.uniqueConcat(includePaths);
    var systemIncludePaths = input.cpp.systemIncludePaths;
    if (systemIncludePaths)
        allIncludePaths = allIncludePaths.uniqueConcat(systemIncludePaths);
    var compilerIncludePaths = input.cpp.compilerIncludePaths;
    if (compilerIncludePaths)
        allIncludePaths = allIncludePaths.uniqueConcat(compilerIncludePaths);
    args = args.concat(allIncludePaths.map(function(include) { return "-I" + include }));

    args.push("-o", output.filePath);

    args.push("--silent"); // Silent operation.

    args = args.concat(ModUtils.moduleProperty(input, "platformFlags"),
                       ModUtils.moduleProperty(input, "flags"),
                       ModUtils.moduleProperty(input, "platformFlags", tag),
                       ModUtils.moduleProperty(input, "flags", tag),
                       ModUtils.moduleProperty(input, "driverFlags", tag));
    return args;
}

function assemblerFlags(project, product, input, output, explicitlyDependsOn) {
    // Determine which C-language we"re compiling
    var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(output.fileTags));

    var args = [];
    args.push(input.filePath);

    if (input.cpp.debugInformation)
        args.push("-r");

    var warnings = input.cpp.warningLevel;
    if (warnings === "none")
        args.push("-w-");
    else
        args.push("-w+");

    args.push("-o", output.filePath);

    args.push("-S"); // Silent operation.

    args = args.concat(ModUtils.moduleProperty(input, "platformFlags", tag),
                       ModUtils.moduleProperty(input, "flags", tag),
                       ModUtils.moduleProperty(input, "driverFlags", tag));
    return args;
}

function linkerFlags(project, product, input, outputs) {
    var i;
    var args = [];

    if (inputs.obj)
        args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));

    args.push("-o", outputs.application[0].filePath);

    if (product.cpp.generateMapFile)
        args.push("--map", outputs.map_file[0].filePath);

    var allLibraryPaths = [];
    var libraryPaths = product.cpp.libraryPaths;
    if (libraryPaths)
        allLibraryPaths = allLibraryPaths.uniqueConcat(libraryPaths);
    var distributionLibraryPaths = product.cpp.distributionLibraryPaths;
    if (distributionLibraryPaths)
        allLibraryPaths = allLibraryPaths.uniqueConcat(distributionLibraryPaths);
    args = args.concat(allLibraryPaths.map(function(path) { return '-L' + path }));

    var libraryDependencies = collectLibraryDependencies(product);
    if (libraryDependencies)
        args = args.concat(libraryDependencies.map(function(dep) { return dep.filePath }));

    var linkerScripts = inputs.linkerscript
            ? inputs.linkerscript.map(function(a) { return a.filePath; }) : [];
    for (i in linkerScripts)
        args.push("--config", linkerScripts[i]);

    if (product.cpp.entryPoint)
        args.push("--entry", product.cpp.entryPoint);

    args.push("--silent"); // Silent operation.

    args = args.concat(ModUtils.moduleProperty(product, "driverLinkerFlags"));
    return args;
}

function archiverFlags(project, product, input, outputs) {
    var args = [];

    if (inputs.obj)
        args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));

    args.push("--create");
    args.push("-o", outputs.staticlibrary[0].filePath);

    return args;
}

function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
    var args = compilerFlags(project, product, input, output, explicitlyDependsOn);
    var compilerPath = input.cpp.compilerPath;
    var cmd = new Command(compilerPath, args)
    cmd.description = "compiling " + input.fileName;
    cmd.highlight = "compiler";
    return [cmd];
}

function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
    var args = assemblerFlags(project, product, input, output, explicitlyDependsOn);
    var assemblerPath = input.cpp.assemblerPath;
    var cmd = new Command(assemblerPath, args)
    cmd.description = "assembling " + input.fileName;
    cmd.highlight = "compiler";
    return [cmd];
}

function prepareLinker(project, product, inputs, outputs, input, output) {
    var primaryOutput = outputs.application[0];
    var args = linkerFlags(project, product, input, outputs);
    var linkerPath = product.cpp.linkerPath;
    var cmd = new Command(linkerPath, args)
    cmd.description = "linking " + primaryOutput.fileName;
    cmd.highlight = "linker";
    return [cmd];
}

function prepareArchiver(project, product, inputs, outputs, input, output) {
    var args = archiverFlags(project, product, input, outputs);
    var archiverPath = product.cpp.archiverPath;
    var cmd = new Command(archiverPath, args)
    cmd.description = "linking " + output.fileName;
    cmd.highlight = "linker";
    cmd.stdoutFilterFunction = function(output) {
        return "";
    };
    return [cmd];
}
<|endoftext|>


<commit_before>(function(env) {
    "use strict";
    env.ddg_spice_github = function(api_result) {

        if (!api_result || !api_result.meta.status === 200) {
          return Spice.failed('github');
        }

        var script = $('[src*="/js/spice/github/"]')[0],
                    source = $(script).attr("src"),
                    query = source.match(/github\/([^\/]+)/)[1];

        if (/language:".*?"/.test(unescape(query))) {
            var itemType = "Git Repos (" + unescape(query).match(/language:"(.*?)"/)[1] + ")";
        } else {
            var itemType = "Git Repos";
        }

        var results = api_result.data.items;

        if (!results) {
            return Spice.failed('github');
        }

        // TODO: temp size limit - relevancy block should handle this later
        if (results.length > 30)
            results = results.splice(0,30);

        DDG.require("moment.js", function() {
            Spice.add({
                id: "github",
                name: "Software",
                data: results,
                meta: {
                    itemType: itemType,
                    searchTerm: unescape(query),
                    sourceUrl: 'https://www.github.com/search?q=' +  encodeURIComponent(query),
                    sourceName: 'GitHub'
                },
                templates: {
                        group: 'text',
                        detail: false,
                        item_detail: false,
                        options: {
                            footer: Spice.github.footer
                        },
                        variants: {
                            tile: 'basic4'
                        }
                    },
                normalize: function(item) {
                    return {
                        title: item.name,
                        subtitle: item.owner.login + "/" + item.name,
                        url: item.html_url,
                        pushed_at: moment(item.pushed_at).fromNow()
                    };
                },
                relevancy: {
                    primary: [
                        { key: 'description', match: /.+/, strict: false } // Reject things without a description.
                    ]
                },
                sort_fields: {
                    watchers: function(a, b) {
                        var x = a.watchers;
                        var y = b.watchers;
                        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
                    }
                },
                sort_default: 'watchers'
            });
        });
    }
}(this));
<commit_msg>Github: Ignore items (repositories) with size of 0<commit_after>(function(env) {
    "use strict";
    env.ddg_spice_github = function(api_result) {

        if (!api_result || !api_result.meta.status === 200) {
          return Spice.failed('github');
        }

        var script = $('[src*="/js/spice/github/"]')[0],
                    source = $(script).attr("src"),
                    query = source.match(/github\/([^\/]+)/)[1];

        if (/language:".*?"/.test(unescape(query))) {
            var itemType = "Git Repos (" + unescape(query).match(/language:"(.*?)"/)[1] + ")";
        } else {
            var itemType = "Git Repos";
        }

        var results = api_result.data.items;

        if (!results) {
            return Spice.failed('github');
        }

        // TODO: temp size limit - relevancy block should handle this later
        if (results.length > 30)
            results = results.splice(0,30);

        DDG.require("moment.js", function() {
            Spice.add({
                id: "github",
                name: "Software",
                data: results,
                meta: {
                    itemType: itemType,
                    searchTerm: unescape(query),
                    sourceUrl: 'https://www.github.com/search?q=' +  encodeURIComponent(query),
                    sourceName: 'GitHub'
                },
                templates: {
                        group: 'text',
                        detail: false,
                        item_detail: false,
                        options: {
                            footer: Spice.github.footer
                        },
                        variants: {
                            tile: 'basic4'
                        }
                    },
                normalize: function(item) {
                    if (item.size === 0) {
                        return;
                    }
                    return {
                        title: item.name,
                        subtitle: item.owner.login + "/" + item.name,
                        url: item.html_url,
                        pushed_at: moment(item.pushed_at).fromNow()
                    };
                },
                relevancy: {
                    primary: [
                        { key: 'description', match: /.+/, strict: false } // Reject things without a description.
                    ]
                },
                sort_fields: {
                    watchers: function(a, b) {
                        var x = a.watchers;
                        var y = b.watchers;
                        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
                    }
                },
                sort_default: 'watchers'
            });
        });
    }
}(this));
<|endoftext|>


<commit_before>// ROUTES

var routes = [

  // staff routes
  [ 'admin'                 , '/admin'                  ],
  [ 'admin_dashboard'       , '/admin/dashboard'        ],
  [ 'admin_highlights'      , '/admin/highlights'       ],
  [ 'admin_hackers'         , '/admin/hackers'          ],
  [ 'admin_deals'           , '/admin/deals'            ],
  [ 'admin_places'          , '/admin/places'           ],
  [ 'admin_growth'          , '/admin/growth'           ],
  [ 'admin_emailTemplates'  , '/admin/emailTemplates'   ],

  // normal routes
  [ 'frontpage'    , '/'                     ],
  [ 'about'        , '/about'                ],
  [ 'agenda'       , '/agenda'               ],
  [ 'books'        , '/books'                ],
  [ 'hackers'      , '/hackers'              ],
  [ 'highlights'   , '/highlights'           ],
  [ 'invitations'  , '/invitations'          ],
  [ 'map'          , '/map'                  ],
  [ 'deals'        , '/deals'                ],

  // special routes (which will redirect)
  [ 'logout'       , '/logout'               ],
  [ 'verifyEmail'  , '/verify-email/:token'  ],
  [ 'growth_github', '/gh/:phrase'           ], // e.g. /gh/FDMwdYYXxMY7dLcD4
  [ 'invite'       , '/+/:inviteBitHash/'    ], // e.g. /+/---_--

  // bare routes (must defined as last in this list)
  [ 'hacker'       , '/:bitHash'             ], // e.g. /--_-_-

];

// the routes that DON'T require login
var noLoginRequired = [
  'docs',
  'about',
  'frontpage',
  'invite',
  'verifyEmail',
];

/*
  special entry routes
  includes refer information
*/

InviteController = DefaultController.extend({
  template: 'frontpage',
  onBeforeAction: function() {
    // set some session variables and then redirects to the frontpage
    // the frontpage is now showing a picture of the user that has invited this visitor;
    Session.set('inviteBitHash', this.params.inviteBitHash);
    this.redirect('frontpage');
    this.next();
  }
});

GrowthGithubController = DefaultController.extend({
  template: 'frontpage',
  onBeforeAction: function() {
    Session.set('growthType', 'github');
    Session.set('growthPhrase', this.params.phrase);
    this.redirect('frontpage');
    this.next();
  }
});

LogoutController = DefaultController.extend({
  template: 'loading',
  onBeforeAction: function() {
    if (Meteor.userId()) {
      GAnalytics.event("LoginService", "logout");
      Meteor.logout();
      this.render('loading');
    } else {
      this.redirect('frontpage');
    }
  }
});

/* hooks */

// set meta data based on current city
var setMetaData = function() {
  var city = City.lookup(Session.get('currentCity'));
  var title, description;

  // modify meta data
  title = "hckrs.io";
  if (city) description = "Hackers community of " + city.name;
  else      description = "Hackers community in your city";

  // actually set data
  setTitle(title);
  setMeta("title", title);
  setMeta("description", description);
  setMetaProperties({
    "og:title": description,
    "og:site_name": title,
    "og:url": city ? Url.replaceCity(city.key, Meteor.absoluteUrl()) : Meteor.absoluteUrl(),
    "og:image": Meteor.absoluteUrl("img/favicons/apple-touch-icon-precomposed.png"),
    "og:description": description
  });

  this.next();
}

var loginRequired = function() {
  if (!Meteor.userId()) {
    if (!Session.get('redirectUrl'))
      Session.set('redirectUrl', location.pathname + location.search + location.hash);
    this.redirect('frontpage');
  }
  this.next();
}

// make sure that user is allowed to enter the site
var allowedAccess = function() {
  var user = Users.myProps(['isAccessDenied','globalId','bitHash']) || {};
  if(user.isAccessDenied) {
    if (user._id !== Url.userIdFromUrl(window.location.href)) {
      this.redirect('hacker', user);
    }
  }
  this.next();
}

// GAnalytics
var pageView = function(route) {
  GAnalytics.pageview(route);
  this.next();
}

// set meta data
Router.onRun(setMetaData);

// make sure the user is logged in, except for the pages below
Router.onRun(loginRequired, {except: noLoginRequired});
Router.onBeforeAction(loginRequired, {except: noLoginRequired});

// make sure that user is allowed to enter the site
Router.onBeforeAction(allowedAccess, {except: noLoginRequired });

// log pageview to Google Analytics
Router.onRun(pageView);

// save and restore scroll state for every page

var scrollState = new State('routerScrollState', {
  routes: {}
});

Router.restoreScrollState = function() {
  var params = Router.current().params;
  var route = Router.current().path;
  var top = scrollState.get(route);

  if (top === 0 && params.hash)
    $(window).scrollTo($("#"+params.hash), {duration: 0, offset: 0});
  else
    $(window).scrollTop(top || 0);
}

var scrollHandler = function(event) {
  var route = Router.current().path;
  var top = $(window).scrollTop();
  scrollState.set(route, top);
}

Meteor.startup(function() {
  var routes = _.map(Router.routes, _.property('name'));

  _.each(Template, function(template, templateName) {
    if (_.contains(routes, templateName)) { // is route template
      var prevRenderFunc = template.rendered;
      template.rendered = function() {
        if (prevRenderFunc) prevRenderFunc.call(this);
        Router.restoreScrollState(); // restore scroll state
      }
    }
  });

  $(window).on("scrollstop", scrollHandler);
});

// internals

_.each(routes, function(route) {
  Router.route(route[1], {name: route[0]});
});

/* router plugins */

Router.scrollToTop = function() {
  $(window).scrollTop(0);
}

// reload current route (hack)
Router.reload = function() {
  var path = Router.current().path;
  Router.go('/about');
  Tracker.flush();
  Router.go(path);
}

// browser refresh location
Router.refresh = function(path) {
  if (!path)
    path = Router.current().path;
  window.location.href = path;
}

// browser refresh location to new city
Router.goToCity = function(city) {
  var url;

  var bitHash = Session.get('inviteBitHash');
  if (bitHash)
    url = Router.routes['invite'].url({inviteBitHash: bitHash});

  url = Url.replaceCity(city, url);

  Router.refresh(url);
}

// set meta data helpers

var setTitle = function(value) {
  $("title").text(value);
}
var setMeta = function(name, content) {
  $("meta[name='"+name+"']").attr('content', content);
}
var setMetaProperties = function(properties) {
  _.each(properties, function(content, property) {
    $("meta[property='"+property+"']").remove(); // remove existing one
    $("<meta>").attr({property: property, content: content}).appendTo('head');
  });
}
var clearProperties = function() {
  $("meta[property]").remove(); // remove all properties
}
var clear = function() {
  setTitle("");
  setMeta("description", "");
  clearProperties();
}
<commit_msg>Fix "scroll to top" after page load.<commit_after>// ROUTES

var routes = [

  // staff routes
  [ 'admin'                 , '/admin'                  ],
  [ 'admin_dashboard'       , '/admin/dashboard'        ],
  [ 'admin_highlights'      , '/admin/highlights'       ],
  [ 'admin_hackers'         , '/admin/hackers'          ],
  [ 'admin_deals'           , '/admin/deals'            ],
  [ 'admin_places'          , '/admin/places'           ],
  [ 'admin_growth'          , '/admin/growth'           ],
  [ 'admin_emailTemplates'  , '/admin/emailTemplates'   ],

  // normal routes
  [ 'frontpage'    , '/'                     ],
  [ 'about'        , '/about'                ],
  [ 'agenda'       , '/agenda'               ],
  [ 'books'        , '/books'                ],
  [ 'hackers'      , '/hackers'              ],
  [ 'highlights'   , '/highlights'           ],
  [ 'invitations'  , '/invitations'          ],
  [ 'map'          , '/map'                  ],
  [ 'deals'        , '/deals'                ],

  // special routes (which will redirect)
  [ 'logout'       , '/logout'               ],
  [ 'verifyEmail'  , '/verify-email/:token'  ],
  [ 'growth_github', '/gh/:phrase'           ], // e.g. /gh/FDMwdYYXxMY7dLcD4
  [ 'invite'       , '/+/:inviteBitHash/'    ], // e.g. /+/---_--

  // bare routes (must defined as last in this list)
  [ 'hacker'       , '/:bitHash'             ], // e.g. /--_-_-

];

// the routes that DON'T require login
var noLoginRequired = [
  'docs',
  'about',
  'frontpage',
  'invite',
  'verifyEmail',
];

/*
  special entry routes
  includes refer information
*/

InviteController = DefaultController.extend({
  template: 'frontpage',
  onBeforeAction: function() {
    // set some session variables and then redirects to the frontpage
    // the frontpage is now showing a picture of the user that has invited this visitor;
    Session.set('inviteBitHash', this.params.inviteBitHash);
    this.redirect('frontpage');
    this.next();
  }
});

GrowthGithubController = DefaultController.extend({
  template: 'frontpage',
  onBeforeAction: function() {
    Session.set('growthType', 'github');
    Session.set('growthPhrase', this.params.phrase);
    this.redirect('frontpage');
    this.next();
  }
});

LogoutController = DefaultController.extend({
  template: 'loading',
  onBeforeAction: function() {
    if (Meteor.userId()) {
      GAnalytics.event("LoginService", "logout");
      Meteor.logout();
      this.render('loading');
    } else {
      this.redirect('frontpage');
    }
  }
});

/* hooks */

// set meta data based on current city
var setMetaData = function() {
  var city = City.lookup(Session.get('currentCity'));
  var title, description;

  // modify meta data
  title = "hckrs.io";
  if (city) description = "Hackers community of " + city.name;
  else      description = "Hackers community in your city";

  // actually set data
  setTitle(title);
  setMeta("title", title);
  setMeta("description", description);
  setMetaProperties({
    "og:title": description,
    "og:site_name": title,
    "og:url": city ? Url.replaceCity(city.key, Meteor.absoluteUrl()) : Meteor.absoluteUrl(),
    "og:image": Meteor.absoluteUrl("img/favicons/apple-touch-icon-precomposed.png"),
    "og:description": description
  });

  this.next();
}

var loginRequired = function() {
  if (!Meteor.userId()) {
    if (!Session.get('redirectUrl'))
      Session.set('redirectUrl', location.pathname + location.search + location.hash);
    this.redirect('frontpage');
  }
  this.next();
}

// make sure that user is allowed to enter the site
var allowedAccess = function() {
  var user = Users.myProps(['isAccessDenied','globalId','bitHash']) || {};
  if(user.isAccessDenied) {
    if (user._id !== Url.userIdFromUrl(window.location.href)) {
      this.redirect('hacker', user);
    }
  }
  this.next();
}

// GAnalytics
var pageView = function(route) {
  GAnalytics.pageview(route);
  this.next();
}

// set meta data
Router.onRun(setMetaData);

// make sure the user is logged in, except for the pages below
Router.onRun(loginRequired, {except: noLoginRequired});
Router.onBeforeAction(loginRequired, {except: noLoginRequired});

// make sure that user is allowed to enter the site
Router.onBeforeAction(allowedAccess, {except: noLoginRequired });

// log pageview to Google Analytics
Router.onRun(pageView);

// save and restore scroll state for every page
var scrollState = new State('routerScrollState', {
  routes: {}
});

var scrollHandler = function(event) {
  var route = Router.current().url;
  var top = $(window).scrollTop();
  scrollState.set(route, top);
}

Meteor.startup(function() {
  $(window).on("scrollstop", scrollHandler);
});

// Restore scroll state after route is loaded
Router.restoreScrollState = function() {
  var params = Router.current().getParams();
  var route = Router.current().url;
  var top = scrollState.get(route);

  Tracker.afterFlush(function() {
    if (top === 0 && params.hash)
      $(window).scrollTo($("#"+params.hash), {duration: 0, offset: 0});
    else
      $(window).scrollTop(top || 0);
  });
}

// Restore scroll state after route is loaded
Router.onAfterAction(Router.restoreScrollState);

// internals

_.each(routes, function(route) {
  Router.route(route[1], {name: route[0]});
});

/* router plugins */

Router.scrollToTop = function() {
  $(window).scrollTop(0);
}

// reload current route (hack)
Router.reload = function() {
  var path = Router.current().path;
  Router.go('/about');
  Tracker.flush();
  Router.go(path);
}

// browser refresh location
Router.refresh = function(path) {
  if (!path)
    path = Router.current().path;
  window.location.href = path;
}

// browser refresh location to new city
Router.goToCity = function(city) {
  var url;

  var bitHash = Session.get('inviteBitHash');
  if (bitHash)
    url = Router.routes['invite'].url({inviteBitHash: bitHash});

  url = Url.replaceCity(city, url);

  Router.refresh(url);
}

// set meta data helpers

var setTitle = function(value) {
  $("title").text(value);
}
var setMeta = function(name, content) {
  $("meta[name='"+name+"']").attr('content', content);
}
var setMetaProperties = function(properties) {
  _.each(properties, function(content, property) {
    $("meta[property='"+property+"']").remove(); // remove existing one
    $("<meta>").attr({property: property, content: content}).appendTo('head');
  });
}
var clearProperties = function() {
  $("meta[property]").remove(); // remove all properties
}
var clear = function() {
  setTitle("");
  setMeta("description", "");
  clearProperties();
}
<|endoftext|>


<commit_before>YUI.add('annotation', function(Y) {

	var Node = Y.Node;

	function Annotation(config) {
		Annotation.superclass.constructor.apply(this, arguments);
	}
	Annotation.NAME = "aclist"; // use same name as Y.Plugin.AutoComplete to inherit css
	Annotation.NS = "annotation";
	Annotation.ATTRS = {
		commentNode: {
			value: null
		},
		target: {
			value: null
		},
		field: {
			value: null
		},
		store: {
			value: null
		},
		tags: {
			value: []
		},
		allowTextSubmit: {
			value:true
		}
	};

	Annotation.LIST_CLASS = 'taglist';
	Annotation.LIST_TEMPLATE = '

';

	Y.extend(Annotation, Y.Plugin.AutoComplete, {

		initializer: function(args) {
			var inputNode = args.inputNode,
				parentNode = this.DEF_PARENT_NODE;

			var tags = new Y.Recordset({records:{}});
			tags.on("add", this._addTags, this);
			tags.on("remove", this._removeTags, this);
			this.tags = tags;

			this.tagList = Node.create(Annotation.LIST_TEMPLATE);
			parentNode.append(this.tagList);
			this.infoNode = new Y.Overlay({
			}).render(parentNode);

			this.on("activeItemChange", this._onHover, this);
			this.on("hoveredItemChange", this._onHover, this);
			this.on("select", this._onItemSelect, this);
			Y.delegate("click", this._onTagRemoveClick, this.tagList, 'li .remove', this);
			inputNode.on("key", this._onTextSubmit, 'enter', this);

			var commentNode = this.get('commentNode');
			if (commentNode) {
			  commentNode = Y.one('#'+commentNode);
			  this.set('commentNode', commentNode);
			  commentNode.on("key", this._onTextSubmit, 'enter', this);
			}
			this.getTags();
		},

		_renderTags : function(tags, index) {
			var tagList = this.tagList;
			// format the tags
			for(var i=0; i < tags.length; i++) {
				tagList.append('
'+this.formatTag(tags[i])+'
');
			}
		},
		_addTags : function(o) {
			this._renderTags(o.added, o.index);
		},
		_removeTags : function(o) {
			var tagNodes = this.tagList.all("li"),
				index = o.index,
				range = o.range;
			for (var i=index; i < index+range; i++) {
				tagNodes.item(i).remove();
			}
		},

		formatTag : function(tag) {
			var label = tag.getValue("label");
			var body = tag.getValue("body");
			var comment = tag.getValue("comment");
			var link = tag.getValue("display_link");
			html = '
';
			html += ''+label+'';

			if (comment && comment != "") {
			  html += ' (' + comment +')';
			}
			html += '

x
';
			return html;
		},

		_onTagRemoveClick : function(e) {
			var index = this.tagList.all("li").indexOf(e.currentTarget.get("parentNode")),
				tags = this.tags,
				record = tags.getRecordByIndex(index),
				annotation = record.getValue("annotation");
			Y.log('remove annotation '+annotation+' at index: '+index);

			Y.io(this.get("store.remove"), {
				data:{
					annotation:annotation
				},
				on:{success: function(e) { tags.remove(index) }
				}
			});
		},
		getTags : function() {
			    var target = this.get('target'),
				 field = this.get('field');
			    var oSelf = this;
			    Y.io(this.get("store.get"),
				 { data: {
					 target: target,
					 field:  field
					 },
				   on: {
				       success: function(e,o) {
						  var r = Y.JSON.parse(o.responseText);
						  if (r && r[field] && r[field].annotations) {
						    var data =  r[field].annotations;
						    oSelf.tags.add(data);
						  }
						}
				       }
				 }
				);
			  },
		_onHover : function(e) {
			var infoNode = this.infoNode,
				active = e.newVal,
				body = '';
			if(active && active.getData().result.raw.info) {
				Y.log(active.getData());
				var scope = active.getData().result.raw.info.scopeNotes[0];
				var defin = active.getData().result.raw.info.definitions[0];
				var alts =  active.getData().result.raw.info.altLabels;
				if (scope && scope.en) { body += "
"+scope.en+"
"; }
				if (defin && defin.en) { body += "
"+defin.en+"
"; }
				for (var i=0; i<alts.length; i++) {
					body += "" +alts[i] + "" ;
				}
			}
			if(body) {
				infoNode.set("bodyContent", body);
				infoNode.set("align", {node:active,
				                      points:[Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.TR]});
				infoNode.show();
			} else {
				infoNode.hide();
			}
		},
		_onItemSelect : function(e) {
			var item = e.details[0].result.raw;
			var comm = this.getcomment();
			if (item.uri && item.label) {
			  this.submitAnnotation({type:"uri", value:item.uri}, item.label, comm);
			} else {
			  this.submitAnnotation({type:"literal", value: item}, item, comm);
			}
		},
		_onTextSubmit : function(e) {
			if(!this.get("activeItem")) {
				var value = this.get("inputNode").get("value");
				var comm = this.getcomment();
				this.submitAnnotation({type:"literal", value:value}, value, comm);
			}
		},

		getcomment: function() {
			      Y.log('getcomment');
			      var commentNode = this.get("commentNode");
			      Y.log(commentNode);
			      if (!commentNode) return "";
			      return commentNode.get("value");
		},

		submitAnnotation : function(body, label, comment) {
			Y.log('add tag: '+body.value+' with label: '+label+ ', comment: ' + comment);

			var inputNode = this.get("inputNode");
			var commentNode   = this.get("commentNode");
			var tags = this.tags;

			Y.io(this.get("store.add"), {
				data:{
					target:this.get("target"),
					field:this.get("field"),
					body:Y.JSON.stringify(body),
					label:label,
					comment: comment
				},
				on:{success: function(e,o) {
					var r = Y.JSON.parse(o.responseText);
					tags.add({body:body, label:label, annotation:r.annotation, comment:comment});
					inputNode.set("value", "");
					if (commentNode) commentNode.set("value", "");
				    }
				}
			});
		}

	});

	Y.Plugin.Annotation = Annotation;

}, '0.0.1', { requires: [
	'node','event','autocomplete','overlay','recordset','io-base','json','querystring-stringify-simple'
	]
});
<commit_msg>FIXED: also get display link when adding annotations, not only on get<commit_after>YUI.add('annotation', function(Y) {

	var Node = Y.Node;

	function Annotation(config) {
		Annotation.superclass.constructor.apply(this, arguments);
	}
	Annotation.NAME = "aclist"; // use same name as Y.Plugin.AutoComplete to inherit css
	Annotation.NS = "annotation";
	Annotation.ATTRS = {
		commentNode: {
			value: null
		},
		target: {
			value: null
		},
		field: {
			value: null
		},
		store: {
			value: null
		},
		tags: {
			value: []
		},
		allowTextSubmit: {
			value:true
		}
	};

	Annotation.LIST_CLASS = 'taglist';
	Annotation.LIST_TEMPLATE = '

';

	Y.extend(Annotation, Y.Plugin.AutoComplete, {

		initializer: function(args) {
			var inputNode = args.inputNode,
				parentNode = this.DEF_PARENT_NODE;

			var tags = new Y.Recordset({records:{}});
			tags.on("add", this._addTags, this);
			tags.on("remove", this._removeTags, this);
			this.tags = tags;

			this.tagList = Node.create(Annotation.LIST_TEMPLATE);
			parentNode.append(this.tagList);
			this.infoNode = new Y.Overlay({
			}).render(parentNode);

			this.on("activeItemChange", this._onHover, this);
			this.on("hoveredItemChange", this._onHover, this);
			this.on("select", this._onItemSelect, this);
			Y.delegate("click", this._onTagRemoveClick, this.tagList, 'li .remove', this);
			inputNode.on("key", this._onTextSubmit, 'enter', this);

			var commentNode = this.get('commentNode');
			if (commentNode) {
			  commentNode = Y.one('#'+commentNode);
			  this.set('commentNode', commentNode);
			  commentNode.on("key", this._onTextSubmit, 'enter', this);
			}
			this.getTags();
		},

		_renderTags : function(tags, index) {
			var tagList = this.tagList;
			// format the tags
			for(var i=0; i < tags.length; i++) {
				tagList.append('
'+this.formatTag(tags[i])+'
');
			}
		},
		_addTags : function(o) {
			this._renderTags(o.added, o.index);
		},
		_removeTags : function(o) {
			var tagNodes = this.tagList.all("li"),
				index = o.index,
				range = o.range;
			for (var i=index; i < index+range; i++) {
				tagNodes.item(i).remove();
			}
		},

		formatTag : function(tag) {
			var label = tag.getValue("label");
			var body = tag.getValue("body");
			var comment = tag.getValue("comment");
			var link = tag.getValue("display_link");
			html = '
';
			html += ''+label+'';

			if (comment && comment != "") {
			  html += ' (' + comment +')';
			}
			html += '

x
';
			return html;
		},

		_onTagRemoveClick : function(e) {
			var index = this.tagList.all("li").indexOf(e.currentTarget.get("parentNode")),
				tags = this.tags,
				record = tags.getRecordByIndex(index),
				annotation = record.getValue("annotation");
			Y.log('remove annotation '+annotation+' at index: '+index);

			Y.io(this.get("store.remove"), {
				data:{
					annotation:annotation
				},
				on:{success: function(e) { tags.remove(index) }
				}
			});
		},
		getTags : function() {
			    var target = this.get('target'),
				 field = this.get('field');
			    var oSelf = this;
			    Y.io(this.get("store.get"),
				 { data: {
					 target: target,
					 field:  field
					 },
				   on: {
				       success: function(e,o) {
						  var r = Y.JSON.parse(o.responseText);
						  if (r && r[field] && r[field].annotations) {
						    var data =  r[field].annotations;
						    oSelf.tags.add(data);
						  }
						}
				       }
				 }
				);
			  },
		_onHover : function(e) {
			var infoNode = this.infoNode,
				active = e.newVal,
				body = '';
			if(active && active.getData().result.raw.info) {
				Y.log(active.getData());
				var scope = active.getData().result.raw.info.scopeNotes[0];
				var defin = active.getData().result.raw.info.definitions[0];
				var alts =  active.getData().result.raw.info.altLabels;
				if (scope && scope.en) { body += "
"+scope.en+"
"; }
				if (defin && defin.en) { body += "
"+defin.en+"
"; }
				for (var i=0; i<alts.length; i++) {
					body += "" +alts[i] + "" ;
				}
			}
			if(body) {
				infoNode.set("bodyContent", body);
				infoNode.set("align", {node:active,
				                      points:[Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.TR]});
				infoNode.show();
			} else {
				infoNode.hide();
			}
		},
		_onItemSelect : function(e) {
			var item = e.details[0].result.raw;
			var comm = this.getcomment();
			if (item.uri && item.label) {
			  this.submitAnnotation({type:"uri", value:item.uri}, item.label, comm);
			} else {
			  this.submitAnnotation({type:"literal", value: item}, item, comm);
			}
		},
		_onTextSubmit : function(e) {
			if(!this.get("activeItem")) {
				var value = this.get("inputNode").get("value");
				var comm = this.getcomment();
				this.submitAnnotation({type:"literal", value:value}, value, comm);
			}
		},

		getcomment: function() {
			      Y.log('getcomment');
			      var commentNode = this.get("commentNode");
			      Y.log(commentNode);
			      if (!commentNode) return "";
			      return commentNode.get("value");
		},

		submitAnnotation : function(body, label, comment) {
			Y.log('add tag: '+body.value+' with label: '+label+ ', comment: ' + comment);

			var inputNode = this.get("inputNode");
			var commentNode   = this.get("commentNode");
			var tags = this.tags;

			Y.io(this.get("store.add"), {
				data:{
					target:this.get("target"),
					field:this.get("field"),
					body:Y.JSON.stringify(body),
					label:label,
					comment: comment
				},
				on:{success: function(e,o) {
					var r = Y.JSON.parse(o.responseText);
					tags.add({body:body, label:label, annotation:r.annotation, comment:comment, display_link:r.display_link});
					inputNode.set("value", "");
					if (commentNode) commentNode.set("value", "");
				    }
				}
			});
		}

	});

	Y.Plugin.Annotation = Annotation;

}, '0.0.1', { requires: [
	'node','event','autocomplete','overlay','recordset','io-base','json','querystring-stringify-simple'
	]
});
<|endoftext|>


<commit_before>'use strict';

app.controller('party/profile', [
  '$scope', 'displayService', 'party', 'pageService','constantService', 'modelService',
  function ($scope, display, party, page, constants, models) {
    var getUsers = function(volumes){

      var users = {};

      users.sponsors = [];
      users.databrary = [];
      users.labOnly = [];
      users.otherCollaborators = [];

      _(volumes).pluck('access').flatten().uniq(function(i){
        return i.party.id;
      }).each(function(v, index, array){

        if(models.Login.user.id === v.party.id){
          v.isCurrent = true;
          users.sponsors.push(v);
        }

        if(v.party.parents && v.party.parents.length){
          users.sponsors = users.sponsors.concat(v.party.parents);
        } else if(v.party.site && v.party.site > page.constants.permission.NONE) {
          users.databrary.push(v);
        } else if(v.party.site == null || v.party.site == page.constants.permission.NONE) {
          users.labOnly.push(v);
        } else {
          users.otherCollaborators.push(v);
        }
      }).value();
      // The "value()" call is to actually force theb chain to work.

      var filterOnId = function(i){
        return i.party.id;
      };

      users.sponsors = _.uniq(users.sponsors, filterOnId);
      users.databrary = _.uniq(users.databrary, filterOnId);
      users.labOnly = _.uniq(users.labOnly, filterOnId);
      users.otherCollaborators = _.uniq(users.otherCollaborators, filterOnId);

      return users;
    };

    // This is a quick helper function to make sure that the isSelected
    // class is set to empty and to avoid repeating code.
    var unSetSelected = function(v){
      v.isSelected = '';
      if(v.v !== undefined){
        v.v = _.map(v.v, function(a){
          a.isSelected = '';
          return a;
        });
      }

      return v;
    };

    $scope.unselectAll = function(){

      $scope.volumes.individual = _.map($scope.volumes.individual, unSetSelected);

      $scope.volumes.collaborator = _.map($scope.volumes.collaborator, unSetSelected);

      $scope.volumes.inherited = _.map($scope.volumes.inherited, unSetSelected);

      $scope.users.sponsors = _.map($scope.users.sponsors, unSetSelected);

      $scope.users.nonGroupAffiliates = _.map($scope.users.nonGroupAffiliates, unSetSelected);

      $scope.users.labGroupMembers = _.map($scope.users.labGroupMembers, unSetSelected);

      $scope.users.otherCollaborators = _.map($scope.users.otherCollaborators, unSetSelected);

    };

    $scope.clickVolume = function(volume) {

      $scope.unselectAll();
      volume.isSelected = 'volumeSelected';
      volume = _.flatten([volume.v || volume]);
      for(var k = 0; k < volume.length; k++){
        for(var i = 0; i < volume[k].access.length; i++){

          var j;

          for (j = 0; j < $scope.users.sponsors.length; j++){
            if($scope.users.sponsors[j].party.id === volume[k].access[i].party.id){
              $scope.users.sponsors[j].isSelected = 'userSelected';
            }
          }

          for (j = 0; j < $scope.users.labGroupMembers.length; j++) {
            if($scope.users.labGroupMembers[j].party.id === volume[k].access[i].party.id){
              $scope.users.labGroupMembers[j].isSelected = 'userSelected';
            }
          }

          for (j = 0; j < $scope.users.nonGroupAffiliates.length; j++) {
            if($scope.users.nonGroupAffiliates[j].party.id === volume[k].access[i].party.id){
              $scope.users.nonGroupAffiliates[j].isSelected = 'userSelected';
            }
          }

          for (j = 0; j < $scope.users.otherCollaborators.length; j++) {
            if($scope.users.otherCollaborators[j].party.id === volume[k].access[i].party.id){
              $scope.users.otherCollaborators[j].isSelected = 'userSelected';
            }
          }
        }
      }
    };

    // This should take in a user, then select volumes on each thing.
    $scope.clickUser = function(user){
      $scope.unselectAll();
      user.isSelected = 'userSelected';
      var i, j, k;

      var compareFunction = function(value, key, array){
        for(j = 0; j < value.access.length; j++){
          if(value.access[j].party.id == user.party.id){
            array[key].isSelected = 'volumeSelected';
          }
        }
      };

      _.each($scope.volumes.individual, compareFunction);
      _.each($scope.volumes.collaborator, compareFunction);

      for(i = 0; i < $scope.volumes.inherited.length; i++){
        _.each($scope.volumes.inherited[i].v, compareFunction);
      }
    };

    var getParents = function(parents) {
      return _.compact(_.map(parents, function(p){
        if(p.member) {
          var v = [];
          return {
            p: p,
            v: v
          };
        }
      }));
    };

    var getVolumes = function(volumes) {
      var tempVolumes = {};
      tempVolumes.individual = [];
      tempVolumes.collaborator = [];

      tempVolumes.inherited = getParents(party.parents);

      _.each(volumes, function(v){

        var isCurrent = _.find(v.access, function(r){
          return r.party.id === models.Login.user.id;
        });

        var isAdmin = _.find(v.access, function(r) {
          return r.party.authorization === 5;
        });

        if(isCurrent && isAdmin){
          // The "mini-object" with v and [v] is to make sure that the data is all
          // shaped the same, making looping over it *substantially* simpler.
          tempVolumes.individual.push(v);
        } else if(isCurrent){
          tempVolumes.collaborator.push(v);
        } else {
          for (var i = 0; i < v.access.length; i++) {
            for (var j = 0; j < tempVolumes.inherited.length; j++) {
              if (v.access[i].children && v.access[i].party.id === tempVolumes.inherited[j].p.party.id) {
                tempVolumes.inherited[j].v.push(v);
                break;
              }
            }
          }
        }
      });

      return tempVolumes;

    };

    $scope.party = party;
    $scope.users = getUsers(party.volumes);
    $scope.volumes = getVolumes(party.volumes);

    $scope.page = page;
    $scope.profile = page.$location.path() === '/profile';
    display.title = party.name;

  }
]);
<commit_msg>Get rid of extraneous variable.<commit_after>'use strict';

app.controller('party/profile', [
  '$scope', 'displayService', 'party', 'pageService','constantService', 'modelService',
  function ($scope, display, party, page, constants, models) {
    var getUsers = function(volumes){

      var users = {};

      users.sponsors = [];
      users.databrary = [];
      users.labOnly = [];
      users.otherCollaborators = [];

      _(volumes).pluck('access').flatten().uniq(function(i){
        return i.party.id;
      }).each(function(v, index, array){

        if(models.Login.user.id === v.party.id){
          v.isCurrent = true;
          users.sponsors.push(v);
        }

        if(v.party.parents && v.party.parents.length){
          users.sponsors = users.sponsors.concat(v.party.parents);
        } else if(v.party.site && v.party.site > page.constants.permission.NONE) {
          users.databrary.push(v);
        } else if(v.party.site == null || v.party.site == page.constants.permission.NONE) {
          users.labOnly.push(v);
        } else {
          users.otherCollaborators.push(v);
        }
      }).value();
      // The "value()" call is to actually force theb chain to work.

      var filterOnId = function(i){
        return i.party.id;
      };

      users.sponsors = _.uniq(users.sponsors, filterOnId);
      users.databrary = _.uniq(users.databrary, filterOnId);
      users.labOnly = _.uniq(users.labOnly, filterOnId);
      users.otherCollaborators = _.uniq(users.otherCollaborators, filterOnId);

      return users;
    };

    // This is a quick helper function to make sure that the isSelected
    // class is set to empty and to avoid repeating code.
    var unSetSelected = function(v){
      v.isSelected = '';
      if(v.v !== undefined){
        v.v = _.map(v.v, function(a){
          a.isSelected = '';
          return a;
        });
      }

      return v;
    };

    $scope.unselectAll = function(){

      $scope.volumes.individual = _.map($scope.volumes.individual, unSetSelected);

      $scope.volumes.collaborator = _.map($scope.volumes.collaborator, unSetSelected);

      $scope.volumes.inherited = _.map($scope.volumes.inherited, unSetSelected);

      $scope.users.sponsors = _.map($scope.users.sponsors, unSetSelected);

      $scope.users.nonGroupAffiliates = _.map($scope.users.nonGroupAffiliates, unSetSelected);

      $scope.users.labGroupMembers = _.map($scope.users.labGroupMembers, unSetSelected);

      $scope.users.otherCollaborators = _.map($scope.users.otherCollaborators, unSetSelected);

    };

    $scope.clickVolume = function(volume) {

      $scope.unselectAll();
      volume.isSelected = 'volumeSelected';
      volume = _.flatten([volume.v || volume]);
      for(var k = 0; k < volume.length; k++){
        for(var i = 0; i < volume[k].access.length; i++){

          var j;

          for (j = 0; j < $scope.users.sponsors.length; j++){
            if($scope.users.sponsors[j].party.id === volume[k].access[i].party.id){
              $scope.users.sponsors[j].isSelected = 'userSelected';
            }
          }

          for (j = 0; j < $scope.users.labGroupMembers.length; j++) {
            if($scope.users.labGroupMembers[j].party.id === volume[k].access[i].party.id){
              $scope.users.labGroupMembers[j].isSelected = 'userSelected';
            }
          }

          for (j = 0; j < $scope.users.nonGroupAffiliates.length; j++) {
            if($scope.users.nonGroupAffiliates[j].party.id === volume[k].access[i].party.id){
              $scope.users.nonGroupAffiliates[j].isSelected = 'userSelected';
            }
          }

          for (j = 0; j < $scope.users.otherCollaborators.length; j++) {
            if($scope.users.otherCollaborators[j].party.id === volume[k].access[i].party.id){
              $scope.users.otherCollaborators[j].isSelected = 'userSelected';
            }
          }
        }
      }
    };

    // This should take in a user, then select volumes on each thing.
    $scope.clickUser = function(user){
      $scope.unselectAll();
      user.isSelected = 'userSelected';
      var i, j, k;

      var compareFunction = function(value, key, array){
        for(j = 0; j < value.access.length; j++){
          if(value.access[j].party.id == user.party.id){
            array[key].isSelected = 'volumeSelected';
          }
        }
      };

      _.each($scope.volumes.individual, compareFunction);
      _.each($scope.volumes.collaborator, compareFunction);

      for(i = 0; i < $scope.volumes.inherited.length; i++){
        _.each($scope.volumes.inherited[i].v, compareFunction);
      }
    };

    var getParents = function(parents) {
      return _.compact(_.map(parents, function(p){
        if(p.member) {
          return {
            p: p,
            v: []
          };
        }
      }));
    };

    var getVolumes = function(volumes) {
      var tempVolumes = {};
      tempVolumes.individual = [];
      tempVolumes.collaborator = [];

      tempVolumes.inherited = getParents(party.parents);

      _.each(volumes, function(v){

        var isCurrent = _.find(v.access, function(r){
          return r.party.id === models.Login.user.id;
        });

        var isAdmin = _.find(v.access, function(r) {
          return r.party.authorization === 5;
        });

        if(isCurrent && isAdmin){
          // The "mini-object" with v and [v] is to make sure that the data is all
          // shaped the same, making looping over it *substantially* simpler.
          tempVolumes.individual.push(v);
        } else if(isCurrent){
          tempVolumes.collaborator.push(v);
        } else {
          for (var i = 0; i < v.access.length; i++) {
            for (var j = 0; j < tempVolumes.inherited.length; j++) {
              if (v.access[i].children && v.access[i].party.id === tempVolumes.inherited[j].p.party.id) {
                tempVolumes.inherited[j].v.push(v);
                break;
              }
            }
          }
        }
      });

      return tempVolumes;

    };

    $scope.party = party;
    $scope.users = getUsers(party.volumes);
    $scope.volumes = getVolumes(party.volumes);

    $scope.page = page;
    $scope.profile = page.$location.path() === '/profile';
    display.title = party.name;

  }
]);
<|endoftext|>


<commit_before>const fs = require('fs')
const express = require('express')
const router = express.Router()

router.get('/', function (req, res, next) {
  var filePath = __dirname + '/../public/dst/pdf/01_january_2018.pdf'

  if (req.query.download) {
    return res.download(filePath)
  }

  renderResume(filePath, res)
})

function renderResume (filePath, res) {
  fs.readFile(filePath, function (err, data) {
    if (err) {
      return res.render('error', {
        title: 'Sorry. Can\'t load the pdf now...',
        specialMessage: 'There was a problem while loading this pdf. Please, send me an email and I\'ll send you the PDF and review the bug: jorge@ferreiro.me',
        error: {}
      })
    }

    res.contentType('application/pdf')
    res.send(data)
  })
}

module.exports = router
<commit_msg>Update resume.js<commit_after>const fs = require('fs')
const express = require('express')
const router = express.Router()

router.get('/', function (req, res, next) {
  var filePath = __dirname + '/../public/dst/pdf/Jorge_Ferreiro_August_2018_web_version.pdf'

  if (req.query.download) {
    return res.download(filePath)
  }

  renderResume(filePath, res)
})

function renderResume (filePath, res) {
  fs.readFile(filePath, function (err, data) {
    if (err) {
      return res.render('error', {
        title: 'Sorry. Can\'t load the pdf now...',
        specialMessage: 'There was a problem while loading this pdf. Please, send me an email and I\'ll send you the PDF and review the bug: jorge@ferreiro.me',
        error: {}
      })
    }

    res.contentType('application/pdf')
    res.send(data)
  })
}

module.exports = router
<|endoftext|>