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

couchTests.view_multi_key_all_docs = function(debug) {
  var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"});
  db.deleteDb();
  db.createDb();
  if (debug) debugger;

  var docs = makeDocs(0, 100);
  db.bulkSave(docs);

  var keys = ["10","15","30","37","50"];
  var rows = db.allDocs({},keys).rows;
  T(rows.length == keys.length);
  for(var i=0; i<rows.length; i++)
    T(rows[i].id == keys[i]);

  // keys in GET parameters
  rows = db.allDocs({keys:keys}, null).rows;
  T(rows.length == keys.length);
  for(var i=0; i<rows.length; i++)
    T(rows[i].id == keys[i]);

  rows = db.allDocs({limit: 1}, keys).rows;
  T(rows.length == 1);
  T(rows[0].id == keys[0]);

  // keys in GET parameters
  rows = db.allDocs({limit: 1, keys: keys}, null).rows;
  T(rows.length == 1);
  T(rows[0].id == keys[0]);

  rows = db.allDocs({skip: 2}, keys).rows;
  T(rows.length == 3);
  for(var i=0; i<rows.length; i++)
      T(rows[i].id == keys[i+2]);

  // keys in GET parameters
  rows = db.allDocs({skip: 2, keys: keys}, null).rows;
  T(rows.length == 3);
  for(var i=0; i<rows.length; i++)
      T(rows[i].id == keys[i+2]);

  rows = db.allDocs({descending: "true"}, keys).rows;
  T(rows.length == keys.length);
  for(var i=0; i<rows.length; i++)
      T(rows[i].id == keys[keys.length-i-1]);

  // keys in GET parameters
  rows = db.allDocs({descending: "true", keys: keys}, null).rows;
  T(rows.length == keys.length);
  for(var i=0; i<rows.length; i++)
      T(rows[i].id == keys[keys.length-i-1]);

  rows = db.allDocs({descending: "true", skip: 3, limit:1}, keys).rows;
  T(rows.length == 1);
  T(rows[0].id == keys[1]);

  // keys in GET parameters
  rows = db.allDocs({descending: "true", skip: 3, limit:1, keys: keys}, null).rows;
  T(rows.length == 1);
  T(rows[0].id == keys[1]);

  // Check we get invalid rows when the key doesn't exist
  rows = db.allDocs({}, [1, "i_dont_exist", "0"]).rows;
  T(rows.length == 3);
  T(rows[0].error == "not_found");
  T(!rows[0].id);
  T(rows[1].error == "not_found");
  T(!rows[1].id);
  T(rows[2].id == rows[2].key && rows[2].key == "0");

  // keys in GET parameters
  rows = db.allDocs({keys: [1, "i_dont_exist", "0"]}, null).rows;
  T(rows.length == 3);
  T(rows[0].error == "not_found");
  T(!rows[0].id);
  T(rows[1].error == "not_found");
  T(!rows[1].id);
  T(rows[2].id == rows[2].key && rows[2].key == "0");

  // empty keys
  rows = db.allDocs({keys: []}, null).rows;
  T(rows.length == 0);
};
<commit_msg>JS test: update view_multi_key_all_docs.js for 2.0<commit_after>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

couchTests.view_multi_key_all_docs = function(debug) {
  var db_name = get_random_db_name();
  var db = new CouchDB(db_name, {"X-Couch-Full-Commit":"false"});
  db.createDb();
  if (debug) debugger;

  var docs = makeDocs(0, 100);
  db.bulkSave(docs);

  var keys = ["10","15","30","37","50"];
  var rows = db.allDocs({},keys).rows;
  T(rows.length == keys.length);
  for(var i=0; i<rows.length; i++)
    T(rows[i].id == keys[i]);

  // keys in GET parameters
  rows = db.allDocs({keys:keys}, null).rows;
  T(rows.length == keys.length);
  for(var i=0; i<rows.length; i++)
    T(rows[i].id == keys[i]);

  rows = db.allDocs({limit: 1}, keys).rows;
  T(rows.length == 1);
  T(rows[0].id == keys[0]);

  // keys in GET parameters
  rows = db.allDocs({limit: 1, keys: keys}, null).rows;
  T(rows.length == 1);
  T(rows[0].id == keys[0]);

  rows = db.allDocs({skip: 2}, keys).rows;
  T(rows.length == 3);
  for(var i=0; i<rows.length; i++)
      T(rows[i].id == keys[i+2]);

  // keys in GET parameters
  rows = db.allDocs({skip: 2, keys: keys}, null).rows;
  T(rows.length == 3);
  for(var i=0; i<rows.length; i++)
      T(rows[i].id == keys[i+2]);

  rows = db.allDocs({descending: "true"}, keys).rows;
  T(rows.length == keys.length);
  for(var i=0; i<rows.length; i++)
      T(rows[i].id == keys[keys.length-i-1]);

  // keys in GET parameters
  rows = db.allDocs({descending: "true", keys: keys}, null).rows;
  T(rows.length == keys.length);
  for(var i=0; i<rows.length; i++)
      T(rows[i].id == keys[keys.length-i-1]);

  rows = db.allDocs({descending: "true", skip: 3, limit:1}, keys).rows;
  T(rows.length == 1);
  T(rows[0].id == keys[1]);

  // keys in GET parameters
  rows = db.allDocs({descending: "true", skip: 3, limit:1, keys: keys}, null).rows;
  T(rows.length == 1);
  T(rows[0].id == keys[1]);

  // Check we get invalid rows when the key doesn't exist
  rows = db.allDocs({}, ["1111", "i_dont_exist", "0"]).rows;
  T(rows.length == 3);
  T(rows[0].error == "not_found");
  T(!rows[0].id);
  T(rows[1].error == "not_found");
  T(!rows[1].id);
  T(rows[2].id == rows[2].key && rows[2].key == "0");

  // keys in GET parameters
  rows = db.allDocs({keys: ["1211", "i_dont_exist", "0"]}, null).rows;
  T(rows.length == 3);
  T(rows[0].error == "not_found");
  T(!rows[0].id);
  T(rows[1].error == "not_found");
  T(!rows[1].id);
  T(rows[2].id == rows[2].key && rows[2].key == "0");

  // empty keys
  rows = db.allDocs({keys: []}, null).rows;
  T(rows.length == 0);

  // cleanup
  db.deleteDb();
};
<|endoftext|>


<commit_before>function decode(str) {
    try {
        return decodeURIComponent(str);
    }
    catch(e) {
        return str;
    }
}

function extract(str, start, end) {
    if( start === end + 1) {
        return "";
    }
    return str.slice(
        trimForward(str, start),
        trimBackward(str, end) + 1
    );
}

function trimForward(str, i) {
    var ch = str.charCodeAt(i);
    while (isWhiteSpace(ch)) {
        ch = str.charCodeAt(++i);
    }
    return i;

}

function trimBackward(str, i) {
    var ch = str.charCodeAt(i);
    while (isWhiteSpace(ch)) {
        ch = str.charCodeAt(--i);
    }
    return i;
}

function isWhiteSpace(ch) {
    return ch <= SPACE;
}

function parse(str) {
    if (typeof str !== "string") {
        throw new TypeError("str must be a string (Cookie parser)");
    }

    if (arguments.length > 1) {
        var opt = arguments[1];
        if (typeof opt === "object" && opt !== null &&
            typeof opt.decode === "function") {
            return slowParse(str, opt.decode);
        }
    }

    var dictionary = {};
    var keyStart = 0;
    var keyEnd = 0;
    var valueStart = 0;
    var valueEnd = 0;
    var valueMightNeedDecoding = false;
    var mode = KEY;
    var i = 0;

    //reset values
    for( var len = str.length; i < len; ++i ) {
        var ch = str.charCodeAt(i);
        if (ch > MAX_ASCII) {
            return slowParse(str, decode);
        }
        switch(mode) {
        case KEY:
            if (ch === EQUALS) {
                mode = VALUE_START;
            }
            else if (ch === SCOLON ||
                     ch === COMMA) {
                keyEnd = keyStart = i + 1;
            }
            else {
                keyEnd = i;
            }
            break;

        case VALUE_START:
            valueStart = valueEnd = i;
            if (ch === QUOTE) {
                valueStart = valueEnd = i + 1;
                mode = STRING;
                break;
            }
            //Character is part of value - fall through
            mode = VALUE;
        /* falls through */
        case VALUE:
            if (ch === PCT) {
                valueMightNeedDecoding = true;
            }
            if (ch === SCOLON ||
                ch === COMMA) {
                var key = extract(str, keyStart, keyEnd);
                var value = extract(str, valueStart, valueEnd);

                dictionary[key] = valueMightNeedDecoding
                    ? decode(value)
                    : value;
                valueMightNeedDecoding = false;
                var j = i;
                for (; j < len; ++j) {
                    if (str.charCodeAt(j) !== SPACE) {
                        i = j - 1;
                        break;
                    }
                }
                keyEnd = keyStart = i + 1;
                mode = KEY;
            }
            else {
                valueEnd = i;
            }
            break;

        case STRING:
            if (ch === PCT) {
                valueMightNeedDecoding = true;
            }
            if (ch === SCOLON ||
                ch === COMMA) {
                var j = trimBackward(str, i - 1);
                valueEnd = j - 1;
                if(valueEnd < valueStart) valueStart = valueEnd;

                var key = extract(str, keyStart, keyEnd);
                var value = extract(str, valueStart, valueEnd);

                dictionary[key] = valueMightNeedDecoding
                    ? decode(value)
                    : value;

                valueMightNeedDecoding = false;
                j = i;
                for (; j < len; ++j) {
                    if (str.charCodeAt(j) !== SPACE) {
                        i = j - 1;
                        break;
                    }
                }
                keyEnd = keyStart = i + 1;
                mode = KEY;
            }
            else {
                valueEnd = i;
            }
            break;
        }
    }

    if (mode !== KEY) {
        if (mode === STRING) {
            var j = trimBackward(str, i - 1);
            valueEnd = j - 1;
            if(valueEnd < valueStart) valueStart = valueEnd;
        }
        var key = extract(str, keyStart, keyEnd);
        var value = extract(str, valueStart, valueEnd);

        dictionary[key] = valueMightNeedDecoding
            ? decode(value)
            : value;
    }
    return dictionary;
}

function serialize() {

}

module.exports = {
    parse: parse,
    serialize: serialize
};

/*
// MIT License
Copyright (C) Roman Shtylman <shtylman@gmail.com>
https://github.com/defunctzombie/node-cookie/
*/
function slowParse(str, dec) {
    var obj = {};
    var pairs = str.split(/[;,] */);

    pairs.forEach(function(pair) {
        var eq_idx = pair.indexOf("=");

        // skip things that don't look like key=value
        if (eq_idx < 0) {
            return;
        }

        var key = pair.substr(0, eq_idx).trim();
        var val = pair.substr(++eq_idx, pair.length).trim();

        // quoted values
        if ("\"" == val[0]) {
            val = val.slice(1, -1);
        }

        // only assign once
        if (undefined == obj[key]) {
            try {
                obj[key] = dec(val);
            } catch (e) {
                obj[key] = val;
            }
        }
    });

    return obj;
}
<commit_msg>serialize method<commit_after>function decode(str) {
    try {
        return decodeURIComponent(str);
    }
    catch(e) {
        return str;
    }
}

function extract(str, start, end) {
    if( start === end + 1) {
        return "";
    }
    return str.slice(
        trimForward(str, start),
        trimBackward(str, end) + 1
    );
}

function trimForward(str, i) {
    var ch = str.charCodeAt(i);
    while (isWhiteSpace(ch)) {
        ch = str.charCodeAt(++i);
    }
    return i;

}

function trimBackward(str, i) {
    var ch = str.charCodeAt(i);
    while (isWhiteSpace(ch)) {
        ch = str.charCodeAt(--i);
    }
    return i;
}

function isWhiteSpace(ch) {
    return ch <= SPACE;
}

function parse(str) {
    if (typeof str !== "string") {
        throw new TypeError("str must be a string (Cookie parser)");
    }

    if (arguments.length > 1) {
        var opt = arguments[1];
        if (typeof opt === "object" && opt !== null &&
            typeof opt.decode === "function") {
            return slowParse(str, opt.decode);
        }
    }

    var dictionary = {};
    var keyStart = 0;
    var keyEnd = 0;
    var valueStart = 0;
    var valueEnd = 0;
    var valueMightNeedDecoding = false;
    var mode = KEY;
    var i = 0;

    //reset values
    for( var len = str.length; i < len; ++i ) {
        var ch = str.charCodeAt(i);
        if (ch > MAX_ASCII) {
            return slowParse(str, decode);
        }
        switch(mode) {
        case KEY:
            if (ch === EQUALS) {
                mode = VALUE_START;
            }
            else if (ch === SCOLON ||
                     ch === COMMA) {
                keyEnd = keyStart = i + 1;
            }
            else {
                keyEnd = i;
            }
            break;

        case VALUE_START:
            valueStart = valueEnd = i;
            if (ch === QUOTE) {
                valueStart = valueEnd = i + 1;
                mode = STRING;
                break;
            }
            //Character is part of value - fall through
            mode = VALUE;
        /* falls through */
        case VALUE:
            if (ch === PCT) {
                valueMightNeedDecoding = true;
            }
            if (ch === SCOLON ||
                ch === COMMA) {
                var key = extract(str, keyStart, keyEnd);
                var value = extract(str, valueStart, valueEnd);

                dictionary[key] = valueMightNeedDecoding
                    ? decode(value)
                    : value;
                valueMightNeedDecoding = false;
                var j = i;
                for (; j < len; ++j) {
                    if (str.charCodeAt(j) !== SPACE) {
                        i = j - 1;
                        break;
                    }
                }
                keyEnd = keyStart = i + 1;
                mode = KEY;
            }
            else {
                valueEnd = i;
            }
            break;

        case STRING:
            if (ch === PCT) {
                valueMightNeedDecoding = true;
            }
            if (ch === SCOLON ||
                ch === COMMA) {
                var j = trimBackward(str, i - 1);
                valueEnd = j - 1;
                if(valueEnd < valueStart) valueStart = valueEnd;

                var key = extract(str, keyStart, keyEnd);
                var value = extract(str, valueStart, valueEnd);

                dictionary[key] = valueMightNeedDecoding
                    ? decode(value)
                    : value;

                valueMightNeedDecoding = false;
                j = i;
                for (; j < len; ++j) {
                    if (str.charCodeAt(j) !== SPACE) {
                        i = j - 1;
                        break;
                    }
                }
                keyEnd = keyStart = i + 1;
                mode = KEY;
            }
            else {
                valueEnd = i;
            }
            break;
        }
    }

    if (mode !== KEY) {
        if (mode === STRING) {
            var j = trimBackward(str, i - 1);
            valueEnd = j - 1;
            if(valueEnd < valueStart) valueStart = valueEnd;
        }
        var key = extract(str, keyStart, keyEnd);
        var value = extract(str, valueStart, valueEnd);

        dictionary[key] = valueMightNeedDecoding
            ? decode(value)
            : value;
    }
    return dictionary;
}

module.exports = {
    parse: parse,
    serialize: serialize
};

/*
// MIT License
Copyright (C) Roman Shtylman <shtylman@gmail.com>
https://github.com/defunctzombie/node-cookie/
*/
function serialize(name, val, opt) {
    opt = opt || {};
    var enc = opt.encode || encode;
    var pairs = [name + '=' + enc(val)];

    if (opt.maxAge) pairs.push('Max-Age=' + opt.maxAge);
    if (opt.domain) pairs.push('Domain=' + opt.domain);
    if (opt.path) pairs.push('Path=' + opt.path);
    if (opt.expires) pairs.push('Expires=' + opt.expires.toUTCString());
    if (opt.httpOnly) pairs.push('HttpOnly');
    if (opt.secure) pairs.push('Secure');

    return pairs.join('; ');
}
function slowParse(str, dec) {
    var obj = {};
    var pairs = str.split(/[;,] */);

    pairs.forEach(function(pair) {
        var eq_idx = pair.indexOf("=");

        // skip things that don't look like key=value
        if (eq_idx < 0) {
            return;
        }

        var key = pair.substr(0, eq_idx).trim();
        var val = pair.substr(++eq_idx, pair.length).trim();

        // quoted values
        if ("\"" == val[0]) {
            val = val.slice(1, -1);
        }

        // only assign once
        if (undefined == obj[key]) {
            try {
                obj[key] = dec(val);
            } catch (e) {
                obj[key] = val;
            }
        }
    });

    return obj;
}
<|endoftext|>


<commit_before><commit_msg>fix bug 32536<commit_after><|endoftext|>


<commit_before>import Tween from './Tween';

export default class TweenManager {
  constructor(){
      this.tweens = [];
      this._tweensToDelete = [];

      this._last = 0;
  }

  update(delta){
    let deltaMS;
    if(!delta && delta !== 0){
      deltaMS = this._getDeltaMS();
      delta = deltaMS/1000;
    }else{
      deltaMS = delta*1000;
    }

    for(let i = 0; i < this.tweens.length; i++){
      let tween = this.tweens[i];
      //console.log(tween.active, tween.isEnded, tween.expire );
      if(tween.active){
        tween.update(delta, deltaMS);
      }
      if (tween.isEnded && tween.expire) {
        tween.remove();
      }
    }

    if(this._tweensToDelete.length){
      for(let i = 0; i < this._tweensToDelete.length; i++) this._remove(this._tweensToDelete[i]);
      this._tweensToDelete.length = 0;
    }
  }

  getTweensForTarget(target){
    let tweens = [];
    for(let i = 0; i < this.tweens.length; i++){
      if(this.tweens[i].target === target)tweens.push(this.tweens[i]);
    }

    return tweens;
  }

  createTween(target){
    return new Tween(target, this);
  }

  addTween(tween){
    tween.manager = this;
    this.tweens.push(tween);
  }

  removeTween(tween){
    this._tweensToDelete.push(tween);
  }

  _remove(tween){
    let index = this.tweens.indexOf(tween);
    if(index !== -1) this.tweens.splice(index, 1);
  }

  _getDeltaMS(){
    if(this._last === 0)this._last = Date.now();
    let now = Date.now();
    let deltaMS = now-this._last;
    this._last = now;
    return deltaMS;
  }
}
<commit_msg>rm console.log<commit_after>import Tween from './Tween';

export default class TweenManager {
  constructor(){
      this.tweens = [];
      this._tweensToDelete = [];

      this._last = 0;
  }

  update(delta){
    let deltaMS;
    if(!delta && delta !== 0){
      deltaMS = this._getDeltaMS();
      delta = deltaMS/1000;
    }else{
      deltaMS = delta*1000;
    }

    for(let i = 0; i < this.tweens.length; i++){
      let tween = this.tweens[i];
      if(tween.active){
        tween.update(delta, deltaMS);
      }
      if (tween.isEnded && tween.expire) {
        tween.remove();
      }
    }

    if(this._tweensToDelete.length){
      for(let i = 0; i < this._tweensToDelete.length; i++) this._remove(this._tweensToDelete[i]);
      this._tweensToDelete.length = 0;
    }
  }

  getTweensForTarget(target){
    let tweens = [];
    for(let i = 0; i < this.tweens.length; i++){
      if(this.tweens[i].target === target)tweens.push(this.tweens[i]);
    }

    return tweens;
  }

  createTween(target){
    return new Tween(target, this);
  }

  addTween(tween){
    tween.manager = this;
    this.tweens.push(tween);
  }

  removeTween(tween){
    this._tweensToDelete.push(tween);
  }

  _remove(tween){
    let index = this.tweens.indexOf(tween);
    if(index !== -1) this.tweens.splice(index, 1);
  }

  _getDeltaMS(){
    if(this._last === 0)this._last = Date.now();
    let now = Date.now();
    let deltaMS = now-this._last;
    this._last = now;
    return deltaMS;
  }
}
<|endoftext|>


<commit_before><commit_msg>Created a super simple service for simple redirects on authorization that we can reuse<commit_after><|endoftext|>


<commit_before><commit_msg>Use requireType instead of suppressing goog.require in goog.i18n.TimeZone. RELNOTES: none<commit_after><|endoftext|>


<commit_before>'use strict';

var doc = global.document;
var ui = require('./ui');
var util = require('./util');
var configure = require('./configure');
var Editor = require('./Editor');
var nextId = 0;

function convertTabs () {
  util.addEventDelegate(doc, 'pmk-input', 'keydown', ui.convertTabs);
}

function ponymark (containers) {
  var postfix = nextId++;
  var editor;

  if (Object.prototype.toString.call(containers) !== '[object Object]') {
    containers = {
      buttons: containers,
      input: containers,
      preview: containers
    };
  }

  markup(containers, postfix);

  editor = new Editor(postfix);
  editor.run();

  return editor.api;
}

function markup (containers, postfix) {
  var buttonBar = doc.createElement('div');
  var preview = doc.createElement('div');
  var input = doc.createElement('textarea');

  buttonBar.id = 'pmk-buttons-' + postfix;
  buttonBar.className = 'pmk-buttons';
  preview.id = 'pmk-preview-' + postfix;
  preview.className = 'pmk-preview';
  input.id = 'pmk-input-' + postfix;
  input.className = 'pmk-input';
  input.placeholder = containers.placeholder || containers.input.getAttribute('placeholder') || '';

  containers.buttons.appendChild(buttonBar);
  containers.input.appendChild(input);
  containers.preview.appendChild(preview);
}

module.exports = ponymark;

ponymark.Editor = Editor;
ponymark.convertTabs = convertTabs;
ponymark.configure = configure;
<commit_msg>rearrange options<commit_after>'use strict';

var doc = global.document;
var ui = require('./ui');
var util = require('./util');
var configure = require('./configure');
var Editor = require('./Editor');
var nextId = 0;

function convertTabs () {
  util.addEventDelegate(doc, 'pmk-input', 'keydown', ui.convertTabs);
}

function ponymark (o) {
  var postfix = nextId++;
  var editor;

  if (Object.prototype.toString.call(o) !== '[object Object]') {
    o = {
      buttons: o,
      input: o,
      preview: o
    };
  }

  markup(o, postfix);

  editor = new Editor(postfix);
  editor.run();

  return editor.api;
}

function markup (o, postfix) {
  var buttonBar = doc.createElement('div');
  var preview = doc.createElement('div');
  var existing = o.input && /textarea/i.test(o.input.tagName);
  var input;

  if (!existing) {
    input = doc.createElement('textarea');
    input.className = 'pmk-input';
    input.placeholder = o.placeholder || o.input.getAttribute('placeholder') || '';
  } else {
    input = o.input;
  }
  input.id = 'pmk-input-' + postfix;

  buttonBar.id = 'pmk-buttons-' + postfix;
  buttonBar.className = 'pmk-buttons';
  preview.id = 'pmk-preview-' + postfix;
  preview.className = 'pmk-preview';

  o.buttons.appendChild(buttonBar);

  if (!existing) {
    o.input.appendChild(input);
  }

  o.preview.appendChild(preview);
}

module.exports = ponymark;

ponymark.Editor = Editor;
ponymark.convertTabs = convertTabs;
ponymark.configure = configure;
<|endoftext|>


<commit_before>/*
	Copyright (c) 2011 Ternary Labs. All Rights Reserved.

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
*/

/**
	* @fileOverview Porthole, a small library for secure cross-domain iFrame communication.
	* @author Georges Auberger
	*/

/*
# Websequencediagrams.com
participant abc.com
participant "iFrame proxy xyz.com"
participant "iFrame proxy abc.com"
participant "iFrame xyz.com"
abc.com->iFrame proxy xyz.com: postMessage(data, targetOrigin)
note left of "iFrame proxy xyz.com": Set url fragment and change size
iFrame proxy xyz.com->iFrame proxy xyz.com: onResize Event
note right of "iFrame proxy xyz.com": read url fragment
iFrame proxy xyz.com->iFrame xyz.com: forwardMessageEvent(event)
iFrame xyz.com->iFrame proxy abc.com: postMessage(data, targetOrigin)
note right of "iFrame proxy abc.com": Set url fragment and change size
iFrame proxy abc.com->iFrame proxy abc.com: onResize Event
note right of "iFrame proxy abc.com": read url fragment
iFrame proxy abc.com->abc.com: forwardMessageEvent(event)
*/

/**
 * Namespace for Porthole, a small library for secure cross-domain iFrame communication.
 */
var Porthole = (typeof Porthole == "undefined") || !Porthole ? {} : Porthole;

// Support testing some code in node.js:
var window = (typeof window == "undefined") ? this : window;

Porthole = {
	/**
	 * Utility function to output to console
	 * @private
	 */
	trace: function(s) {
	  try { console.log("Porthole: " + s); } catch (e) { }
	},

	/**
	 * Utility function to output to console
	 * @private
	 */
	error: function(s) {
	  try { console.error("Porthole: " + s); } catch (e) { }
	}
};
/**
 * Proxy window object to post message to target window
 *
 * @constructor
 * @param proxyIFrameUrl
 * @param targetWindowName
 */
Porthole.WindowProxy = function(){};

Porthole.WindowProxy.prototype = {
/**
 * Post a message to the target window only if the content comes from the target origin.
 * targetOrigin can be a url or *
 * @public
 * @param {String} data
 * @param {String} targetOrigin
 */
	postMessage : function() {},
/**
 * Add an event listener to receive messages.
 * @public
 * @param {Function} eventListenerCallback
 * @returns {Function} eventListenerCallback
 */
	addEventListener: function(f) {},
/**
 * Remove an event listener.
 * @public
 * @param {Function} eventListenerCallback
 */
	removeEventListener: function(f) {}
};

/**
 * Legacy browser implementation of proxy window object to post message to target window
 *
 * @private
 * @constructor
 * @param proxyIFrameUrl
 * @param targetWindowName
 */
Porthole.WindowProxyLegacy = function(proxyIFrameUrl, targetWindowName) {
	if (targetWindowName === undefined) {
		targetWindowName = '';
	}
	this.targetWindowName = targetWindowName;

	this.eventListeners = [];
	this.origin = window.location.protocol + '//' + window.location.host;
	if (proxyIFrameUrl !== null) {
		this.proxyIFrameName = this.targetWindowName + 'ProxyIFrame';
		this.proxyIFrameLocation = proxyIFrameUrl;

		// Create the proxy iFrame and add to dom
		this.proxyIFrameElement = this.createIFrameProxy();
	} else {
		// Won't be able to send messages
		this.proxyIFrameElement = null;
	}
};

Porthole.WindowProxyLegacy.prototype = {
	getTargetWindowName: function() {
		return this.targetWindowName;
	},

	getOrigin: function() {
		return this.origin;
	},

	/**
	 * Create an iframe and load the proxy
	 *
	 * @private
	 * @returns iframe
	 */
	createIFrameProxy: function() {
		var iframe = document.createElement("iframe");
		iframe.setAttribute('id', this.proxyIFrameName);
		iframe.setAttribute('name', this.proxyIFrameName);
		iframe.setAttribute('src', this.proxyIFrameLocation);
		iframe.setAttribute('frameBorder', '1'); // IE needs this otherwise resize event is not fired
		iframe.setAttribute('scrolling', 'auto');
		iframe.setAttribute('width', 30);	// Need a certain size othwerise IE7 does not fire resize event
		iframe.setAttribute('height', 30);
		iframe.setAttribute('style', "position: absolute; left: -100px; top:0px;");
		// IE needs this because setting style attribute is broken. No really.
		if (iframe.style.setAttribute) {
			iframe.style.setAttribute('cssText', "position: absolute; left: -100px; top:0px;");
		}
		document.body.appendChild(iframe);
		return iframe;
	},

	postMessage: function(data, targetOrigin) {
		if (targetOrigin === undefined) {
			targetOrigin = '*';
		}
		if (this.proxyIFrameElement === null) {
			Porthole.error("Can't send message because no proxy url was passed in the constructor");
		} else {
			sourceWindowName = window.name;
			this.proxyIFrameElement.setAttribute('src', this.proxyIFrameLocation + '#' + data +
				'&sourceOrigin=' + escape(this.getOrigin()) +
				'&targetOrigin=' + escape(targetOrigin) +
				'&sourceWindowName=' + sourceWindowName +
				'&targetWindowName=' + this.targetWindowName);
			this.proxyIFrameElement.height = this.proxyIFrameElement.height > 50 ? 50 : 100;
		}
	},

	addEventListener: function(f) {
		this.eventListeners.push(f);
		return f;
	},

	removeEventListener: function(f) {
		try {
			var index = this.eventListeners.indexOf(f);
			this.eventListeners.splice(index, 1);
		} catch(e) {
			this.eventListeners = [];
			Porthole.error(e);
		}
	},

	dispatchEvent: function(e) {
		for (var i = 0; i < this.eventListeners.length; i++) {
			try {
				this.eventListeners[i](e);
			} catch(ex) {
				Porthole.error("Exception trying to call back listener: " + ex);
			}
	  }
	}
};

/**
	* Implementation for modern browsers that supports it
	*/
Porthole.WindowProxyHTML5 = function(proxyIFrameUrl, targetWindowName) {
	if (targetWindowName === undefined) {
		targetWindowName = '';
	}
	this.targetWindowName = targetWindowName;
};

Porthole.WindowProxyHTML5.prototype = {
	postMessage: function(data, targetOrigin) {
		if (targetOrigin === undefined) {
			targetOrigin = '*';
		}

		// Lookup window object from target window name
		if (this.targetWindowName === '') {
			targetWindow = top;
		} else if (this.targetWindowName === 'top' || this.targetWindowName === 'parent') {
			targetWindow = window[this.targetWindowName];
		} else {
			targetWindow = parent.frames[this.targetWindowName];
		}
		targetWindow.postMessage(data, targetOrigin);
	},
	addEventListener: function(f) {
		window.addEventListener("message", f, false);
		return f;
	},
	removeEventListener: function(f) {
		window.removeEventListener("message", f, false);
	},
	dispatchEvent: function(e) {
		var evt = document.createEvent("MessageEvent");
		evt.initMessageEvent("message", true, true, e.data, e.origin, 1, window, null);
		window.dispatchEvent(evt);
	}
};

if (typeof window.postMessage != 'function') {
	Porthole.trace("Using legacy browser support");
	Porthole.WindowProxy = Porthole.WindowProxyLegacy;
	Porthole.WindowProxy.prototype = Porthole.WindowProxyLegacy.prototype;
} else {
	Porthole.trace("Using built-in browser support");
	Porthole.WindowProxy = Porthole.WindowProxyHTML5;
	Porthole.WindowProxy.prototype = Porthole.WindowProxyHTML5.prototype;
}
Porthole.WindowProxy.prototype.post = function(data) {
    this.postMessage(Porthole.WindowProxy.serialize(data));
};

/**
	* Convinience method to split a message of type param=value&param2=value2
	* and return an array such as ['param':value, 'param2':value2]
	*
	* @param {String} message
	* @returns {Array} key value pair array
	*/
Porthole.WindowProxy.splitMessageParameters = function(message) {
	if (typeof message == 'undefined' || message === null) {
		return null;
	}
	var hash = {};
	var pairs = message.split(/&/);
	for (var keyValuePairIndex in pairs) {
        if (pairs.hasOwnProperty(keyValuePairIndex)) {
		    var nameValue = pairs[keyValuePairIndex].split('=');
		    if (typeof(nameValue[1]) == 'undefined') {
			    hash[nameValue[0]] = '';
		    } else {
			    hash[nameValue[0]] = nameValue[1];
		    }
        }
	}
	return hash;
};

/**
 * Serialize an object using JSON.stringify
 *
 * @param {Object} obj The object to be serialized
 * @return {String}
 */
Porthole.WindowProxy.serialize = function(obj) {
    if (typeof JSON === 'undefined') {
        throw new Error('Porthole serialization depends on JSON!');
    }

    return JSON.stringify(obj);
};

/**
 * Unserialize using JSON.parse
 *
 * @param {String} text Serialization
 * @return {Object}
 */
Porthole.WindowProxy.unserialize =  function(text) {
    if (typeof JSON === 'undefined') {
        throw new Error('Porthole unserialization dependens on JSON!');
    }

    return JSON.parse(text);
};

/**
	* Event object to be passed to registered event handlers
	* @param {String} data
	* @param {String} origin url of window sending the message
	* @param {Object} source window object sending the message
	*/
Porthole.MessageEvent = function MessageEvent(data, origin, source) {
	this.data = data;
	this.origin = origin;
	this.source = source;
};

/**
	* Dispatcher object to relay messages.
	* @public
	* @constructor
	*/
Porthole.WindowProxyDispatcher = {
	/**
		* Forward a message event to the target window
		* @private
		*/
	forwardMessageEvent: function(e) {
		var message = document.location.hash;
		if (message.length > 0) {
			// Eat the hash character
			message = message.substr(1);

			m = Porthole.WindowProxyDispatcher.parseMessage(message);

			if (m.targetWindowName === '') {
				targetWindow = top;
			} else if (m.targetWindowName === 'top' || m.targetWindowName === 'parent') {
				targetWindow = window[m.targetWindowName];
			} else {
				targetWindow = parent.frames[m.targetWindowName];
			}

			var windowProxy = Porthole.WindowProxyDispatcher.findWindowProxyObjectInWindow(targetWindow, m.sourceWindowName);

			if (windowProxy) {
				if (windowProxy.origin == m.targetOrigin || m.targetOrigin == '*') {
					e = new Porthole.MessageEvent(m.data, m.sourceOrigin, windowProxy);
					windowProxy.dispatchEvent(e);
				} else {
					Porthole.error("Target origin " + windowProxy.origin + " does not match desired target of " + m.targetOrigin);
				}
			} else {
				Porthole.error("Could not find window proxy object on the target window");
			}
		}
	},

	parseMessage: function(message) {
		if (typeof message == 'undefined' || message === null) {
			return null;
		}
		params = Porthole.WindowProxy.splitMessageParameters(message);
		var h = {targetOrigin:'', sourceOrigin:'', sourceWindowName:'', data:''};
		h.targetOrigin = unescape(params.targetOrigin);
		h.sourceOrigin = unescape(params.sourceOrigin);
		h.sourceWindowName = unescape(params.sourceWindowName);
		h.targetWindowName = unescape(params.targetWindowName);
		var d = message.split(/&/);
		if (d.length > 3) {
			d.pop();
			d.pop();
			d.pop();
			d.pop();
			h.data = d.join('&');
		}
		return h;
	},

	/**
		* Look for a window proxy object in the target window
		* @private
		*/
	findWindowProxyObjectInWindow: function(w, sourceWindowName) {
		// IE does not enumerate global objects on the window object
		if (w.RuntimeObject) {
			w = w.RuntimeObject();
		}
		if (w) {
			for (var i in w) {
				if (w.hasOwnProperty(i)) {
					try {
						// Ensure that we're finding the proxy object that is declared to be targetting the window that is calling us
						if (w[i] !== null && typeof w[i] == "object" && w[i] instanceof w.Porthole.WindowProxy &&
									w[i].getTargetWindowName() == sourceWindowName) {
							return w[i];
						}
					} catch(e) {
						// Swallow exception in case we access an object we shouldn't
					}
				}
			}
		}
		return null;
	},

	/**
	 * Start a proxy to relay messages.
	 * @public
	 */
	start: function() {
		if (window.addEventListener) {
			window.addEventListener('resize', Porthole.WindowProxyDispatcher.forwardMessageEvent, false);
		} else if (document.body.attachEvent) {
			window.attachEvent('onresize', Porthole.WindowProxyDispatcher.forwardMessageEvent);
		} else {
			// Should never happen
			Porthole.error("Can't attach resize event");
		}
	}
};

// Support testing in node.js:
if (typeof exports != "undefined") {
    exports.Porthole = Porthole;
}
<commit_msg>wrap code<commit_after>/*
	Copyright (c) 2011 Ternary Labs. All Rights Reserved.

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
*/

/**
	* @fileOverview Porthole, a small library for secure cross-domain iFrame communication.
	* @author Georges Auberger
	*/

/*
# Websequencediagrams.com
participant abc.com
participant "iFrame proxy xyz.com"
participant "iFrame proxy abc.com"
participant "iFrame xyz.com"
abc.com->iFrame proxy xyz.com: postMessage(data, targetOrigin)
note left of "iFrame proxy xyz.com": Set url fragment and change size
iFrame proxy xyz.com->iFrame proxy xyz.com: onResize Event
note right of "iFrame proxy xyz.com": read url fragment
iFrame proxy xyz.com->iFrame xyz.com: forwardMessageEvent(event)
iFrame xyz.com->iFrame proxy abc.com: postMessage(data, targetOrigin)
note right of "iFrame proxy abc.com": Set url fragment and change size
iFrame proxy abc.com->iFrame proxy abc.com: onResize Event
note right of "iFrame proxy abc.com": read url fragment
iFrame proxy abc.com->abc.com: forwardMessageEvent(event)
*/

(function (window) {
    'use strict';

/**
 * Namespace for Porthole, a small library for secure cross-domain iFrame communication.
 */
var Porthole = (typeof Porthole === "undefined" || !Porthole) ? {} : Porthole;

Porthole = {
	/**
	 * Utility function to output to console
	 * @private
	 */
	trace: function(s) {
	  try { console.log("Porthole: " + s); } catch (e) { }
	},

	/**
	 * Utility function to output to console
	 * @private
	 */
	error: function(s) {
	  try { console.error("Porthole: " + s); } catch (e) { }
	}
};
/**
 * Proxy window object to post message to target window
 *
 * @constructor
 * @param proxyIFrameUrl
 * @param targetWindowName
 */
Porthole.WindowProxy = function(){};

Porthole.WindowProxy.prototype = {
/**
 * Post a message to the target window only if the content comes from the target origin.
 * targetOrigin can be a url or *
 * @public
 * @param {String} data
 * @param {String} targetOrigin
 */
	postMessage : function() {},
/**
 * Add an event listener to receive messages.
 * @public
 * @param {Function} eventListenerCallback
 * @returns {Function} eventListenerCallback
 */
	addEventListener: function(f) {},
/**
 * Remove an event listener.
 * @public
 * @param {Function} eventListenerCallback
 */
	removeEventListener: function(f) {}
};

/**
 * Legacy browser implementation of proxy window object to post message to target window
 *
 * @private
 * @constructor
 * @param proxyIFrameUrl
 * @param targetWindowName
 */
Porthole.WindowProxyLegacy = function(proxyIFrameUrl, targetWindowName) {
	if (targetWindowName === undefined) {
		targetWindowName = '';
	}
	this.targetWindowName = targetWindowName;

	this.eventListeners = [];
	this.origin = window.location.protocol + '//' + window.location.host;
	if (proxyIFrameUrl !== null) {
		this.proxyIFrameName = this.targetWindowName + 'ProxyIFrame';
		this.proxyIFrameLocation = proxyIFrameUrl;

		// Create the proxy iFrame and add to dom
		this.proxyIFrameElement = this.createIFrameProxy();
	} else {
		// Won't be able to send messages
		this.proxyIFrameElement = null;
	}
};

Porthole.WindowProxyLegacy.prototype = {
	getTargetWindowName: function() {
		return this.targetWindowName;
	},

	getOrigin: function() {
		return this.origin;
	},

	/**
	 * Create an iframe and load the proxy
	 *
	 * @private
	 * @returns iframe
	 */
	createIFrameProxy: function() {
		var iframe = document.createElement("iframe");
		iframe.setAttribute('id', this.proxyIFrameName);
		iframe.setAttribute('name', this.proxyIFrameName);
		iframe.setAttribute('src', this.proxyIFrameLocation);
		iframe.setAttribute('frameBorder', '1'); // IE needs this otherwise resize event is not fired
		iframe.setAttribute('scrolling', 'auto');
		iframe.setAttribute('width', 30);	// Need a certain size othwerise IE7 does not fire resize event
		iframe.setAttribute('height', 30);
		iframe.setAttribute('style', "position: absolute; left: -100px; top:0px;");
		// IE needs this because setting style attribute is broken. No really.
		if (iframe.style.setAttribute) {
			iframe.style.setAttribute('cssText', "position: absolute; left: -100px; top:0px;");
		}
		document.body.appendChild(iframe);
		return iframe;
	},

	postMessage: function(data, targetOrigin) {
		if (targetOrigin === undefined) {
			targetOrigin = '*';
		}
		if (this.proxyIFrameElement === null) {
			Porthole.error("Can't send message because no proxy url was passed in the constructor");
		} else {
			sourceWindowName = window.name;
			this.proxyIFrameElement.setAttribute('src', this.proxyIFrameLocation + '#' + data +
				'&sourceOrigin=' + escape(this.getOrigin()) +
				'&targetOrigin=' + escape(targetOrigin) +
				'&sourceWindowName=' + sourceWindowName +
				'&targetWindowName=' + this.targetWindowName);
			this.proxyIFrameElement.height = this.proxyIFrameElement.height > 50 ? 50 : 100;
		}
	},

	addEventListener: function(f) {
		this.eventListeners.push(f);
		return f;
	},

	removeEventListener: function(f) {
		try {
			var index = this.eventListeners.indexOf(f);
			this.eventListeners.splice(index, 1);
		} catch(e) {
			this.eventListeners = [];
			Porthole.error(e);
		}
	},

	dispatchEvent: function(e) {
		for (var i = 0; i < this.eventListeners.length; i++) {
			try {
				this.eventListeners[i](e);
			} catch(ex) {
				Porthole.error("Exception trying to call back listener: " + ex);
			}
	  }
	}
};

/**
	* Implementation for modern browsers that supports it
	*/
Porthole.WindowProxyHTML5 = function(proxyIFrameUrl, targetWindowName) {
	if (targetWindowName === undefined) {
		targetWindowName = '';
	}
	this.targetWindowName = targetWindowName;
};

Porthole.WindowProxyHTML5.prototype = {
	postMessage: function(data, targetOrigin) {
		if (targetOrigin === undefined) {
			targetOrigin = '*';
		}

		// Lookup window object from target window name
		if (this.targetWindowName === '') {
			targetWindow = top;
		} else if (this.targetWindowName === 'top' || this.targetWindowName === 'parent') {
			targetWindow = window[this.targetWindowName];
		} else {
			targetWindow = parent.frames[this.targetWindowName];
		}
		targetWindow.postMessage(data, targetOrigin);
	},
	addEventListener: function(f) {
		window.addEventListener("message", f, false);
		return f;
	},
	removeEventListener: function(f) {
		window.removeEventListener("message", f, false);
	},
	dispatchEvent: function(e) {
		var evt = document.createEvent("MessageEvent");
		evt.initMessageEvent("message", true, true, e.data, e.origin, 1, window, null);
		window.dispatchEvent(evt);
	}
};

if (typeof window.postMessage != 'function') {
	Porthole.trace("Using legacy browser support");
	Porthole.WindowProxy = Porthole.WindowProxyLegacy;
	Porthole.WindowProxy.prototype = Porthole.WindowProxyLegacy.prototype;
} else {
	Porthole.trace("Using built-in browser support");
	Porthole.WindowProxy = Porthole.WindowProxyHTML5;
	Porthole.WindowProxy.prototype = Porthole.WindowProxyHTML5.prototype;
}
Porthole.WindowProxy.prototype.post = function(data) {
    this.postMessage(Porthole.WindowProxy.serialize(data));
};

/**
	* Convinience method to split a message of type param=value&param2=value2
	* and return an array such as ['param':value, 'param2':value2]
	*
	* @param {String} message
	* @returns {Array} key value pair array
	*/
Porthole.WindowProxy.splitMessageParameters = function(message) {
	if (typeof message == 'undefined' || message === null) {
		return null;
	}
	var hash = {};
	var pairs = message.split(/&/);
	for (var keyValuePairIndex in pairs) {
        if (pairs.hasOwnProperty(keyValuePairIndex)) {
		    var nameValue = pairs[keyValuePairIndex].split('=');
		    if (typeof(nameValue[1]) == 'undefined') {
			    hash[nameValue[0]] = '';
		    } else {
			    hash[nameValue[0]] = nameValue[1];
		    }
        }
	}
	return hash;
};

/**
 * Serialize an object using JSON.stringify
 *
 * @param {Object} obj The object to be serialized
 * @return {String}
 */
Porthole.WindowProxy.serialize = function(obj) {
    if (typeof JSON === 'undefined') {
        throw new Error('Porthole serialization depends on JSON!');
    }

    return JSON.stringify(obj);
};

/**
 * Unserialize using JSON.parse
 *
 * @param {String} text Serialization
 * @return {Object}
 */
Porthole.WindowProxy.unserialize =  function(text) {
    if (typeof JSON === 'undefined') {
        throw new Error('Porthole unserialization dependens on JSON!');
    }

    return JSON.parse(text);
};

/**
	* Event object to be passed to registered event handlers
	* @param {String} data
	* @param {String} origin url of window sending the message
	* @param {Object} source window object sending the message
	*/
Porthole.MessageEvent = function MessageEvent(data, origin, source) {
	this.data = data;
	this.origin = origin;
	this.source = source;
};

/**
	* Dispatcher object to relay messages.
	* @public
	* @constructor
	*/
Porthole.WindowProxyDispatcher = {
	/**
		* Forward a message event to the target window
		* @private
		*/
	forwardMessageEvent: function(e) {
		var message = document.location.hash;
		if (message.length > 0) {
			// Eat the hash character
			message = message.substr(1);

			m = Porthole.WindowProxyDispatcher.parseMessage(message);

			if (m.targetWindowName === '') {
				targetWindow = top;
			} else if (m.targetWindowName === 'top' || m.targetWindowName === 'parent') {
				targetWindow = window[m.targetWindowName];
			} else {
				targetWindow = parent.frames[m.targetWindowName];
			}

			var windowProxy = Porthole.WindowProxyDispatcher.findWindowProxyObjectInWindow(targetWindow, m.sourceWindowName);

			if (windowProxy) {
				if (windowProxy.origin == m.targetOrigin || m.targetOrigin == '*') {
					e = new Porthole.MessageEvent(m.data, m.sourceOrigin, windowProxy);
					windowProxy.dispatchEvent(e);
				} else {
					Porthole.error("Target origin " + windowProxy.origin + " does not match desired target of " + m.targetOrigin);
				}
			} else {
				Porthole.error("Could not find window proxy object on the target window");
			}
		}
	},

	parseMessage: function(message) {
		if (typeof message == 'undefined' || message === null) {
			return null;
		}
		params = Porthole.WindowProxy.splitMessageParameters(message);
		var h = {targetOrigin:'', sourceOrigin:'', sourceWindowName:'', data:''};
		h.targetOrigin = unescape(params.targetOrigin);
		h.sourceOrigin = unescape(params.sourceOrigin);
		h.sourceWindowName = unescape(params.sourceWindowName);
		h.targetWindowName = unescape(params.targetWindowName);
		var d = message.split(/&/);
		if (d.length > 3) {
			d.pop();
			d.pop();
			d.pop();
			d.pop();
			h.data = d.join('&');
		}
		return h;
	},

	/**
		* Look for a window proxy object in the target window
		* @private
		*/
	findWindowProxyObjectInWindow: function(w, sourceWindowName) {
		// IE does not enumerate global objects on the window object
		if (w.RuntimeObject) {
			w = w.RuntimeObject();
		}
		if (w) {
			for (var i in w) {
				if (w.hasOwnProperty(i)) {
					try {
						// Ensure that we're finding the proxy object that is declared to be targetting the window that is calling us
						if (w[i] !== null && typeof w[i] == "object" && w[i] instanceof w.Porthole.WindowProxy &&
									w[i].getTargetWindowName() == sourceWindowName) {
							return w[i];
						}
					} catch(e) {
						// Swallow exception in case we access an object we shouldn't
					}
				}
			}
		}
		return null;
	},

	/**
	 * Start a proxy to relay messages.
	 * @public
	 */
	start: function() {
		if (window.addEventListener) {
			window.addEventListener('resize', Porthole.WindowProxyDispatcher.forwardMessageEvent, false);
		} else if (document.body.attachEvent) {
			window.attachEvent('onresize', Porthole.WindowProxyDispatcher.forwardMessageEvent);
		} else {
			// Should never happen
			Porthole.error("Can't attach resize event");
		}
	}
};

// Support testing in node.js:
if (typeof exports != "undefined") {
    exports.Porthole = Porthole;
}

})(this);
<|endoftext|>


<commit_before>import { WHITE, KING, PAWN } from './brands';
import { Board } from './board'
import { Mobility } from './piece/mobility';
import { Castling } from './castling';
import { EnPassantTarget } from './eptarget'
import { Point } from './point';
import { Promotion } from './promotion'
import {
	entries,
	identity,
	squareName,
	squareCoords,
	oppositeColor,
	bounded,
} from './util';
import {
	ChessError,
	MobilityError,
	CheckError,
	PromotionError
} from './error'

const assign = require('lodash.assign');
const contains = require('lodash.contains');

export class Position {

	constructor({
		ranks=8,
		files=8,
		activeColor=WHITE,
		castling=null,
		enPassantTarget=null,
		halfmoveClock=0,
		fullmoveClock=0,
		board=new Board(ranks, files),
	} = {}) {
		this.board = board;
		this.activeColor = activeColor;
		this.castling = castling;
		this.enPassantTarget = enPassantTarget;
		this.halfmoveClock = halfmoveClock;
		this.fullmoveClock = fullmoveClock;
		this.promotionSquare = Promotion.square(this);
	}

	beget(overrides) {
		return new Position(assign({}, this, overrides));
	}

	get files() {
		return this.board.files;
	}

	get ranks() {
		return this.board.ranks;
	}

	pieces(brand) {
		return this.board.getPieces(brand);
	}

	piece(squareName) {
		return this.pieceByCoords(squareCoords(squareName));
	}

	pieceCoords(piece) {
		return this.board.getPieceCoords(piece);
	}

	pieceByCoords(point, rotated=false) {
		return this.board.getPieceByCoords(point, rotated);
	}

	*queryAll(selector={}) {
		pieces: for (var piece of this.pieces(selector.brand)) {
			for (var [val, key] of entries(selector)) {
				if (piece[key] !== val) {
					continue pieces;
				}
			}
			yield piece;
		}
	}

	queryArray(selector) {
		return [ ...this.queryAll(selector) ];
	}

	query(selector) {
		for (var i of this.queryAll(selector)) {
			return i;
		}
		return null;
	}

	*checks(
		color=this.activeColor,
		loc=this.pieceCoords(this.query({ brand: KING, color }))
	) {
		for (var enemy of this.queryAll({ color: oppositeColor(color) })) {
			if (enemy.canCapture(this, this.pieceCoords(enemy), loc)) {
				yield enemy;
			}
		}
	}

	isCheck(color, loc) {
		for (var _ of this.checks(color, loc)) {
			return true;
		}
		return false;
	}

	isCheckmate(color=this.activeColor) {
		if (!this.isCheck(color)) {
			// it can't be checkmate if it's not even check:
			return false;
		}
		for (var ally of this.queryAll({ color })) {
			for (var move of bounded(this.board, ally.moves(this))) {
				try {
					if (!this.movePiece(ally, move).isCheck(color)) {
						return false;
					}
				}
				catch (err) {
					if (err instanceof ChessError) {
						continue;
					}
					throw err;
				}
			}
		}
		return true;
	}

	tryMovePiece(piece, target) {
		try {
			return this.movePiece(piece, target);
		}
		catch (err) {
			if (err instanceof ChessError) {
				return this;
			}
			throw err;
		}
	}

	movePiece(piece, target) {
		if (target == null || piece == null) {
			throw new Error("Argument error");
		}

		const { capturePiece, captureTarget, wasEnPassant }
			= EnPassantTarget.capturablePiece(this, piece, target);

		if (!Mobility.isLegal({
			position: this,
			piece,
			target,
			capturePiece,
		})) {
			throw new MobilityError();
		}

		const castling = Castling.analyze(this, piece, target);

		const position = this.beget({
			activeColor: oppositeColor(this.activeColor),
			castling,
			enPassantTarget: EnPassantTarget.analyze(this, piece, target),
			halfmoveClock: this.halfmoveClock + 1,
			fullmoveClock: this.fullmoveClock,
			board: this.board.map((p, square) => {
				if (p === piece) {
					// is it the square being vacated by the piece.
					return null;
				}
				if (wasEnPassant && square.equal(captureTarget)) {
					// it was just captured en passant.
					return null;
				}
				if (p && p === castling.rook) {
					// it is the rook that is being moved during castling.
					return null;
				}
				if (castling.square && square.equal(castling.square)) {
					// it is the square that the rook is being moved to during castling.
					return castling.rook;
				}
				if (square.equal(target)) {
					// it is the square that the piece is being moved to.
					return piece;
				}
				return p;
			}),
		});
		if (position.isCheck(this.activeColor)) {
			// this move is illegal, because it would put the king in check!
			throw new CheckError();
		}
		return position;
	}

	promote(prize) {
		if (this.promotionSquare == null) {
			throw new PromotionError();
		}
		const color = oppositeColor(this.activeColor);
		return this.beget({
			board: this.board.map((p, square) => {
				if (p && p.brand === PAWN && Promotion.rank(color) === square.y) {
					// it is the piece that is replacing a promoted pawn.
					return prize;
				}
				return p;
			}),
			// that we we've promoted, unset the promotion square.
			promotionSquare: null,
		});
	}
}
<commit_msg>promotion: simpler algorithm for replacing promoted pawn<commit_after>import { WHITE, KING, PAWN } from './brands';
import { Board } from './board'
import { Mobility } from './piece/mobility';
import { Castling } from './castling';
import { EnPassantTarget } from './eptarget'
import { Point } from './point';
import { Promotion } from './promotion'
import {
	entries,
	identity,
	squareName,
	squareCoords,
	oppositeColor,
	bounded,
} from './util';
import {
	ChessError,
	MobilityError,
	CheckError,
	PromotionError
} from './error'

const assign = require('lodash.assign');
const contains = require('lodash.contains');

export class Position {

	constructor({
		ranks=8,
		files=8,
		activeColor=WHITE,
		castling=null,
		enPassantTarget=null,
		halfmoveClock=0,
		fullmoveClock=0,
		board=new Board(ranks, files),
	} = {}) {
		this.board = board;
		this.activeColor = activeColor;
		this.castling = castling;
		this.enPassantTarget = enPassantTarget;
		this.halfmoveClock = halfmoveClock;
		this.fullmoveClock = fullmoveClock;
		this.promotionSquare = Promotion.square(this);
	}

	beget(overrides) {
		return new Position(assign({}, this, overrides));
	}

	get files() {
		return this.board.files;
	}

	get ranks() {
		return this.board.ranks;
	}

	pieces(brand) {
		return this.board.getPieces(brand);
	}

	piece(squareName) {
		return this.pieceByCoords(squareCoords(squareName));
	}

	pieceCoords(piece) {
		return this.board.getPieceCoords(piece);
	}

	pieceByCoords(point, rotated=false) {
		return this.board.getPieceByCoords(point, rotated);
	}

	*queryAll(selector={}) {
		pieces: for (var piece of this.pieces(selector.brand)) {
			for (var [val, key] of entries(selector)) {
				if (piece[key] !== val) {
					continue pieces;
				}
			}
			yield piece;
		}
	}

	queryArray(selector) {
		return [ ...this.queryAll(selector) ];
	}

	query(selector) {
		for (var i of this.queryAll(selector)) {
			return i;
		}
		return null;
	}

	*checks(
		color=this.activeColor,
		loc=this.pieceCoords(this.query({ brand: KING, color }))
	) {
		for (var enemy of this.queryAll({ color: oppositeColor(color) })) {
			if (enemy.canCapture(this, this.pieceCoords(enemy), loc)) {
				yield enemy;
			}
		}
	}

	isCheck(color, loc) {
		for (var _ of this.checks(color, loc)) {
			return true;
		}
		return false;
	}

	isCheckmate(color=this.activeColor) {
		if (!this.isCheck(color)) {
			// it can't be checkmate if it's not even check:
			return false;
		}
		for (var ally of this.queryAll({ color })) {
			for (var move of bounded(this.board, ally.moves(this))) {
				try {
					if (!this.movePiece(ally, move).isCheck(color)) {
						return false;
					}
				}
				catch (err) {
					if (err instanceof ChessError) {
						continue;
					}
					throw err;
				}
			}
		}
		return true;
	}

	tryMovePiece(piece, target) {
		try {
			return this.movePiece(piece, target);
		}
		catch (err) {
			if (err instanceof ChessError) {
				return this;
			}
			throw err;
		}
	}

	movePiece(piece, target) {
		if (target == null || piece == null) {
			throw new Error("Argument error");
		}

		const { capturePiece, captureTarget, wasEnPassant }
			= EnPassantTarget.capturablePiece(this, piece, target);

		if (!Mobility.isLegal({
			position: this,
			piece,
			target,
			capturePiece,
		})) {
			throw new MobilityError();
		}

		const castling = Castling.analyze(this, piece, target);

		const position = this.beget({
			activeColor: oppositeColor(this.activeColor),
			castling,
			enPassantTarget: EnPassantTarget.analyze(this, piece, target),
			halfmoveClock: this.halfmoveClock + 1,
			fullmoveClock: this.fullmoveClock,
			board: this.board.map((p, square) => {
				if (p === piece) {
					// is it the square being vacated by the piece.
					return null;
				}
				if (wasEnPassant && square.equal(captureTarget)) {
					// it was just captured en passant.
					return null;
				}
				if (p && p === castling.rook) {
					// it is the rook that is being moved during castling.
					return null;
				}
				if (castling.square && square.equal(castling.square)) {
					// it is the square that the rook is being moved to during castling.
					return castling.rook;
				}
				if (square.equal(target)) {
					// it is the square that the piece is being moved to.
					return piece;
				}
				return p;
			}),
		});
		if (position.isCheck(this.activeColor)) {
			// this move is illegal, because it would put the king in check!
			throw new CheckError();
		}
		return position;
	}

	promote(prize) {
		if (this.promotionSquare == null) {
			throw new PromotionError();
		}
		return this.beget({
			board: this.board.map((p, square) =>
				// replace the promoted pawn with the new piece:
				square.equal(this.promotionSquare) ? prize : p),
			// that we we've promoted, unset the promotion square.
			promotionSquare: null,
		});
	}
}
<|endoftext|>


<commit_before>import React, { useState, useContext } from 'react';

import { SubmissionsList, Modal, CreateForm, FlagForm } from '../components';
import axios from '../../../src/js/axiosWithCsrf';
import ProjectSubmissionContext from "../ProjectSubmissionContext";

const ProjectSubmissions = (props) => {
  const { userId, lesson, course } = useContext(ProjectSubmissionContext);
  const [showCreateModal, setShowCreateModal] = useState(false);
  const [showFlagModal, setShowFlagModal] = useState(false);
  const [submissions, setSubmissions] = useState(props.submissions);
  const [flaggedSubmission, setFlaggedSubmission] = useState({});
  const [userSubmission, setUserSubmission] = useState(props.userSubmission);

  const toggleShowFlagModal = () => setShowFlagModal(prevShowFlagModal => !prevShowFlagModal);

  const toggleShowCreateModal = () => {
    setShowCreateModal(prevShowCreateModal => !prevShowCreateModal);
  };

  const handleCreate = async (data) => {
    const { repo_url, live_preview_url, is_public } = data;

    event.preventDefault();

    const response = await axios.post(
      `/project_submissions`,
      {
        project_submission: {
          repo_url,
          live_preview_url,
          is_public,
          lesson_id: lesson.id,
        }
      }
    );
    if (response.status === 200) {
      setUserSubmission(prevSubmission => response.data);
    }
  };

  const handleUpdate = async (data) => {
    const { repo_url, live_preview_url, is_public, project_submission_id } = data;

    event.preventDefault();

    const response = await axios.put(
      `/project_submissions/${project_submission_id}`,
      {
        project_submission: {
          repo_url,
          live_preview_url,
          is_public,
          lesson_id: lesson.id,
        }
      }
    );
    if (response.status === 200) {
      setUserSubmission(prevSubmission => response.data);
    }
  };

  const handleDelete = async (id) => {
    event.preventDefault();

    const response = await axios.delete(`/project_submissions/${id}`, {});
    if (response.status === 200) {
      setUserSubmission(prevSubmissions => null);
    }
  };

  const handleFlag = async (data) => {
    const { project_submission_id, reason } = data;

    const response = await axios.post(
      `/project_submissions/${project_submission_id}/flags`,
      { reason: reason }
    );
    if (response.status === 200) {
      setFlaggedSubmission({});
    }
  };

  const toggleLikeSubmission = async (submission, isUserSubmission = false) => {
    const response = await axios.post(
      `/project_submissions/${submission.id}/likes`,
      {
        submission_id: submission.id,
        is_liked_by_current_user: submission.is_liked_by_current_user
      }
    );

    if (response.status === 200) {
      const updatedSubmission = response.data;

      if (isUserSubmission) {
        setUserSubmission(prevSubmission => updatedSubmission);
      } else {
        setSubmissions(prevSubmissions => {
          const newSubmissions = prevSubmissions.map((submission) => {
            if (updatedSubmission.id === submission.id) {
              return updatedSubmission;
            }

            return submission;
          })

          return newSubmissions;
        });
      }
    }
  };

  const showAddSubmissionButton = () => !userSubmission

  return (

Solutions:

{course.title}: ({lesson.title})

        <Modal show={showCreateModal} handleClose={toggleShowCreateModal}>
          <CreateForm
            lessonId={lesson.id}
            onSubmit={handleCreate}
            onClose={toggleShowCreateModal}
            userId={userId}
          />
        </Modal>

        <Modal show={showFlagModal} handleClose={toggleShowFlagModal}>
          <FlagForm
            submission={flaggedSubmission}
            onSubmit={handleFlag}
            onClose={toggleShowFlagModal}
            userId={userId}
          />
        </Modal>

          {showAddSubmissionButton() && (
            <button className="submissions__add button button--primary" onClick={toggleShowCreateModal}>
              Add Solution
            </button>
          )}

        This is a beta feature. If you have any feedback
        please let us know.

      <SubmissionsList
        submissions={submissions}
        userSubmission={userSubmission}
        handleUpdate={handleUpdate}
        onFlag={(submission) => { setFlaggedSubmission(submission); toggleShowFlagModal() }}
        handleDelete={handleDelete}
        handleLikeToggle={toggleLikeSubmission}
      />

  )
}

export default ProjectSubmissions;
<commit_msg>Feature: Remove Project Submissions Beta Message<commit_after>import React, { useState, useContext } from 'react';

import { SubmissionsList, Modal, CreateForm, FlagForm } from '../components';
import axios from '../../../src/js/axiosWithCsrf';
import ProjectSubmissionContext from "../ProjectSubmissionContext";

const ProjectSubmissions = (props) => {
  const { userId, lesson, course } = useContext(ProjectSubmissionContext);
  const [showCreateModal, setShowCreateModal] = useState(false);
  const [showFlagModal, setShowFlagModal] = useState(false);
  const [submissions, setSubmissions] = useState(props.submissions);
  const [flaggedSubmission, setFlaggedSubmission] = useState({});
  const [userSubmission, setUserSubmission] = useState(props.userSubmission);

  const toggleShowFlagModal = () => setShowFlagModal(prevShowFlagModal => !prevShowFlagModal);

  const toggleShowCreateModal = () => {
    setShowCreateModal(prevShowCreateModal => !prevShowCreateModal);
  };

  const handleCreate = async (data) => {
    const { repo_url, live_preview_url, is_public } = data;

    event.preventDefault();

    const response = await axios.post(
      `/project_submissions`,
      {
        project_submission: {
          repo_url,
          live_preview_url,
          is_public,
          lesson_id: lesson.id,
        }
      }
    );
    if (response.status === 200) {
      setUserSubmission(prevSubmission => response.data);
    }
  };

  const handleUpdate = async (data) => {
    const { repo_url, live_preview_url, is_public, project_submission_id } = data;

    event.preventDefault();

    const response = await axios.put(
      `/project_submissions/${project_submission_id}`,
      {
        project_submission: {
          repo_url,
          live_preview_url,
          is_public,
          lesson_id: lesson.id,
        }
      }
    );
    if (response.status === 200) {
      setUserSubmission(prevSubmission => response.data);
    }
  };

  const handleDelete = async (id) => {
    event.preventDefault();

    const response = await axios.delete(`/project_submissions/${id}`, {});
    if (response.status === 200) {
      setUserSubmission(prevSubmissions => null);
    }
  };

  const handleFlag = async (data) => {
    const { project_submission_id, reason } = data;

    const response = await axios.post(
      `/project_submissions/${project_submission_id}/flags`,
      { reason: reason }
    );
    if (response.status === 200) {
      setFlaggedSubmission({});
    }
  };

  const toggleLikeSubmission = async (submission, isUserSubmission = false) => {
    const response = await axios.post(
      `/project_submissions/${submission.id}/likes`,
      {
        submission_id: submission.id,
        is_liked_by_current_user: submission.is_liked_by_current_user
      }
    );

    if (response.status === 200) {
      const updatedSubmission = response.data;

      if (isUserSubmission) {
        setUserSubmission(prevSubmission => updatedSubmission);
      } else {
        setSubmissions(prevSubmissions => {
          const newSubmissions = prevSubmissions.map((submission) => {
            if (updatedSubmission.id === submission.id) {
              return updatedSubmission;
            }

            return submission;
          })

          return newSubmissions;
        });
      }
    }
  };

  const showAddSubmissionButton = () => !userSubmission

  return (

Solutions:

{course.title}: ({lesson.title})

        <Modal show={showCreateModal} handleClose={toggleShowCreateModal}>
          <CreateForm
            lessonId={lesson.id}
            onSubmit={handleCreate}
            onClose={toggleShowCreateModal}
            userId={userId}
          />
        </Modal>

        <Modal show={showFlagModal} handleClose={toggleShowFlagModal}>
          <FlagForm
            submission={flaggedSubmission}
            onSubmit={handleFlag}
            onClose={toggleShowFlagModal}
            userId={userId}
          />
        </Modal>

          {showAddSubmissionButton() && (
            <button className="submissions__add button button--primary" onClick={toggleShowCreateModal}>
              Add Solution
            </button>
          )}

      <SubmissionsList
        submissions={submissions}
        userSubmission={userSubmission}
        handleUpdate={handleUpdate}
        onFlag={(submission) => { setFlaggedSubmission(submission); toggleShowFlagModal() }}
        handleDelete={handleDelete}
        handleLikeToggle={toggleLikeSubmission}
      />

  )
}

export default ProjectSubmissions;
<|endoftext|>


<commit_before>'use strict';
var assert = require('chai').assert;
var path = require('path');
var Librarian = require('../');

describe('Librarian', function(){

    var NOOP = function(){};

    it('should expose constructor', function(){
        assert.isFunction(Librarian);
    });

    it('should not require new keyword', function(){
        var l = Librarian();
        assert.instanceOf(l, Librarian);
    });

    it('should have a DEFAULTS object', function(){
        assert.isObject(Librarian.DEFAULTS);
    });

    xdescribe('#use', function(){
        it('should add plugin to stack', function(){
            var l = Librarian();
            l.use(NOOP);
            assert.equal(l.plugins.length, 1);
        });
    });

    describe('#directory', function(){

        it('should set a working directory by default equal to process.env.PWD', function(){
            var l = Librarian();
            assert.equal(l.directory(), process.env.PWD);
        });

        it('should set the working directory', function(){
            var l = Librarian({directory:'dir'});
            assert.ok(l.directory(), 'dir');
        });

        it('should respect absolute directories', function(){
            var l = Librarian({directory:'/dir'});
            assert.ok(l.directory(), '/dir');
        });
    });

    describe('#source', function(){
        it('should set a "source" directory in DEFAULTS', function(){
            var l = Librarian();
            assert.ok(l.source(), Librarian.DEFAULTS.source);
        });

        it('should set the "source" directory', function(){
            var l = Librarian({source:'dir'});
            assert.ok(l.directory(), 'dir');
        });

        it('should get full path of source directory', function(){
            var l = Librarian();
            var absoluteBuildPath = path.join(process.env.PWD, '/build');
            assert.ok(l.source(), absoluteBuildPath);
        });

        it('should respect absolute directories', function(){
            var l = Librarian({source:'/dir'});
            assert.ok(l.source(), '/dir');
        });

        it('should throw on non strings', function(){
            var l = Librarian();
            assert.throws(function(){
                l.source(23);
            });
        });
    });

    describe('#destination', function(){
        it('should set a destination directory in DEFAULTS', function(){
            var l = Librarian();
            assert.ok(l.destination(), Librarian.DEFAULTS.destination);
        });

        it('should get full path of destination directory', function(){
            var l = Librarian();
            var absoluteBuildPath = path.join(process.env.PWD, '/build');
            assert.ok(l.destination(), absoluteBuildPath);
        });

        it('should respect absolute directories', function(){
            var l = Librarian({destination:'/dir'});
            assert.ok(l.destination(), '/dir');
        });

        it('should throw on non strings', function(){
            var l = Librarian();
            assert.throws(function(){
                l.destination(23);
            });
        });
    });

    describe('#clean', function(){
        it('should set the "clean" default used in DEFAULTS', function(){
            var l = Librarian();
            assert.equal(l.clean(), Librarian.DEFAULTS.clean);
        });

        it('should set the "clean" option', function(){
            var l = Librarian();
            l.clean(false);
            assert.equal(l.clean(), false);
        });

        it('should throw on on boolean', function(){
            var l = Librarian();
            assert.throws(function(){
                l.clean(23);
            });
        });
    });

    describe('#frontmatter', function(){
        it('should set the "frontmatter" default used in DEFAULTS', function(){
            var l = Librarian();
            assert.equal(l.frontmatter(), Librarian.DEFAULTS.frontmatter);
        });

        it('should set the "frontmatter" option', function(){
            var l = Librarian({frontmatter: true});
            assert.equal(l.frontmatter(), true)
        });

        it('should set the "frontmatter"', function(){
            var l = Librarian();
            l.frontmatter(true);
            assert.equal(l.frontmatter(), true)
        });

        it('should throw on on boolean', function(){
            var l = Librarian();
            assert.throws(function(){
                l.frontmatter(23);
            });
        });
    });

    describe('#metadata', function(){
        it('should set the "metadata" default used in DEFAULTS', function(){
            var l = Librarian();
            assert.deepEqual(l.metadata(), Librarian.DEFAULTS.metadata);
        });

        it('should set the "metadata" option', function(){
            var meta = {
                user: 'goliatone',
                url:'http://goliatone.com'
            };

            var l = Librarian({metadata: meta});
            assert.deepEqual(l.metadata(), meta);
        });

        it('should get "metadata"', function(){
            var l = Librarian();
            assert.deepEqual(l.metadata(), {});
        });

        it('should set "metadata" clone', function(){
            var meta = {
                user: 'goliatone',
                url:'http://goliatone.com'
            };
            var l = Librarian();
            l.metadata(meta);
            assert.notEqual(l.metadata(), meta);
            assert.deepEqual(l.metadata(), meta);
        });
    });
});<commit_msg>TESTS: wip...<commit_after>'use strict';
var assert = require('chai').assert;
var fs = require('fs');
var path = require('path');
var fixture = path.resolve.bind(path, __dirname, 'fixtures');

var Librarian = require('../');

describe('Librarian', function(){

    var NOOP = function(){};

    it('should expose constructor', function(){
        assert.isFunction(Librarian);
    });

    it('should not require new keyword', function(){
        var l = Librarian();
        assert.instanceOf(l, Librarian);
    });

    it('should have a DEFAULTS object', function(){
        assert.isObject(Librarian.DEFAULTS);
    });

    it('should take an options object', function(){
        var options = {directory:'my-directory'};
        var l = Librarian(options);
        assert.ok(l.directory(), 'my-directory');
    });

    it('should take a single string argument that will be the working directory', function(){
        //this might change!
        var l = Librarian('my-directory');
        assert.ok(l.directory(), 'my-directory');
    });

    xdescribe('#use', function(){
        it('should add plugin to stack', function(){
            var l = Librarian();
            l.use(NOOP);
            assert.equal(l.plugins.length, 1);
        });
    });

    describe('#directory', function(){

        it('should set a working directory by default equal to process.env.PWD', function(){
            var l = Librarian();
            assert.equal(l.directory(), process.env.PWD);
        });

        it('should set the working directory', function(){
            var l = Librarian({directory:'dir'});
            assert.ok(l.directory(), 'dir');
        });

        it('should respect absolute directories', function(){
            var l = Librarian({directory:'/dir'});
            assert.ok(l.directory(), '/dir');
        });
    });

    describe('#source', function(){
        it('should set a "source" directory in DEFAULTS', function(){
            var l = Librarian();
            assert.ok(l.source(), Librarian.DEFAULTS.source);
        });

        it('should set the "source" directory', function(){
            var l = Librarian({source:'dir'});
            assert.ok(l.directory(), 'dir');
        });

        it('should get full path of source directory', function(){
            var l = Librarian();
            var absoluteBuildPath = path.join(process.env.PWD, '/build');
            assert.ok(l.source(), absoluteBuildPath);
        });

        it('should respect absolute directories', function(){
            var l = Librarian({source:'/dir'});
            assert.ok(l.source(), '/dir');
        });

        it('should throw on non strings', function(){
            var l = Librarian();
            assert.throws(function(){
                l.source(23);
            });
        });
    });

    describe('#destination', function(){
        it('should set a destination directory in DEFAULTS', function(){
            var l = Librarian();
            assert.ok(l.destination(), Librarian.DEFAULTS.destination);
        });

        it('should get full path of destination directory', function(){
            var l = Librarian();
            var absoluteBuildPath = path.join(process.env.PWD, '/build');
            assert.ok(l.destination(), absoluteBuildPath);
        });

        it('should respect absolute directories', function(){
            var l = Librarian({destination:'/dir'});
            assert.ok(l.destination(), '/dir');
        });

        it('should throw on non strings', function(){
            var l = Librarian();
            assert.throws(function(){
                l.destination(23);
            });
        });
    });

    describe('#clean', function(){
        it('should set the "clean" default used in DEFAULTS', function(){
            var l = Librarian();
            assert.equal(l.clean(), Librarian.DEFAULTS.clean);
        });

        it('should set the "clean" option', function(){
            var l = Librarian();
            l.clean(false);
            assert.equal(l.clean(), false);
        });

        it('should throw on on boolean', function(){
            var l = Librarian();
            assert.throws(function(){
                l.clean(23);
            });
        });
    });

    describe('#frontmatter', function(){
        it('should set the "frontmatter" default used in DEFAULTS', function(){
            var l = Librarian();
            assert.equal(l.frontmatter(), Librarian.DEFAULTS.frontmatter);
        });

        it('should initialize the "frontmatter" option', function(){
            var l = Librarian({frontmatter: true});
            assert.equal(l.frontmatter(), true)
        });

        it('should set the "frontmatter"', function(){
            var l = Librarian();
            l.frontmatter(true);
            assert.equal(l.frontmatter(), true)
        });

        it('should throw on on boolean', function(){
            var l = Librarian();
            assert.throws(function(){
                l.frontmatter(23);
            });
        });
    });

    describe('#metadata', function(){
        it('should set the "metadata" default used in DEFAULTS', function(){
            var l = Librarian();
            assert.deepEqual(l.metadata(), Librarian.DEFAULTS.metadata);
        });

        it('should initialize the "metadata" option', function(){
            var meta = {
                user: 'goliatone',
                url:'http://goliatone.com'
            };

            var l = Librarian({metadata: meta});
            assert.deepEqual(l.metadata(), meta);
        });

        it('should get "metadata"', function(){
            var l = Librarian();
            assert.deepEqual(l.metadata(), {});
        });

        it('should set "metadata" clone', function(){
            var meta = {
                user: 'goliatone',
                url:'http://goliatone.com'
            };
            var l = Librarian();
            l.metadata(meta);
            assert.notEqual(l.metadata(), meta);
            assert.deepEqual(l.metadata(), meta);
        });
    });

    describe('#attributes', function(){
        it('should set the "attributes" default used in DEFAULTS', function(){
            var l = Librarian();
            assert.deepEqual(l._attributes, Librarian.DEFAULTS.attributes);
        });

        it('should initialize the "attributes" option', function(){
            var attributes = ['stats', 'content'];
            var l = Librarian({attributes: attributes});
            assert.ok(l.attributes(), attributes);
        });

        it('should get "attributes" option', function(){
            var l = Librarian();
            assert.deepEqual(l.attributes(), Librarian.DEFAULTS.attributes);
        });

        it('should set "attributes" option', function(){
            var l = Librarian();
            var attributes = ['stats', 'content'];
            l.attributes(attributes);
            assert.ok(l.attributes(), attributes);
        });
    });

    describe('#path', function(){
        it('should return a path relative to the working directory', function(){
            var l = Librarian({source:'test/tmp'});
            var rel = l.path('one', 'two', 'three');
            assert.ok(rel, '/test/tmp/one/two/three');
        });
    });

    describe('#read', function(){
        it('should read from a source directory', function(done){
            var l = Librarian({
                directory: fixture('read')
            });
            var stats = fs.statSync(fixture('read/src/index.md'));

            l.read(function(err, files){
                if(err) return done(err);
                assert.ok(files, {
                    'index.md': {
                        title: 'A Title',
                        contents: new Buffer('body'),
                        mode: stats.mode.toString(8).slice(-4),
                        stats:stats,
                        isUtf8: true
                    }
                });
                done();
            });
        });

        it('should read from a provided directory', function(done){
            var l = Librarian({
                directory: fixture('read-dir')
            });
            var stats = fs.statSync(fixture('read-dir/dir/index.md'));
            var dir = fixture('read-dir/dir');
            l.read(dir, function(err, files){
                if(err) done(err);
                assert.ok(files, {
                    'index.md': {
                        title: 'A Title',
                        contents: new Buffer('body'),
                        mode: stats.mode.toString(8).slice(-4),
                        stats:stats,
                        isUtf8: true
                    }
                });
            });
            done();
        });

        it('should preserve an existing file mode', function(done){
            var l = Librarian({
                directory: fixture('read-mode')
            });
            var stats = fs.statSync(fixture('read-mode/src/bin'));

            l.read(function(err, files){
                if(err) done(err);
                assert.ok(files, {
                    'bin': {
                        contents: new Buffer('echo test'),
                        mode: stats.mode.toString(8).slice(-4),
                        stats: stats,
                        isUtf8: false
                    }
                });
            });
            done();
        });

        describe('should expose isUtf8 metadata property', function(){
            it('should be false for binary files', function(done){
                var l = Librarian({
                    directory: fixture('read-isUtf8-false')
                });

                l.read(function(err, files){
                    if(err) done(err);
                    assert.isFalse(files['image.png'].isUtf8);
                });
                done();
            });

            it('should be true for text files', function(done){
                var l = Librarian({
                    directory: fixture('read-isUtf8-true')
                });

                l.read(function(err, files){
                    if(err) done(err);
                    assert.isTrue(files['index.md'].isUtf8);
                });
                done();
            });
        });

        it('should expose attributes in each file metadata', function(done){
            var l = Librarian({
                directory: fixture('expose-attributes')
            });
            l.read(function(err, files){
                if(err) done(err);
                var file = files['index.md'];
                Librarian.DEFAULTS.attributes.map(function(attr){
                    assert.property(file, attr, attr);
                });
            });
            done();
        });

        it('should not parse front-matter if "frontmatter" is false', function(done){
            var l = Librarian({
                directory: fixture('read-frontmatter'),
                frontmatter: false
            });
            l.read(function(err, files){
                if(err) done(err);
                assert.isUndefined(files['index.md'].title);
            });
            done();
        });
    });
});<|endoftext|>