<commit_before>"use strict";

$.ajaxSetup({
    cache: false,
    contentType: 'text/plain',
    dataType: 'json',
    headers: { 'X-WebKDC-Request' : 'OK' },
    type: 'POST',
});

var Crypto = {};

Crypto.toBase64 = function(str) {
    return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Latin1.parse(str));
};

Crypto.fromBase64 = function(str) {
    return CryptoJS.enc.Latin1.stringify(CryptoJS.enc.Base64.parse(str));
};

Crypto.randomNonce = function() {
    try {
        var word = sjcl.random.randomWords(1)[0];
	// Twos-complement it if negative.
	if (word < 0)
	    word += 0x80000000;
	return word;
    } catch (e) {
        if (e instanceof sjcl.exception.notReady) {
            // TODO: We should retry a little later. We can also
            // adjust the paranoia argument.
            window.setTimeout(function () { alert(String(e)); });
            return;
        }
        throw e;
    }
};

var KDC = {};

KDC.urlBase = '/kdc/v1/';
KDC.realm = 'ATHENA.MIT.EDU'; // XXX

KDC.asReq = function(username, success, error) {
    var asReq = {};
    asReq.pvno = krb.pvno;
    asReq.msgType = krb.KRB_MT_AS_REQ;
    // TODO: Implement pre-authentication and everything.
    // asReq.padata = []; // Omit if empty.

    // FIXME: This is obnoxious. Also constants.
    asReq.reqBody = {};
    // TODO: Pick a reasonable set of flags. These are just taken from
    // a wireshark trace.
    asReq.reqBody.kdcOptions = krb.KDCOptions.make(
        krb.KDCOptions.forwardable,
        krb.KDCOptions.proxiable,
        krb.KDCOptions.renewable_ok);

    asReq.reqBody.principalName = {};
    asReq.reqBody.principalName.nameType = krb.KRB_NT_PRINCIPAL;
    asReq.reqBody.principalName.nameString = [ username ];

    asReq.reqBody.realm = KDC.realm;

    asReq.reqBody.sname = {};
    asReq.reqBody.sname.nameType = krb.KRB_NT_SRV_INST;
    asReq.reqBody.sname.nameString = [ 'krbtgt', KDC.realm ];

    var now = new Date();
    now.setUTCMilliseconds(0);
    var later = new Date(Date.UTC(now.getUTCFullYear(),
                                  now.getUTCMonth(),
                                  now.getUTCDate() + 1,
                                  now.getUTCHours(),
                                  now.getUTCMinutes(),
                                  now.getUTCSeconds()));
    asReq.reqBody.from = now;
    asReq.reqBody.till = later;
    asReq.reqBody.nonce = Crypto.randomNonce();
    asReq.reqBody.etype = [krb.enctype.des_cbc_crc];

    $.ajax(KDC.urlBase + 'AS_REQ', {
        data: Crypto.toBase64(krb.AS_REQ.encodeDER(asReq)),
        error: function(xhr, status, error) {
            var msg = status || 'unknown error';
            if(error)
                msg += ': ' + error;
            error(msg);
        },
        success: function(data, status, xhr) {
            switch(data.status) {
                case 'ERROR':
                    error(data.msg);
                    break;
                case 'TIMEOUT':
                    error('KDC connection timed out');
                    break;
                case 'OK':
                    var der = Crypto.fromBase64(data.reply);
                    success(asReq, krb.AS_REP_OR_ERROR.decodeDER(der)[1]);
                    break;
            }
        },
    });
};

KDC.getTGTSession = function (username, password, success, error) {
    KDC.asReq(username, function (asReq, asRep) {
        // TODO: Rearrange this code to interpret this error and stuff. We
        // may get a request for pre-authentication, in which case we
        // retry with pre-auth after prompting for the password. (We
        // already have the password, but I believe in theory this could
        // be written so that we prompt on demand.)
        if(asRep.msgType == krb.KRB_MT_ERROR)
            return error(asRep.eText + ' (' + asRep.errorCode + ')');

        // 3.1.5.  Receipt of KRB_AS_REP Message

        // If the reply message type is KRB_AS_REP, then the
        // client verifies that the cname and crealm fields in the
        // cleartext portion of the reply match what it requested.
        if(asRep.crealm != asReq.reqBody.realm)
            return error('crealm does not match');
        if(!krb.principalNamesEqual(asReq.reqBody.principalName, asRep.cname))
            return error('cname does not match');

        // If any padata fields are present, they may be used to
        // derive the proper secret key to decrypt the message.
        if (asRep.padata) {
            // TODO: Do something about this one.
        }

        // The default salt string, if none is provided via
        // pre-authentication data, is the concatenation of the
        // principal's realm and name components, in order, with
        // no separators.
        var salt = asReq.reqBody.realm + username;
        var encProfile = krb.encProfiles[asRep.encPart.etype];
        if (encProfile === undefined)
            return error('Unsupported enctype ' + asRep.encPart.etype);

        var key = encProfile.stringToKey(password, salt);
        // The key usage value for encrypting this field is 3 in
        // an AS-REP message, using the client's long-term key or
        // another key selected via pre-authentication mechanisms.
        var derivedKey = encProfile.deriveKey(key, krb.KU_AS_REQ_ENC_PART);

        // The client decrypts the encrypted part of the response
        // using its secret key...
        try {
            var t = encProfile.decrypt(
                derivedKey,
                encProfile.initialCipherState(derivedKey, false),
                asRep.encPart.cipher);
        } catch(e) {
            return error(e);
        }

        // Some ciphers add padding, so we can't abort if there is
        // data left over. Also allow an EncTGSRepPart because the
        // MIT KDC is screwy.
        var encRepPart = krb.EncASorTGSRepPart.decodeDERPrefix(t[1])[0][1];

        // ...and verifies that the nonce in the encrypted part
        // matches the nonce it supplied in its request (to detect
        // replays).
        console.log('asReq', asReq);
        console.log('encRepPart', encRepPart);
        if (asReq.reqBody.nonce != encRepPart.nonce)
            return error('nonce does not match');

        // It also verifies that the sname and srealm in the
        // response match those in the request (or are otherwise
        // expected values), and that the host address field is
        // also correct.
        if (!krb.principalNamesEqual(asReq.reqBody.sname, encRepPart.sname))
            return error('sname does not match');

        // It then stores the ticket, session key, start and
        // expiration times, and other information for later use.
        success(new KDC.Session(asRep, encRepPart));

        // TODO: Do we want to do anything with last-req and
        // authtime?
    }, error);
};

KDC.Session = function (asRep, encRepPart) {
    // Just store everything. Whatever.
    this.crealm = asRep.crealm;
    this.cname = asRep.cname;
    this.ticket = asRep.ticket;

    this.key = encRepPart.key;
    this.flags = encRepPart.flags;
    this.starttime = encRepPart.starttime;
    this.endtime = encRepPart.endtime;
    this.renewTill = encRepPart.renewTill;
    this.srealm = encRepPart.srealm;
    this.sname = encRepPart.sname;
    this.caddr = encRepPart.caddr;
};

KDC.Session.prototype.makeAPReq = function (keyUsage,
                                            cksum,
                                            subkey,
                                            seqNumber) {
    var apReq = { };
    apReq.pvno = krb.pvno;
    apReq.msgType = krb.KRB_MT_AP_REQ;
    apReq.apOptions = krb.APOptions.make();
    apReq.ticket = this.ticket;

    var auth = { };
    auth.authenticatorVno = krb.pvno;
    auth.crealm = this.crealm;
    auth.cname = this.cname;
    if (cksum !== undefined) auth.cksum = cksum;
    auth.ctime = new Date();
    auth.cusec = auth.ctime.getUTCMilliseconds() * 1000;
    auth.ctime.setUTCMilliseconds(0);
    if (subkey !== undefined) auth.subkey = subkey;
    auth.seqNumber = seqNumber;

    // Encode the authenticator.
    // FIXME: This is kinda tedious.
    var encProfile = krb.encProfiles[this.key.keytype];
    if (encProfile === undefined)
        throw "Unknown enctype " + this.key.keytype;
    var derivedKey = encProfile.deriveKey(this.key.keyvalue, keyUsage);
    apReq.authenticator = encProfile.encrypt(
        derivedKey,
        encProfile.initialCipherState(derivedKey, true),
        krb.Authenticator.encodeDER(auth))[1];

    return apReq;
};

KDC.Session.prototype.getServiceSession = function (blah, success, error) {
    var tgsReq = { };
    tgsReq.pvno = krb.pvno;
    tgsReq.msgType = krb.KRB_MT_TGS_REQ;

    // Requests for additional tickets (KRB_TGS_REQ) MUST contain a
    // padata of PA-TGS-REQ.

    // FIXME: Do we need a subkey and stuff? We can't forward the TGT
    // session key to the random server. I'm still unclear on whether
    // we have to do anything interesting to achieve that.
    // TODO: Checksum the reqBody and pass it in.
    var apReq = this.makeAPReq(krb.KU_TGS_REQ_PA_TGS_REQ);
    tgsReq.padata = [{ padataType: krb.PA_TGS_REQ,
                       padataValue: krb.AP_REQ.encodeDER(apReq) }];

    tgsReq.reqBody = { };
    // TODO: Flags?
    tgsReq.reqBody.kdcOptions = krb.KDCOptions.make();
    // TODO: The rest of this function.
    tgsReq.reqBody.nonce = Crypto.randomNonce();
};
<commit_msg>Get that last bit of tabbedness<commit_after>"use strict";

$.ajaxSetup({
    cache: false,
    contentType: 'text/plain',
    dataType: 'json',
    headers: { 'X-WebKDC-Request' : 'OK' },
    type: 'POST',
});

var Crypto = {};

Crypto.toBase64 = function(str) {
    return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Latin1.parse(str));
};

Crypto.fromBase64 = function(str) {
    return CryptoJS.enc.Latin1.stringify(CryptoJS.enc.Base64.parse(str));
};

Crypto.randomNonce = function() {
    try {
        var word = sjcl.random.randomWords(1)[0];
        // Twos-complement it if negative.
        if (word < 0)
            word += 0x80000000;
        return word;
    } catch (e) {
        if (e instanceof sjcl.exception.notReady) {
            // TODO: We should retry a little later. We can also
            // adjust the paranoia argument.
            window.setTimeout(function () { alert(String(e)); });
            return;
        }
        throw e;
    }
};

var KDC = {};

KDC.urlBase = '/kdc/v1/';
KDC.realm = 'ATHENA.MIT.EDU'; // XXX

KDC.asReq = function(username, success, error) {
    var asReq = {};
    asReq.pvno = krb.pvno;
    asReq.msgType = krb.KRB_MT_AS_REQ;
    // TODO: Implement pre-authentication and everything.
    // asReq.padata = []; // Omit if empty.

    // FIXME: This is obnoxious. Also constants.
    asReq.reqBody = {};
    // TODO: Pick a reasonable set of flags. These are just taken from
    // a wireshark trace.
    asReq.reqBody.kdcOptions = krb.KDCOptions.make(
        krb.KDCOptions.forwardable,
        krb.KDCOptions.proxiable,
        krb.KDCOptions.renewable_ok);

    asReq.reqBody.principalName = {};
    asReq.reqBody.principalName.nameType = krb.KRB_NT_PRINCIPAL;
    asReq.reqBody.principalName.nameString = [ username ];

    asReq.reqBody.realm = KDC.realm;

    asReq.reqBody.sname = {};
    asReq.reqBody.sname.nameType = krb.KRB_NT_SRV_INST;
    asReq.reqBody.sname.nameString = [ 'krbtgt', KDC.realm ];

    var now = new Date();
    now.setUTCMilliseconds(0);
    var later = new Date(Date.UTC(now.getUTCFullYear(),
                                  now.getUTCMonth(),
                                  now.getUTCDate() + 1,
                                  now.getUTCHours(),
                                  now.getUTCMinutes(),
                                  now.getUTCSeconds()));
    asReq.reqBody.from = now;
    asReq.reqBody.till = later;
    asReq.reqBody.nonce = Crypto.randomNonce();
    asReq.reqBody.etype = [krb.enctype.des_cbc_crc];

    $.ajax(KDC.urlBase + 'AS_REQ', {
        data: Crypto.toBase64(krb.AS_REQ.encodeDER(asReq)),
        error: function(xhr, status, error) {
            var msg = status || 'unknown error';
            if(error)
                msg += ': ' + error;
            error(msg);
        },
        success: function(data, status, xhr) {
            switch(data.status) {
                case 'ERROR':
                    error(data.msg);
                    break;
                case 'TIMEOUT':
                    error('KDC connection timed out');
                    break;
                case 'OK':
                    var der = Crypto.fromBase64(data.reply);
                    success(asReq, krb.AS_REP_OR_ERROR.decodeDER(der)[1]);
                    break;
            }
        },
    });
};

KDC.getTGTSession = function (username, password, success, error) {
    KDC.asReq(username, function (asReq, asRep) {
        // TODO: Rearrange this code to interpret this error and stuff. We
        // may get a request for pre-authentication, in which case we
        // retry with pre-auth after prompting for the password. (We
        // already have the password, but I believe in theory this could
        // be written so that we prompt on demand.)
        if(asRep.msgType == krb.KRB_MT_ERROR)
            return error(asRep.eText + ' (' + asRep.errorCode + ')');

        // 3.1.5.  Receipt of KRB_AS_REP Message

        // If the reply message type is KRB_AS_REP, then the
        // client verifies that the cname and crealm fields in the
        // cleartext portion of the reply match what it requested.
        if(asRep.crealm != asReq.reqBody.realm)
            return error('crealm does not match');
        if(!krb.principalNamesEqual(asReq.reqBody.principalName, asRep.cname))
            return error('cname does not match');

        // If any padata fields are present, they may be used to
        // derive the proper secret key to decrypt the message.
        if (asRep.padata) {
            // TODO: Do something about this one.
        }

        // The default salt string, if none is provided via
        // pre-authentication data, is the concatenation of the
        // principal's realm and name components, in order, with
        // no separators.
        var salt = asReq.reqBody.realm + username;
        var encProfile = krb.encProfiles[asRep.encPart.etype];
        if (encProfile === undefined)
            return error('Unsupported enctype ' + asRep.encPart.etype);

        var key = encProfile.stringToKey(password, salt);
        // The key usage value for encrypting this field is 3 in
        // an AS-REP message, using the client's long-term key or
        // another key selected via pre-authentication mechanisms.
        var derivedKey = encProfile.deriveKey(key, krb.KU_AS_REQ_ENC_PART);

        // The client decrypts the encrypted part of the response
        // using its secret key...
        try {
            var t = encProfile.decrypt(
                derivedKey,
                encProfile.initialCipherState(derivedKey, false),
                asRep.encPart.cipher);
        } catch(e) {
            return error(e);
        }

        // Some ciphers add padding, so we can't abort if there is
        // data left over. Also allow an EncTGSRepPart because the
        // MIT KDC is screwy.
        var encRepPart = krb.EncASorTGSRepPart.decodeDERPrefix(t[1])[0][1];

        // ...and verifies that the nonce in the encrypted part
        // matches the nonce it supplied in its request (to detect
        // replays).
        console.log('asReq', asReq);
        console.log('encRepPart', encRepPart);
        if (asReq.reqBody.nonce != encRepPart.nonce)
            return error('nonce does not match');

        // It also verifies that the sname and srealm in the
        // response match those in the request (or are otherwise
        // expected values), and that the host address field is
        // also correct.
        if (!krb.principalNamesEqual(asReq.reqBody.sname, encRepPart.sname))
            return error('sname does not match');

        // It then stores the ticket, session key, start and
        // expiration times, and other information for later use.
        success(new KDC.Session(asRep, encRepPart));

        // TODO: Do we want to do anything with last-req and
        // authtime?
    }, error);
};

KDC.Session = function (asRep, encRepPart) {
    // Just store everything. Whatever.
    this.crealm = asRep.crealm;
    this.cname = asRep.cname;
    this.ticket = asRep.ticket;

    this.key = encRepPart.key;
    this.flags = encRepPart.flags;
    this.starttime = encRepPart.starttime;
    this.endtime = encRepPart.endtime;
    this.renewTill = encRepPart.renewTill;
    this.srealm = encRepPart.srealm;
    this.sname = encRepPart.sname;
    this.caddr = encRepPart.caddr;
};

KDC.Session.prototype.makeAPReq = function (keyUsage,
                                            cksum,
                                            subkey,
                                            seqNumber) {
    var apReq = { };
    apReq.pvno = krb.pvno;
    apReq.msgType = krb.KRB_MT_AP_REQ;
    apReq.apOptions = krb.APOptions.make();
    apReq.ticket = this.ticket;

    var auth = { };
    auth.authenticatorVno = krb.pvno;
    auth.crealm = this.crealm;
    auth.cname = this.cname;
    if (cksum !== undefined) auth.cksum = cksum;
    auth.ctime = new Date();
    auth.cusec = auth.ctime.getUTCMilliseconds() * 1000;
    auth.ctime.setUTCMilliseconds(0);
    if (subkey !== undefined) auth.subkey = subkey;
    auth.seqNumber = seqNumber;

    // Encode the authenticator.
    // FIXME: This is kinda tedious.
    var encProfile = krb.encProfiles[this.key.keytype];
    if (encProfile === undefined)
        throw "Unknown enctype " + this.key.keytype;
    var derivedKey = encProfile.deriveKey(this.key.keyvalue, keyUsage);
    apReq.authenticator = encProfile.encrypt(
        derivedKey,
        encProfile.initialCipherState(derivedKey, true),
        krb.Authenticator.encodeDER(auth))[1];

    return apReq;
};

KDC.Session.prototype.getServiceSession = function (blah, success, error) {
    var tgsReq = { };
    tgsReq.pvno = krb.pvno;
    tgsReq.msgType = krb.KRB_MT_TGS_REQ;

    // Requests for additional tickets (KRB_TGS_REQ) MUST contain a
    // padata of PA-TGS-REQ.

    // FIXME: Do we need a subkey and stuff? We can't forward the TGT
    // session key to the random server. I'm still unclear on whether
    // we have to do anything interesting to achieve that.
    // TODO: Checksum the reqBody and pass it in.
    var apReq = this.makeAPReq(krb.KU_TGS_REQ_PA_TGS_REQ);
    tgsReq.padata = [{ padataType: krb.PA_TGS_REQ,
                       padataValue: krb.AP_REQ.encodeDER(apReq) }];

    tgsReq.reqBody = { };
    // TODO: Flags?
    tgsReq.reqBody.kdcOptions = krb.KDCOptions.make();
    // TODO: The rest of this function.
    tgsReq.reqBody.nonce = Crypto.randomNonce();
};
<|endoftext|>


<commit_before>/* This simple http server is made by malpower
 * for testing web applications of mobile.
 * This porgram is based on Node.js which is
 * a platform from joyent, inc. It allows user
 * building backend service programs with JS.
 * Node.js uses Google V8 engine, it means that
 * it will be fast.
 * You can also share your files on http with
 * this simple http server.Conf.js is a configure
 * file for this simple server.Anthor named
 * malpower who is a web programmer in Chengdu.
 * This is the seconds edition of malache, you
 * can visit [https://github.com/malpower/Malache2]
 * to get the latest code.
 * Email: malpower@ymail.com
 */

var net=require("net");
var Connection=require("./objects/Connection");
var conf=require("./conf");
conf.cwd=process.cwd()+"/";

var server=net.createServer(function(socket)
{//main server, collect sockets connections simply and create a Connection with sockets collected.
    new Connection(socket);
});

server.listen(conf.port);

server.on("error",function(err)
{//catch errors when listening failed.
	console.log("server starting failed, check conf.js for port.");
	console.log(err);
});

console.log("============Malache2============");
console.log("Server is running on port: "+conf.port);
console.log("Domains:");
for (var x in conf.domains)
{
	console.log("    "+x);
}
console.log("================================");

<commit_msg>version info on malache2<commit_after>/* This simple http server is made by malpower
 * for testing web applications of mobile.
 * This porgram is based on Node.js which is
 * a platform from joyent, inc. It allows user
 * building backend service programs with JS.
 * Node.js uses Google V8 engine, it means that
 * it will be fast.
 * You can also share your files on http with
 * this simple http server.Conf.js is a configure
 * file for this simple server.Anthor named
 * malpower who is a web programmer in Chengdu.
 * This is the seconds edition of malache, you
 * can visit [https://github.com/malpower/Malache2]
 * to get the latest code.
 * Email: malpower@ymail.com
 */

var net=require("net");
var Connection=require("./objects/Connection");
var conf=require("./conf");
conf.cwd=process.cwd()+"/";

var server=net.createServer(function(socket)
{//main server, collect sockets connections simply and create a Connection with sockets collected.
    new Connection(socket);
});

server.listen(conf.port);

server.on("error",function(err)
{//catch errors when listening failed.
	console.log("server starting failed, check conf.js for port.");
	console.log(err);
});

console.log("============Malache2============");
console.log("Version: 201409102217D");
console.log("Server is running on port: "+conf.port);
console.log("Domains:");
for (var x in conf.domains)
{
	console.log("  "+x);
}
console.log("================================");

<|endoftext|>


<commit_before>var Suite = require('./Suite')
  , Test = require('./Test')
  , EventEmitter = require('events').EventEmitter
  , util = require('util')
  , path = require('path')
  , Date = global.Date

/**
 * Creates a new PPUnit object
 *
 * @constructor
 */
var PPUnit = function () {
    PPUnit.super_.call(this)

    this.rootSuite = new Suite(undefined)
    this.rootSuite.timeout(2000)
    this.rootSuite.globallyExclusive()
    this.rootSuite.locallyExclusiveTests()

    this.allTests = []

    this._nextId = 1

    this._files = []

    this.failures = []

    this.stats = {
        suites: 0
      , tests: 0
      , skipped: 0
      , passes: 0
      , failures: 0
      , startTime: 0
      , end: undefined
      , duration: undefined
    }
}

util.inherits(PPUnit, EventEmitter)
module.exports = PPUnit

/**
 * Adds a file that contains tests to be run
 *
 * @param {String} file Path to the file
 */
PPUnit.prototype.addFile = function (file) {
    this._files.push(path.resolve(file))
}

/**
 * Runs the test suites
 *
 * @param {function} callback A function to call after finish is emitted
 */
PPUnit.prototype.run = function (callback) {
    this._loadFiles()

    var self = this

    self.rootSuite.on('test', function (test) {
        self._addTest(test)
    })

    self.rootSuite.on('suite', function (suite) {
        suite.id = self._nextId++
    })

    self.rootSuite.prepare()

    self.stats.startTime = new Date
    self.emit('start')

    self.allTests[self.allTests.length - 1].on('finish', function () {
        self.stats.end = new Date
        self.stats.duration = new Date - self.stats.startTime

        self.emit('finish')
        callback()
    })

    self.allTests[0].run()
}

/**
 * Loads/requires the files and builds the test suites
 *
 * @private
 */
PPUnit.prototype._loadFiles = function () {
    var self = this

    self._files.forEach(function (file) {
        //TODO: Emit pre-require and require
        require(file)
    })
}

/**
 * Adds a test to the list and wires up events
 *
 * @param {Test} newTest The test to add
 */
PPUnit.prototype._addTest = function (newTest) {
    var self = this

    newTest.id = this._nextId++

    newTest.on('start', function () {
        self.emit('test start', newTest)
    })

    newTest.on('finish', function () {
        if (newTest.type === Test.TYPE.NORMAL) {
            self.stats.tests++

            switch (newTest.result) {
                case Test.RESULT.SUCCESS:
                    self.stats.passes++
                    break

                case Test.RESULT.HOOK_FAILURE:
                    if (newTest.type !== Test.TYPE.NORMAL) {
                        break
                    }

                case Test.RESULT.TIMEOUT:
                case Test.RESULT.FAILURE:
                    self.failures.push(newTest)
                    self.stats.failures++
                    break

                case Test.RESULT.SKIPPED:
                    self.stats.skipped++
                    break
            }
        }

        self.emit('test finish', newTest)
    })

    newTest.on('error', function (error) {
        console.error('Test had an error', error)
        self.emit('test error', newTest, error)
    })

    if (newTest.exclusivity === Test.EXCLUSIVITY.GLOBAL) {
        var edges = []

        this.allTests.forEach(function (test) {
            if (test.nextTests.length) {
                return
            }

            edges.push(test)
        })

        newTest.addPriorTests(edges)
    }

    this.allTests.push(newTest)
}
<commit_msg>Adding non test types to failures for reporting<commit_after>var Suite = require('./Suite')
  , Test = require('./Test')
  , EventEmitter = require('events').EventEmitter
  , util = require('util')
  , path = require('path')
  , Date = global.Date

/**
 * Creates a new PPUnit object
 *
 * @constructor
 */
var PPUnit = function () {
    PPUnit.super_.call(this)

    this.rootSuite = new Suite(undefined)
    this.rootSuite.timeout(2000)
    this.rootSuite.globallyExclusive()
    this.rootSuite.locallyExclusiveTests()

    this.allTests = []

    this._nextId = 1

    this._files = []

    this.failures = []

    this.stats = {
        suites: 0
      , tests: 0
      , skipped: 0
      , passes: 0
      , failures: 0
      , startTime: 0
      , end: undefined
      , duration: undefined
    }
}

util.inherits(PPUnit, EventEmitter)
module.exports = PPUnit

/**
 * Adds a file that contains tests to be run
 *
 * @param {String} file Path to the file
 */
PPUnit.prototype.addFile = function (file) {
    this._files.push(path.resolve(file))
}

/**
 * Runs the test suites
 *
 * @param {function} callback A function to call after finish is emitted
 */
PPUnit.prototype.run = function (callback) {
    this._loadFiles()

    var self = this

    self.rootSuite.on('test', function (test) {
        self._addTest(test)
    })

    self.rootSuite.on('suite', function (suite) {
        suite.id = self._nextId++
    })

    self.rootSuite.prepare()

    self.stats.startTime = new Date
    self.emit('start')

    self.allTests[self.allTests.length - 1].on('finish', function () {
        self.stats.end = new Date
        self.stats.duration = new Date - self.stats.startTime

        self.emit('finish')
        callback()
    })

    self.allTests[0].run()
}

/**
 * Loads/requires the files and builds the test suites
 *
 * @private
 */
PPUnit.prototype._loadFiles = function () {
    var self = this

    self._files.forEach(function (file) {
        //TODO: Emit pre-require and require
        require(file)
    })
}

/**
 * Adds a test to the list and wires up events
 *
 * @param {Test} newTest The test to add
 */
PPUnit.prototype._addTest = function (newTest) {
    var self = this

    newTest.id = this._nextId++

    newTest.on('start', function () {
        self.emit('test start', newTest)
    })

    newTest.on('finish', function () {
        if (newTest.type === Test.TYPE.NORMAL) {
            self.stats.tests++

            switch (newTest.result) {
                case Test.RESULT.SUCCESS:
                    self.stats.passes++
                    break

                case Test.RESULT.HOOK_FAILURE:
                    if (newTest.type !== Test.TYPE.NORMAL) {
                        break
                    }

                case Test.RESULT.TIMEOUT:
                case Test.RESULT.FAILURE:
                    self.failures.push(newTest)
                    self.stats.failures++
                    break

                case Test.RESULT.SKIPPED:
                    self.stats.skipped++
                    break
            }
        } else if (newTest.result === Test.RESULT.FAILURE) {
            self.failures.push(newTest)
            self.stats.failures++
        }

        self.emit('test finish', newTest)
    })

    newTest.on('error', function (error) {
        console.error('Test had an error', error)
        self.emit('test error', newTest, error)
    })

    if (newTest.exclusivity === Test.EXCLUSIVITY.GLOBAL) {
        var edges = []

        this.allTests.forEach(function (test) {
            if (test.nextTests.length) {
                return
            }

            edges.push(test)
        })

        newTest.addPriorTests(edges)
    }

    this.allTests.push(newTest)
}
<|endoftext|>


<commit_before>
import {Controller as controller} from './controller';

export default () => {
    return {
        restrict: 'E',
        templateUrl: 'monad/src/directives/list/table/template.html',
        scope: {rows: '=', path: '@', total: '@', page: '='},
        controller,
        link: (scope, elem, attrs) => {
            scope.columns = scope.$eval(attrs.columns);
        },
        bindToController: true
    };
};

<commit_msg>pass module<commit_after>
import {Controller as controller} from './controller';

export default () => {
    return {
        restrict: 'E',
        templateUrl: 'monad/src/directives/list/table/template.html',
        scope: {module: '@', rows: '=', path: '@', total: '@', page: '='},
        controller,
        link: (scope, elem, attrs) => {
            scope.columns = scope.$eval(attrs.columns);
        },
        bindToController: true
    };
};

<|endoftext|>


<commit_before>/*
Step: [0-1]
StepSink: Step ->
StepSource: StepSink ->
  step(n): stepSource // produce n linear steps between 0 and 1 inclusive
VertexSink: Vertex, Step, Step* ->
VertexGenerator: VertexSink -> StepSink
  vertices(vertices) // take the given vertices to create a VertexGenerator
  parametric(f): (Step -> Vertex) -> VertexGenerator // convert a vertex producer into a vertex generator
VertexMap: VertexSink -> VertexSink
  zTranslate(start,end): translate vertices along z axis
  zRotate(start*,end*): rotate vertices around z axis
  tag(edges): mark vertices with tags
Facer: FaceSink -> VertexSink
  face(options): Produce a facer with the given options for tesselating and joining
Renderer: FaceSink
  ThreeJSRenderer
  CSGRenerer
  STLRenderer
  NativeRenderer
*/

var context = typeof window != 'undefined' ? window : exports;

context.math = {vadd:vadd, vsub:vsub, vscale:vscale, vdot:vdot, vcross: vcross, vlength:vlength, vnorm:vnorm}

/*
// cube
var renderer = ThreeJSRenderer();

// cube
step(2)(
  vertices([[1,1,0],[-1,1,0],[-1,-1,0],[1,-1,0]])(
  transform(zTranslate(1), label) (
  face( edgeLoop, tesselate('bottom'), tesselate('top',true) )( renderer ))))

var geometry = renderer.geometry;

// OR
extrudeClosed = face( edgeLoop, tesselate('bottom'), tesselate('top',true) )

// sphere
var R = 40, Q = 20, 2PI = 2*Math.Pi, hPI = Math.PI/2;
function simiCircle(s) {return [R*Math.cos(tween(s,-hPI,hPI)),0,R*Math.sin(tween(s,-hPI,hPI))]}

step(Q)(
  step(Q)(
    parametric(semiCircle))(
      zRotate()(
        face(connect:'tb', singular:'lr')( renderer ))))
*/

function Vertex( point, transformStep, ribStep, id) {
  this[0] = point[0];
  this[1] = point[1];
  this[2] = point[2];
  this[3] = transformStep;
  this[4] = ribStep;
  this[5] = id;
}
Vertex.prototype = new Float64Array(6);
Object.defineProperty(Vertex.prototype, 'x', {get:function() {return this[0]}, set:function(x) {this[0]=x}})
Object.defineProperty(Vertex.prototype, 'y', {get:function() {return this[1]}, set:function(y) {this[1]=y}})
Object.defineProperty(Vertex.prototype, 'z', {get:function() {return this[2]}, set:function(z) {this[2]=z}})
Object.defineProperty(Vertex.prototype, 'transformStep', {
  get:function() {return this[3]},
  set:function(transformStep) {this[3]=transformStep}})
Object.defineProperty(Vertex.prototype, 'ribStep', {
  get:function() {return this[4]},
  set:function(ribStep) {this[4]=ribStep}})
Object.defineProperty(Vertex.prototype, 'id', {
  get:function() {return this[5]},
  set:function(id) {this[5]=id}})

// STEP
function step(iterations) {
  return function(stepSink) {
    for (var i=0; i < iterations; i++) stepSink( i / (iterations - 1) );
  }
}

// VERTICES
function vertices(points) {
  return function(vertexSink) {
    var index = 0;
    return function(step) {
      for (var i=0,p; p=points[i]; i++)
        vertexSink( new Vertex(p, step, i / (points.length-1), index++) );
    }
  }
}

function parametric(f) {
  return function(vertexSink) {
    var index = 0;
    return function( ribStep ) {
      return function( transformStep ) {
        vertexSink( new Vertex(f(ribStep, transformStep), transformStep, ribStep, index++) );
      }
    }
  }
}

// TRANSFORM
function translate(translations) {
  return function( vertexSink ) {
    return function( vertex ) {
      var tIndex = parseInt(vertex.transformStep * (translations.length-1))
      var translate = vertex.transformStep==1 ?
        translations[tIndex] :
        vinterp( translations[tIndex], translations[tIndex+1], vertex.transformStep-tIndex)
      vertexSink( new Vertex(vadd(translate,vertex), vertex.transformStep, vertex.ribStep, vertex.id ) );
    }
  }
}

// FACER
function facer() {
  return function( faceSink ) {
    var lastRib;
    var nextRib = [];
    return function( vertex, transformStep, ribStep, index ) {
      if (lastRib) {
        // figure this out.
      }
      nextRib.push([vertex,transformStep,index])
    }
  }
}

/// TESSELATE

function vadd(a,v) { return [a[0]+v[0], a[1]+v[1], a[2]+v[2]]; }
function vsub(a,v) { return [a[0]-v[0], a[1]-v[1], a[2]-v[2]]; }
function vscale(a,c) { return [a[0]*c, a[1]*c, a[2]*c]; }
function vdot(a,v) { return a[0]*v[0] + a[1]*v[1] + a[2]*v[2]; }
function vcross(a,v) { return [a[1]*v[2] - a[2]*v[1], a[2]*v[0] - a[0]*v[2], a[0]*v[1] - a[1]*v[0]]; }
function vlength(v) { return Math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); }
function vnorm(v) { var l=vlength(v); return l > 0 ? [v[0]/l, v[1]/l, v[2]/l] : v; }
function vinterp(a,b,c) { return vadd(a,vscale(vsub(b,a),c)); }

function vectorAverage(vs) { return vs.length ? vscale( vs.reduce(vadd,[0,0,0]), 1/vs.length ) : [0,0,0]; }

function loopMeanNormal(vs) {
  function v(i) { return vs[i%vs.length] }
  return vectorAverage(vs.map(function(v0,i){return vcross(vsub(v0,v(i+1)), vsub(v(i+2), v(i+1)))}))
}

function intersect(v1, v2, v3, v4) {
  var det = (v1.x-v2.x)*(v3.y-v4.y) - (v1.y-v2.y)*(v3.x-v4.x);
  return !det ? null : {
    x: ((v1.x*v2.y-v2.x*v1.y)*(v3.x-v4.x) - (v3.x*v4.y-v4.x*v3.y)*(v1.x-v2.x))/det,
    y: ((v1.x*v2.y-v2.x*v1.y)*(v3.y-v4.y) - (v3.x*v4.y-v4.x*v3.y)*(v1.y-v2.y))/det
  };
}

function doesIntersect(v1, v2, v3, v4) {
  var p = intersect(v1,v2,v3,v4);
  if (!p) return false;
  return p.x >= Math.min(v1.x,v2.x) && p.x >= Math.min(v3.x,v4.x)
    && p.x <= Math.max(v1.x,v2.x) && p.x <= Math.max(v3.x,v4.x)
    && p.y >= Math.min(v1.y,v2.y) && p.y >= Math.min(v3.y,v4.y)
    && p.y <= Math.max(v1.y,v2.y) && p.y <= Math.max(v3.y,v4.y);
}

function isSelfIntersecting( p1, p2, vertices ) {
  for (var i=0,v1,v2; v1=vertices[i], v2=vertices[i+1]; i++)
    if ( doesIntersect(p1,p2,v1,v2) ) return true;
  return false;
}

function projectIntoPlane( p, planePoint, planeNormal ) {
  // p - pp - (((p-pp) . pn) * pn)
  var pTranslated = vsub( p, planePoint );
  return vsub( pTranslated, vscale( planeNormal, vdot( pTranslated, planeNormal )))
}

function tesselate3d( points3d, faceSink ) {
  var planeNormal = vnorm(loopMeanNormal(points3d));
  var planePoint = vectorAverage(points3d);

  var offNormal = vadd( planePoint, Math.abs(planeNormal[0] < .5) ? [1,0,0] : [0,1,0] );
  var axis1 = vnorm(projectIntoPlane(offNormal ,planePoint, planeNormal));
  var axis2 = vcross( axis1, planeNormal );

  var vertices2d = points3d.map( function(p) {
    var pointInPlane = projectIntoPlane(p, planePoint, planeNormal);
    return [vdot(pointInPlane,axis1), vdot(pointInPlane,axis2)];
  })

  tesslateVertices( vertices2d, function(face) {
    faceSink(face);
  })
}

function tesselateVertices(vertices, faceSink) {
  if ( vertices.length < 3 ) return;
  if ( vertices.length < 4 ) return tesselateConvex(vertices);

  // traveling in either direction, find the first negative vertex followed by a positive one.
  // If there are no negative vertices, the shape is convex. Tesselate and return.
  // Starting with the vertex after that, find the first negative vertex or the last vertext s.t.
  //   the angle formed from it and the first two vertices is < π.
  // Create two new sets of vertices, one containing all the vertices found above, and the
  //   other containing the rest plus the first and last from above.
  // The first set is convex, so pass it on to be tesselated.
  // The second list is "less concave", because the points at the ends now have less negative angles.
  // Recurse with the second list.
  function index(i) { return (i+vertices.length)%vertices.length;  }
  function center(i) { return vertices[ i%vertices.length ] }
  function left(i) { return vertices[ (i+vertices.length-1)%vertices.length ] }
  function right(i) { return vertices[ (i+1)%vertices.length ] }
  function angle(l,p,r) { return Math.atan2(
    (r.x-p.x)*(l.y-p.y) - (r.y-p.y)*(l.x-p.x),
    (r.x-p.x)*(l.x-p.x) + (r.y-p.y)*(l.y-p.y)
  ) }

  var angles = vertices.map( function(p,i) { return angle(left(i),p,right(i)); })

  var startPoint;
  for (var i=vertices.length-1; i>=0; i--) {
    if ( angles[i] <= 0 && angles[index(i+1)] > 0 ) {
      startPoint = i;

      for (var j=2, endPoint; j<vertices.length-1; j++) {
      endPoint = j + startPoint;
        if ( angle(left(endPoint),center(endPoint),right(endPoint)) <= 0 )
          break;

        if ( angle(center(endPoint),center(startPoint), right(startPoint)) <= 0 ) {
          endPoint = (endPoint+vertices.length-1) % vertices.length;
          break;
        }
      }

      endPoint = index(endPoint);

      var newShape, rest;
      if (endPoint < startPoint) {
        newShape = vertices.slice(startPoint).concat(vertices.slice(0,endPoint+1));
        rest = vertices.slice(endPoint, startPoint+1);
      } else {
        newShape = vertices.slice(startPoint, endPoint+1);
        rest = vertices.slice(endPoint).concat(vertices.slice(0,startPoint+1));
      }

      if ( ! isSelfIntersecting( vertices[startPoint], vertices[endPoint], rest.slice(1,rest.length-1) ) ) {
        if ( Math.abs(endPoint- startPoint) <= 1 || Math.abs(endPoint- startPoint) >= vertices.length -1 ) {
          console.log("wrap around", startPoint, endPoint, vertices.length);
          return;
        }
        if (endPoint < startPoint) {
          tesselate( vertices.slice(startPoint).concat(vertices.slice(0,endPoint+1)) );
          tesselate( vertices.slice(endPoint, startPoint+1 ) );
        } else {
          tesselate( vertices.slice(startPoint, endPoint+1 ) );
          tesselate( vertices.slice(endPoint).concat(vertices.slice(0,startPoint+1)) );
        }

        ctx.strokeStyle = '#fff';
        ctx.lineWidth = 2;
        var p = center(startPoint);
        ctx.beginPath()
        ctx.moveTo( p.x, p.y );
        p = center(endPoint);
        ctx.lineTo( p.x, p.y );
        ctx.stroke();
        return;
      }
    }
  }

  return tesselateConvex(vertices);

}

function tesselateConvex(vertices) {
  var ai = 0, bi=(vertices.length/3)|0, ci=(2*vertices.length/3)|0;
  var a = vertices[ai], b=vertices[bi], c=vertices[ci];

  ctx.fillStyle = randomColor();
  ctx.strokeStyle = '#000';
  ctx.lineWidth = 1;
  ctx.beginPath();
  ctx.moveTo(a.x,a.y);
  ctx.lineTo(b.x,b.y);
  ctx.lineTo(c.x,c.y);
  ctx.closePath();
  ctx.fill();
  ctx.stroke();

  if (bi-ai > 1) tesselateConvex(vertices.slice(ai,bi+1));
  if (ci-bi > 1) tesselateConvex(vertices.slice(bi,ci+1));
  if (vertices.length-ci > 1)
    tesselateConvex(vertices.slice(ci,vertices.length).concat([a]));
}
<commit_msg>basic facing<commit_after>/*
Step: [0-1]
StepSink: Step ->
StepSource: StepSink ->
  step(n): stepSource // produce n linear steps between 0 and 1 inclusive
VertexSink: Vertex, Step, Step* ->
VertexGenerator: VertexSink -> StepSink
  vertices(vertices) // take the given vertices to create a VertexGenerator
  parametric(f): (Step -> Vertex) -> VertexGenerator // convert a vertex producer into a vertex generator
VertexMap: VertexSink -> VertexSink
  zTranslate(start,end): translate vertices along z axis
  zRotate(start*,end*): rotate vertices around z axis
  tag(edges): mark vertices with tags
Facer: FaceSink -> VertexSink
  face(options): Produce a facer with the given options for tesselating and joining
Renderer: FaceSink
  ThreeJSRenderer
  CSGRenerer
  STLRenderer
  NativeRenderer
*/

var context = typeof window != 'undefined' ? window : exports;

context.math = {vadd:vadd, vsub:vsub, vscale:vscale, vdot:vdot, vcross: vcross, vlength:vlength, vnorm:vnorm}

/*
// cube
var renderer = ThreeJSRenderer();

// cube
step(2)(
  vertices([[1,1,0],[-1,1,0],[-1,-1,0],[1,-1,0]])(
  transform(zTranslate(1), label) (
  face( edgeLoop, tesselate('bottom'), tesselate('top',true) )( renderer ))))

var geometry = renderer.geometry;

// OR
extrudeClosed = face( edgeLoop, tesselate('bottom'), tesselate('top',true) )

// sphere
var R = 40, Q = 20, 2PI = 2*Math.Pi, hPI = Math.PI/2;
function simiCircle(s) {return [R*Math.cos(tween(s,-hPI,hPI)),0,R*Math.sin(tween(s,-hPI,hPI))]}

step(Q)(
  step(Q)(
    parametric(semiCircle))(
      zRotate()(
        face(connect:'tb', singular:'lr')( renderer ))))
*/

function Vertex( point, transformStep, ribStep, id) {
  this[0] = point[0];
  this[1] = point[1];
  this[2] = point[2];
  this[3] = transformStep;
  this[4] = ribStep;
  this[5] = id;
}
Vertex.prototype = new Float64Array(6);
Object.defineProperty(Vertex.prototype, 'x', {get:function() {return this[0]}, set:function(x) {this[0]=x}})
Object.defineProperty(Vertex.prototype, 'y', {get:function() {return this[1]}, set:function(y) {this[1]=y}})
Object.defineProperty(Vertex.prototype, 'z', {get:function() {return this[2]}, set:function(z) {this[2]=z}})
Object.defineProperty(Vertex.prototype, 'transformStep', {
  get:function() {return this[3]},
  set:function(transformStep) {this[3]=transformStep}})
Object.defineProperty(Vertex.prototype, 'ribStep', {
  get:function() {return this[4]},
  set:function(ribStep) {this[4]=ribStep}})
Object.defineProperty(Vertex.prototype, 'id', {
  get:function() {return this[5]},
  set:function(id) {this[5]=id}})

// STEP
function step(iterations) {
  return function(stepSink) {
    for (var i=0; i < iterations; i++) stepSink( i / (iterations - 1) );
  }
}

// VERTICES
function vertices(points) {
  return function(vertexSink) {
    var index = 0;
    return function(step) {
      for (var i=0,p; p=points[i]; i++)
        vertexSink( new Vertex(p, step, i / (points.length-1), index++) );
    }
  }
}

function parametric(f) {
  return function(vertexSink) {
    var index = 0;
    return function( ribStep ) {
      return function( transformStep ) {
        vertexSink( new Vertex(f(ribStep, transformStep), transformStep, ribStep, index++) );
      }
    }
  }
}

// TRANSFORM
function translate(translations) {
  return function( vertexSink ) {
    return function( vertex ) {
      var tIndex = parseInt(vertex.transformStep * (translations.length-1))
      var translate = vertex.transformStep==1 ?
        translations[tIndex] :
        vinterp( translations[tIndex], translations[tIndex+1], vertex.transformStep-tIndex)
      vertexSink( new Vertex(vadd(translate,vertex), vertex.transformStep, vertex.ribStep, vertex.id ) );
    }
  }
}

// TESSELATE
function facer() {
  return function( faceSink ) {
    var lastRib;
    var nextRib = [];
    var bottomVertexIndex = 0;
    var lastTransformStep = 0;
    return function( vertex ) {
      if ( vertex.transformStep > lastTransformStep ) {
        lastRib = nextRib;
        lastTransformStep = vertex.transformStep;
      }

      if (lastRib && nextRib.length) {
        var topLeftVertex = nextRib[nextRib.length-1];
        var bottomLeftVertex = lastRib[bottomVertexIndex];
        var bottomRightVertex = lastRib[bottomVertexIndex+1];
        while ( bottomRightVertex &&
            vertex.ribStep > bottomLeftVertex.ribStep + (bottomRightVertex.ribStep-bottomLeftVertex.ribStep)/2 ) {
          faceSink( [bottomLeftVertex, topLeftVertex, bottomRightVertex] );
          bottomVertexIndex++;
          bottomLeftVertex = bottomRightVertex;
          bottomRightVertex = lastRib[bottomVertexIndex+1];
        }
        faceSink( [bottomLeftVertex, topLeftVertex, vertex] );
      }

      nextRib.push([vertex,transformStep,index])
    }
  }
}

// MATH

function vadd(a,v) { return [a[0]+v[0], a[1]+v[1], a[2]+v[2]]; }
function vsub(a,v) { return [a[0]-v[0], a[1]-v[1], a[2]-v[2]]; }
function vscale(a,c) { return [a[0]*c, a[1]*c, a[2]*c]; }
function vdot(a,v) { return a[0]*v[0] + a[1]*v[1] + a[2]*v[2]; }
function vcross(a,v) { return [a[1]*v[2] - a[2]*v[1], a[2]*v[0] - a[0]*v[2], a[0]*v[1] - a[1]*v[0]]; }
function vlength(v) { return Math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); }
function vnorm(v) { var l=vlength(v); return l > 0 ? [v[0]/l, v[1]/l, v[2]/l] : v; }
function vinterp(a,b,c) { return vadd(a,vscale(vsub(b,a),c)); }

function vectorAverage(vs) { return vs.length ? vscale( vs.reduce(vadd,[0,0,0]), 1/vs.length ) : [0,0,0]; }

function loopMeanNormal(vs) {
  function v(i) { return vs[i%vs.length] }
  return vectorAverage(vs.map(function(v0,i){return vcross(vsub(v0,v(i+1)), vsub(v(i+2), v(i+1)))}))
}

function intersect(v1, v2, v3, v4) {
  var det = (v1.x-v2.x)*(v3.y-v4.y) - (v1.y-v2.y)*(v3.x-v4.x);
  return !det ? null : {
    x: ((v1.x*v2.y-v2.x*v1.y)*(v3.x-v4.x) - (v3.x*v4.y-v4.x*v3.y)*(v1.x-v2.x))/det,
    y: ((v1.x*v2.y-v2.x*v1.y)*(v3.y-v4.y) - (v3.x*v4.y-v4.x*v3.y)*(v1.y-v2.y))/det
  };
}

function doesIntersect(v1, v2, v3, v4) {
  var p = intersect(v1,v2,v3,v4);
  if (!p) return false;
  return p.x >= Math.min(v1.x,v2.x) && p.x >= Math.min(v3.x,v4.x)
    && p.x <= Math.max(v1.x,v2.x) && p.x <= Math.max(v3.x,v4.x)
    && p.y >= Math.min(v1.y,v2.y) && p.y >= Math.min(v3.y,v4.y)
    && p.y <= Math.max(v1.y,v2.y) && p.y <= Math.max(v3.y,v4.y);
}

function isSelfIntersecting( p1, p2, vertices ) {
  for (var i=0,v1,v2; v1=vertices[i], v2=vertices[i+1]; i++)
    if ( doesIntersect(p1,p2,v1,v2) ) return true;
  return false;
}

function projectIntoPlane( p, planePoint, planeNormal ) {
  // p - pp - (((p-pp) . pn) * pn)
  var pTranslated = vsub( p, planePoint );
  return vsub( pTranslated, vscale( planeNormal, vdot( pTranslated, planeNormal )))
}

function tesselate3d( points3d, faceSink ) {
  var planeNormal = vnorm(loopMeanNormal(points3d));
  var planePoint = vectorAverage(points3d);

  var offNormal = vadd( planePoint, Math.abs(planeNormal[0] < .5) ? [1,0,0] : [0,1,0] );
  var axis1 = vnorm(projectIntoPlane(offNormal ,planePoint, planeNormal));
  var axis2 = vcross( axis1, planeNormal );

  var vertices2d = points3d.map( function(p) {
    var pointInPlane = projectIntoPlane(p, planePoint, planeNormal);
    return [vdot(pointInPlane,axis1), vdot(pointInPlane,axis2)];
  })

  tesslateVertices( vertices2d, function(face) {
    faceSink(face);
  })
}

function tesselateVertices(vertices, faceSink) {
  if ( vertices.length < 3 ) return;
  if ( vertices.length < 4 ) return tesselateConvex(vertices);

  // traveling in either direction, find the first negative vertex followed by a positive one.
  // If there are no negative vertices, the shape is convex. Tesselate and return.
  // Starting with the vertex after that, find the first negative vertex or the last vertext s.t.
  //   the angle formed from it and the first two vertices is < π.
  // Create two new sets of vertices, one containing all the vertices found above, and the
  //   other containing the rest plus the first and last from above.
  // The first set is convex, so pass it on to be tesselated.
  // The second list is "less concave", because the points at the ends now have less negative angles.
  // Recurse with the second list.
  function index(i) { return (i+vertices.length)%vertices.length;  }
  function center(i) { return vertices[ i%vertices.length ] }
  function left(i) { return vertices[ (i+vertices.length-1)%vertices.length ] }
  function right(i) { return vertices[ (i+1)%vertices.length ] }
  function angle(l,p,r) { return Math.atan2(
    (r.x-p.x)*(l.y-p.y) - (r.y-p.y)*(l.x-p.x),
    (r.x-p.x)*(l.x-p.x) + (r.y-p.y)*(l.y-p.y)
  ) }

  var angles = vertices.map( function(p,i) { return angle(left(i),p,right(i)); })

  var startPoint;
  for (var i=vertices.length-1; i>=0; i--) {
    if ( angles[i] <= 0 && angles[index(i+1)] > 0 ) {
      startPoint = i;

      for (var j=2, endPoint; j<vertices.length-1; j++) {
      endPoint = j + startPoint;
        if ( angle(left(endPoint),center(endPoint),right(endPoint)) <= 0 )
          break;

        if ( angle(center(endPoint),center(startPoint), right(startPoint)) <= 0 ) {
          endPoint = (endPoint+vertices.length-1) % vertices.length;
          break;
        }
      }

      endPoint = index(endPoint);

      var newShape, rest;
      if (endPoint < startPoint) {
        newShape = vertices.slice(startPoint).concat(vertices.slice(0,endPoint+1));
        rest = vertices.slice(endPoint, startPoint+1);
      } else {
        newShape = vertices.slice(startPoint, endPoint+1);
        rest = vertices.slice(endPoint).concat(vertices.slice(0,startPoint+1));
      }

      if ( ! isSelfIntersecting( vertices[startPoint], vertices[endPoint], rest.slice(1,rest.length-1) ) ) {
        if ( Math.abs(endPoint- startPoint) <= 1 || Math.abs(endPoint- startPoint) >= vertices.length -1 ) {
          console.log("wrap around", startPoint, endPoint, vertices.length);
          return;
        }
        if (endPoint < startPoint) {
          tesselate( vertices.slice(startPoint).concat(vertices.slice(0,endPoint+1)) );
          tesselate( vertices.slice(endPoint, startPoint+1 ) );
        } else {
          tesselate( vertices.slice(startPoint, endPoint+1 ) );
          tesselate( vertices.slice(endPoint).concat(vertices.slice(0,startPoint+1)) );
        }

        ctx.strokeStyle = '#fff';
        ctx.lineWidth = 2;
        var p = center(startPoint);
        ctx.beginPath()
        ctx.moveTo( p.x, p.y );
        p = center(endPoint);
        ctx.lineTo( p.x, p.y );
        ctx.stroke();
        return;
      }
    }
  }

  return tesselateConvex(vertices);

}

function tesselateConvex(vertices) {
  var ai = 0, bi=(vertices.length/3)|0, ci=(2*vertices.length/3)|0;
  var a = vertices[ai], b=vertices[bi], c=vertices[ci];

  ctx.fillStyle = randomColor();
  ctx.strokeStyle = '#000';
  ctx.lineWidth = 1;
  ctx.beginPath();
  ctx.moveTo(a.x,a.y);
  ctx.lineTo(b.x,b.y);
  ctx.lineTo(c.x,c.y);
  ctx.closePath();
  ctx.fill();
  ctx.stroke();

  if (bi-ai > 1) tesselateConvex(vertices.slice(ai,bi+1));
  if (ci-bi > 1) tesselateConvex(vertices.slice(bi,ci+1));
  if (vertices.length-ci > 1)
    tesselateConvex(vertices.slice(ci,vertices.length).concat([a]));
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */

(function() {

  // Establish scope.
  window.WebComponents = window.WebComponents || {flags:{}};

  // loading script
  var file = 'webcomponents-lite.js';
  var script = document.querySelector('script[src*="' + file + '"]');

  // Flags. Convert url arguments to flags
  var flags = {};
  if (!flags.noOpts) {
    // from url
    location.search.slice(1).split('&').forEach(function(option) {
      var parts = option.split('=');
      var match;
      if (parts[0] && (match = parts[0].match(/wc-(.+)/))) {
        flags[match[1]] = parts[1] || true;
      }
    });
    // from script
    if (script) {
      for (var i=0, a; (a=script.attributes[i]); i++) {
        if (a.name !== 'src') {
          flags[a.name] = a.value || true;
        }
      }
    }
    // log flags
    if (flags.log && flags.log.split) {
      var parts = flags.log.split(',');
      flags.log = {};
      parts.forEach(function(f) {
        flags.log[f] = true;
      });
    } else {
      flags.log = {};
    }
  }

  // construct full dependency list
  var modules = [
    'URL/URL.js',
    'WeakMap/WeakMap.js',
    'MutationObserver/MutationObserver.js',
    'HTMLImports/HTMLImports.js',
    'CustomElements/CustomElements.js',
    'Template/Template.js',
    // these scripts are loaded here due to polyfill timing issues
    'WebComponents/unresolved.js'
  ];

  var src = script.getAttribute('src');
  var path = src.slice(0, src.lastIndexOf(file));

  modules.forEach(function(f) {
    document.write('<script src="' + path + 'src/' + f + '"></script>');
  });

  // exports
  WebComponents.flags = flags;

})();
<commit_msg>Include rAF/dom.js in wc-lite's dependency list<commit_after>/**
 * @license
 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */

(function() {

  // Establish scope.
  window.WebComponents = window.WebComponents || {flags:{}};

  // loading script
  var file = 'webcomponents-lite.js';
  var script = document.querySelector('script[src*="' + file + '"]');

  // Flags. Convert url arguments to flags
  var flags = {};
  if (!flags.noOpts) {
    // from url
    location.search.slice(1).split('&').forEach(function(option) {
      var parts = option.split('=');
      var match;
      if (parts[0] && (match = parts[0].match(/wc-(.+)/))) {
        flags[match[1]] = parts[1] || true;
      }
    });
    // from script
    if (script) {
      for (var i=0, a; (a=script.attributes[i]); i++) {
        if (a.name !== 'src') {
          flags[a.name] = a.value || true;
        }
      }
    }
    // log flags
    if (flags.log && flags.log.split) {
      var parts = flags.log.split(',');
      flags.log = {};
      parts.forEach(function(f) {
        flags.log[f] = true;
      });
    } else {
      flags.log = {};
    }
  }

  // construct full dependency list
  var modules = [
    'URL/URL.js',
    'WeakMap/WeakMap.js',
    'MutationObserver/MutationObserver.js',
    'HTMLImports/HTMLImports.js',
    'CustomElements/CustomElements.js',
    'Template/Template.js',
    // these scripts are loaded here due to polyfill timing issues
    'WebComponents/dom.js',
    'WebComponents/unresolved.js'
  ];

  var src = script.getAttribute('src');
  var path = src.slice(0, src.lastIndexOf(file));

  modules.forEach(function(f) {
    document.write('<script src="' + path + 'src/' + f + '"></script>');
  });

  // exports
  WebComponents.flags = flags;

})();
<|endoftext|>


<commit_before>'use strict';

/* global chrome */

var queryInfo = {
    active: true,
    currentWindow: true
};

chrome.runtime.onMessage.addListener(function (msg, sender) {
    if (msg.origin && msg.token && msg.title) {
        localStorage.origin = msg.origin;
        localStorage.token = msg.token;
        localStorage.title = msg.title;
        show('home');
    }
});

function getCurrentTabUrl(callback) {
    chrome.tabs.query(queryInfo, function(tabs) {
        callback(tabs[0].url);
    });
}

function tryToDetectSettings() {
    chrome.tabs.query(queryInfo, function(tabs) {
        chrome.tabs.executeScript(tabs[0].id, { file: 'detectapp.js' });
    });
}

tryToDetectSettings();

document.addEventListener('DOMContentLoaded', function() {
    if (!localStorage.token) {
        show('setup');
    } else {
        show('main');
    }

    document.getElementById('actionAdd').addEventListener('click', add);

    getCurrentTabUrl(function(url) {
        document.getElementById('content').value = url;
    });
});

var views = [
    'main',
    'done',
    'home',
    'setup',
    'busy'
];

function show(view) {
    views.forEach(function (view) {
        document.getElementById(view).style.display = 'none';
    });

    document.getElementById(view).style.display = 'block';
}

function add() {
    show('busy');

    var http = new XMLHttpRequest();
    var url = localStorage.origin + '/api/things?token=' + localStorage.token;
    var body = JSON.stringify({ content: document.getElementById('content').value });

    http.open('POST', url, true);

    http.setRequestHeader('Content-type', 'application/json');
    http.setRequestHeader('Content-length', body.length);
    http.setRequestHeader('Connection', 'close');

    http.onreadystatechange = function() {//Call a function when the state changes.
        if(http.readyState === 4) {
            if (http.status === 401) {
                delete localStorage.token;
                show('setup');
                return;
            }
            if (http.status === 201) return show('done');
        }
    };
    http.send(body);
}<commit_msg>Set focus on the input field<commit_after>'use strict';

/* global chrome */

var queryInfo = {
    active: true,
    currentWindow: true
};

chrome.runtime.onMessage.addListener(function (msg, sender) {
    if (msg.origin && msg.token && msg.title) {
        localStorage.origin = msg.origin;
        localStorage.token = msg.token;
        localStorage.title = msg.title;
        show('home');
    }
});

function getCurrentTabUrl(callback) {
    chrome.tabs.query(queryInfo, function(tabs) {
        callback(tabs[0].url);
    });
}

function tryToDetectSettings() {
    chrome.tabs.query(queryInfo, function(tabs) {
        chrome.tabs.executeScript(tabs[0].id, { file: 'detectapp.js' });
    });
}

tryToDetectSettings();

document.addEventListener('DOMContentLoaded', function() {
    if (!localStorage.token) {
        show('setup');
    } else {
        show('main');

        document.getElementById('actionAdd').addEventListener('click', add);

        getCurrentTabUrl(function(url) {
            document.getElementById('content').value = url + '\n\n';
        });

        // setting autofocus or set focus immediately wont work
        setTimeout(function () { document.getElementById('content').focus(); }, 250);
    }
});

var views = [
    'main',
    'done',
    'home',
    'setup',
    'busy'
];

function show(view) {
    views.forEach(function (view) {
        document.getElementById(view).style.display = 'none';
    });

    document.getElementById(view).style.display = 'block';
}

function add() {
    show('busy');

    var http = new XMLHttpRequest();
    var url = localStorage.origin + '/api/things?token=' + localStorage.token;
    var body = JSON.stringify({ content: document.getElementById('content').value });

    http.open('POST', url, true);

    http.setRequestHeader('Content-type', 'application/json');
    http.setRequestHeader('Content-length', body.length);
    http.setRequestHeader('Connection', 'close');

    http.onreadystatechange = function() {//Call a function when the state changes.
        if(http.readyState === 4) {
            if (http.status === 401) {
                delete localStorage.token;
                show('setup');
                return;
            }
            if (http.status === 201) return show('done');
        }
    };
    http.send(body);
}<|endoftext|>


<commit_before>// ==UserScript==
// @name        7DTD Webmap Annotations
// @namespace   http://fienen.com
// @include     http://*/static/index.html
// @version     0.1
// ==/UserScript==

// ===============================================================================================
// Add Marker control

L.Control.AddMarker = L.Control.extend({
	options: {
		position: 'bottomleft'
	},

	onAdd: function (map) {
		var name = 'control-addmarker',
		    container = L.DomUtil.create('div', name + ' leaflet-bar');

		this._map = map;

		this._reloadbutton = this._createButton(
			"Add Marker", "Add Marker",
			name + "-btn", container, this._reload, this);

		return container;
	},

	onRemove: function (map) {
	},

	_reload: function (e) {
		tileTime = new Date().getTime();
		tileLayer.redraw();
		tileLayerMiniMap.redraw();
	},

	_createButton: function (html, title, className, container, fn, context) {
		var link = L.DomUtil.create('a', className, container);
		link.innerHTML = html;
		link.href = '#';
		link.title = title;

		var stop = L.DomEvent.stopPropagation;

		L.DomEvent
		    .on(link, 'click', stop)
		    .on(link, 'mousedown', stop)
		    .on(link, 'dblclick', stop)
		    .on(link, 'click', L.DomEvent.preventDefault)
		    .on(link, 'click', fn, context)
		    .on(link, 'click', this._refocusOnMap, context);

		return link;
	}

});

new L.Control.AddMarker({
}).addTo(map);<commit_msg>Resolves #7<commit_after>// ==UserScript==
// @name        7DTD Webmap Annotations
// @namespace   http://fienen.com
// @include     http://*/static/index.html
// @version     0.1
// ==/UserScript==

// Loading confirmation
console.log('Initializing 7DTD Webmap Annotations script...');

// ===============================================================================================
// Add Marker control

L.Control.AddMarker = L.Control.extend({
	/*
	options: {
		position: 'bottomleft'
	},
	*/

	onAdd: function (map) {
		var name = 'control-addmarker',
		    container = L.DomUtil.create('div', name + ' leaflet-bar');

		this._map = map;

		this._reloadbutton = this._createButton(
			"Add Marker", "Add Marker",
			name + "-btn", container, this._reload, this);

		return container;
	},

	onRemove: function (map) {
	},

	_reload: function (e) {
		tileTime = new Date().getTime();
		tileLayer.redraw();
		tileLayerMiniMap.redraw();
	},

	_createButton: function (html, title, className, container, fn, context) {
		var link = L.DomUtil.create('a', className, container);
		link.innerHTML = html;
		link.href = '#';
		link.title = title;

		var stop = L.DomEvent.stopPropagation;

		L.DomEvent
		    .on(link, 'click', stop)
		    .on(link, 'mousedown', stop)
		    .on(link, 'dblclick', stop)
		    .on(link, 'click', L.DomEvent.preventDefault)
		    .on(link, 'click', fn, context)
		    .on(link, 'click', this._refocusOnMap, context);

		return link;
	}

});

new L.Control.AddMarker({
}).addTo(map);

// Loading complete confirmation
console.log('7DTD Webmap Annotations initialization complete.');<|endoftext|>


<commit_before>var TLDS = TLDS || [];
if (typeof require != 'undefined') {
	TLDS = require('./tlds').TLDS;
}

function loadValidTLDS() {
	var tldsArray = [];

	TLDS.forEach(function(tld){
		tldsArray.push('\\.' + tld + '(?!\\.|\\w)');
	});

	return tldsArray.join('|');
}

var validLinkMarkDownRegEx = new RegExp('[a-zA-Z0-9](' + loadValidTLDS() + ')|^https?:\\/\\/[a-zA-Z0-9]', "i");

var _ = _ || null;
if ((typeof require != 'undefined') && !_) {
	var _ = require('underscore');
}

var Markdown = function(raw, options) {
	var options = options || {};
	if (!raw) {
		return '';
	}
	if (!options.dont_escape) {
		raw = _.escape(raw);
	}
	var code_blocks = {};
	var block_count = 0;
	var quote_tag = options.use_blockquote ? 'span class="blockquote"' : 'q';
	var end_quote_tag = options.use_blockquote ? '/span' : '/q';
	var bench = +new Date();
	var link_last_offset = bold_last_offset = italic_last_offset = strike_last_offset = underline_last_offset = 0;
	var test = 0;
	var total = 0;
	var link_was_inside_tag = bold_in_url = italic_in_url = strike_in_url = underline_in_url = false;
	var val = raw.replace(/\&\#x2F;/g, '/'). // not sure why underscore replaces these...docs don't even claim that it does
		replace(/\[([^\]]*?)\]\(([\s\S]*?)\)/g, function(full_match, text, link) {
			if (text === 'code') {
				return full_match;
			}

			if(!validLinkMarkDownRegEx.test(link)) {
				return full_match;
			}

			return "" + text + "";

		}).
		replace(/\[code\]([\s\S]*?)(\[\/code\]|$)/gi, function(full_match, text) {
			var code;
			try {
				code = unescape(text);
				code = code.replace(/</g, '<').replace(/>/g, '>');
			}
			catch(error) {
				code = text.replace(/(\%\w\w)/g, function(fm, esc) {
					return unescape(esc);
				});
			}
			code_blocks['code_' + block_count] = code;
			var to_return = '[code_' + block_count + ']';
			block_count++;
			return to_return;
		}).
		replace(Markdown.global_url_regex, function(
			full_match,
			maybe_email1,
			maybe_email2,
			link,
			proto_and_slashes,
			protocol,
			junk,
			junkpoint5,
			junk1,
			junk2,
			junk3,
			junk4,
			junk5,
			junk6,
			last_char,
			offset,
			full_str
	) {
			if(!validLinkMarkDownRegEx.test(link)) {
				return full_match;
			}

			var sub_bench = +new Date();
			var start = full_str.substr(link_last_offset, offset - link_last_offset);
			link_last_offset = offset;
			if (start.match(/.*\($/)) {
				return full_match;
			}
			var inside_tag = link_was_inside_tag ? (start.match(/.*>[^<]*$/) ? false : true) : start.match(/.*<[^>]*$/);
			if (inside_tag) {
				link_was_inside_tag = true;
				return full_match;
			}
			link_was_inside_tag = false;
			var inside_post_tag = start.match(/.*(\{\{-\{\{)(?![\s\S]*\}\}-\}\})[\s\S]*$/);
			if (inside_post_tag) {
				return full_match;
			}
			var lead_match = full_str.substring(0, offset);
			var lead_str = lead_match + full_match;
			var link_matches = lead_str.replace(/\{\{\-\{\{/g, '<').replace(/\}\}-\}\}/g, '>').match(/^[\s\S]*([\s\S]*?)$/);
			if (link_matches) {
				var link_match = link_matches[1];
				if (!link_match.match(/<\/a>/) || link_match.match(/<\/a>$/)) {
					return full_match;
				}
			}
			//console.warn("nomatch:", +new Date() - sub_bench);
			return "" +
					(maybe_email2 ? maybe_email2 : '') +
					link + "" + last_char;
		}).
		replace(/\|([^\n]*)\|(\s|\n|$)/g, function(full_match, text) {
			var cols = text.split(/\|/);
			if (!cols.length) {
				return text;
			}
			var percent = (100 / cols.length).toFixed(0);
			return "

" +
					cols.join("	") +
				"

";
		}).
		replace(/<\/table>
/g, '').
		replace(/((^|\n)\* [^\*\n]*)+/g, function(full_match, junk, start) {
			var parts = full_match.split(/\n/);
			if (parts[0].length === 0) {
				parts.shift();
			}
			return start + "

" +
				parts.map(function(part) { return part.replace(/^\* /, ''); }).
					join("

") +
				"

";
		}).
		replace(/\*\*(\S[^\*\*]*?\S)\*\*/g, function(full_match, text, offset, full_str) {
			total++;
			if (Markdown.is_in_url(full_match, text, offset, full_str, bold_in_url, bold_last_offset)) {
				bold_last_offset = offset;
				bold_in_url = true;
				return full_match;
			}
			bold_last_offset = offset;
			bold_in_url = false;
			return "" + text + "";
		}).
		replace(/\*(\S[^\*]*?\S)\*/g, function(full_match, text, offset, full_str) {
			if (Markdown.is_in_url(full_match, text, offset, full_str, italic_in_url, italic_last_offset)) {
				italic_last_offset = offset;
				italic_in_url = true;
				return full_match;
			}
			italic_last_offset = offset;
			italic_in_url = false;
			return "" + text + "";
		}).
		replace(/__(\S[^__]*?\S)__/g, function(full_match, text, offset, full_str) {
			if (Markdown.is_in_url(full_match, text, offset, full_str, underline_in_url, underline_last_offset)) {
				underline_last_offset = offset;
				underline_in_url = true;
				return full_match;
			}
			underline_last_offset = offset;
			underline_in_url = false;
			return "" + text + "";
		}).
		replace(/~~(\S[^~~]*?\S)~~/g, function(full_match, text, offset, full_str) {
			if (Markdown.is_in_url(full_match, text, offset, full_str, strike_in_url, strike_last_offset)) {
				strike_last_offset = offset;
				strike_in_url = true;
				return full_match;
			}
			strike_last_offset = offset;
			strike_in_url = false;
			return "" + text + "";
		}).
		replace(/\{\{\[\[-([^\{\{\[\[]*?)-\]\]\}\}/g, function(full_match, text, offset, full_str) {
			return "" + text + "";
		}).
		replace(/(^|\n)> ([^\n]*)/g, function(full_match, start, text) {
			return start + "<" + quote_tag + ">" + text + "<" + end_quote_tag + ">";
		}).
		replace(/\[code_(\w+)\]/g, function(full_match, which) {
			return "
" + code_blocks['code_' + which] + "
";
		}).
		replace(/mailto:<a href=/g, function(full_match, which) {
			return "[^<]*$/) : start.match(/.*<[^>]*$/);
	if (inside_tag) { return true; }
	var last_str = /([A-Za-z0-9\!\#\$\%\&\'\*\+\-\/\=\?\%\_\`\{\|\}\~\.\:]+)$/g.exec(start);
	if (last_str) {
		var potential_url = last_str[0] + text;
		if (potential_url.match(Markdown.url_regex)) {
			return true;
		}
	}
	return false;
};

var Markdown_Is_Valid_Link = function(link) {
	return validLinkMarkDownRegEx.test(link);
}

Markdown.tld_url_regex = validLinkMarkDownRegEx;
Markdown.url_regex = /^((ftp|https?):\/\/)?[-\w]+\.([-\w]+\.)*(\d+\.\d+\.\d+|[-A-Za-z]+)(:\d+)?($|(\/\S?(\/\S)*\/?)|(\#\S?)|(\?\S?))/i;
Markdown.global_url_regex = /(([a-zA-Z0-9\!\#\$\%\&\'\*\+\-\/\=\?\%\_\`\{\|\}\~\.]+@)?)(((ftp|https?):\/\/)?[-\w]+\.([-\w]+\.)*(\d+\.\d+\.\d+|[-A-Za-z]+)(:\d+)?(((\/([A-Za-z0-9-\._~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=])*)+)\??([A-Za-z0-9-\._~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\%])*)?)([^A-Za-z]|$)/gi;

var Markdown_For_Search = function(raw, options) {
	options = options || {};
	if (!raw) { return ''; }
	if (!options.dont_escape) {
		raw = _.escape(raw);
	}
	return raw.replace(/\{\{\[\[-([^\{\{\[\[]*?)-\]\]\}\}/g, function(full_match, text) {
		return "" + text + "";
	});
};

var Remove_Markdown = function(raw, options) {
	options = options || {};
	return (options.dont_escape ? raw : _.escape(raw)).
		replace(/\&\#x2F;/g, '/'). // not sure why underscore replaces these...docs don't even claim that it does
		replace(/\[code\]/g, '').
		replace(/\[\/code\]/g,'').
		replace(/\|([^\n]*)\|/g, function(full_match, text) {
			var cols = text.split(/\|/);
			if (!cols.length) {
				return text;
			}
			return cols.join('\t');
		}).
		replace(/\*\*(\S[^\*\*]*?\S)\*\*/g, function(full_match, text) {
			return text;
		}).
		// replace(/\`(.*?)\`/g, function(full_match, text) {
		// 	return text;
		// }).
		replace(/\*(\S[^\*]*?\S)\*/g, function(full_match, text) {
			return text;
		}).
		replace(/__(\S[^__]*?\S)__/g, function(full_match, text) {
			return text;
		}).
		replace(/~~(\S[^~~]*?\S)~~/g, function(full_match, text) {
			return text;
		}).
		replace(/(^|\n)> ([^\n]*)/g, function(full_match, start, text) {
			return start + " " + text + " ";
		}).
		replace(/\[([^\]]*?)\]\(([\s\S]*?)\)/g, function(full_match, text, link) {
			return text;
		});
};

if (typeof exports == 'object') {
	exports.Markdown = Markdown;
	exports.Remove_Markdown = Remove_Markdown;
	exports.Markdown_For_Search = Markdown_For_Search;
	exports.Markdown_Is_Valid_Link = Markdown_Is_Valid_Link;
}
<commit_msg>don't open new tab for on-domain links<commit_after>var TLDS = TLDS || [];
if (typeof require != 'undefined') {
	TLDS = require('./tlds').TLDS;
}

function loadValidTLDS() {
	var tldsArray = [];

	TLDS.forEach(function(tld){
		tldsArray.push('\\.' + tld + '(?!\\.|\\w)');
	});

	return tldsArray.join('|');
}

var validLinkMarkDownRegEx = new RegExp('[a-zA-Z0-9](' + loadValidTLDS() + ')|^https?:\\/\\/[a-zA-Z0-9]', "i");

var _ = _ || null;
if ((typeof require != 'undefined') && !_) {
	var _ = require('underscore');
}

var Markdown = function(raw, options) {
	var options = options || {};
	if (!raw) {
		return '';
	}
	if (!options.dont_escape) {
		raw = _.escape(raw);
	}
	var code_blocks = {};
	var block_count = 0;
	var quote_tag = options.use_blockquote ? 'span class="blockquote"' : 'q';
	var end_quote_tag = options.use_blockquote ? '/span' : '/q';
	var bench = +new Date();
	var link_last_offset = bold_last_offset = italic_last_offset = strike_last_offset = underline_last_offset = 0;
	var test = 0;
	var total = 0;
	var link_was_inside_tag = bold_in_url = italic_in_url = strike_in_url = underline_in_url = false;
	var val = raw.replace(/\&\#x2F;/g, '/'). // not sure why underscore replaces these...docs don't even claim that it does
		replace(/\[([^\]]*?)\]\(([\s\S]*?)\)/g, function(full_match, text, link) {
			if (text === 'code') {
				return full_match;
			}

			if(!validLinkMarkDownRegEx.test(link)) {
				return full_match;
			}

			if (window && window.location && window.location.origin) {
				if (link.indexOf(window.location.origin) === 0) {
					return "" + text + "";
				}
			}

			return "" + text + "";

		}).
		replace(/\[code\]([\s\S]*?)(\[\/code\]|$)/gi, function(full_match, text) {
			var code;
			try {
				code = unescape(text);
				code = code.replace(/</g, '<').replace(/>/g, '>');
			}
			catch(error) {
				code = text.replace(/(\%\w\w)/g, function(fm, esc) {
					return unescape(esc);
				});
			}
			code_blocks['code_' + block_count] = code;
			var to_return = '[code_' + block_count + ']';
			block_count++;
			return to_return;
		}).
		replace(Markdown.global_url_regex, function(
			full_match,
			maybe_email1,
			maybe_email2,
			link,
			proto_and_slashes,
			protocol,
			junk,
			junkpoint5,
			junk1,
			junk2,
			junk3,
			junk4,
			junk5,
			junk6,
			last_char,
			offset,
			full_str
	) {
			if(!validLinkMarkDownRegEx.test(link)) {
				return full_match;
			}

			var sub_bench = +new Date();
			var start = full_str.substr(link_last_offset, offset - link_last_offset);
			link_last_offset = offset;
			if (start.match(/.*\($/)) {
				return full_match;
			}
			var inside_tag = link_was_inside_tag ? (start.match(/.*>[^<]*$/) ? false : true) : start.match(/.*<[^>]*$/);
			if (inside_tag) {
				link_was_inside_tag = true;
				return full_match;
			}
			link_was_inside_tag = false;
			var inside_post_tag = start.match(/.*(\{\{-\{\{)(?![\s\S]*\}\}-\}\})[\s\S]*$/);
			if (inside_post_tag) {
				return full_match;
			}
			var lead_match = full_str.substring(0, offset);
			var lead_str = lead_match + full_match;
			var link_matches = lead_str.replace(/\{\{\-\{\{/g, '<').replace(/\}\}-\}\}/g, '>').match(/^[\s\S]*([\s\S]*?)$/);
			if (link_matches) {
				var link_match = link_matches[1];
				if (!link_match.match(/<\/a>/) || link_match.match(/<\/a>$/)) {
					return full_match;
				}
			}
			//console.warn("nomatch:", +new Date() - sub_bench);
			var no_blank = false;
			if (window && window.location && window.location.origin) {
				var full_link = protocol + link;
				if (full_link.indexOf(window.location.origin) === 0) {
					no_blank = true;
				}
			}

			return "" +
					(maybe_email2 ? maybe_email2 : '') +
					link + "" + last_char;
		}).
		replace(/\|([^\n]*)\|(\s|\n|$)/g, function(full_match, text) {
			var cols = text.split(/\|/);
			if (!cols.length) {
				return text;
			}
			var percent = (100 / cols.length).toFixed(0);
			return "

" +
					cols.join("	") +
				"

";
		}).
		replace(/<\/table>
/g, '').
		replace(/((^|\n)\* [^\*\n]*)+/g, function(full_match, junk, start) {
			var parts = full_match.split(/\n/);
			if (parts[0].length === 0) {
				parts.shift();
			}
			return start + "

" +
				parts.map(function(part) { return part.replace(/^\* /, ''); }).
					join("

") +
				"

";
		}).
		replace(/\*\*(\S[^\*\*]*?\S)\*\*/g, function(full_match, text, offset, full_str) {
			total++;
			if (Markdown.is_in_url(full_match, text, offset, full_str, bold_in_url, bold_last_offset)) {
				bold_last_offset = offset;
				bold_in_url = true;
				return full_match;
			}
			bold_last_offset = offset;
			bold_in_url = false;
			return "" + text + "";
		}).
		replace(/\*(\S[^\*]*?\S)\*/g, function(full_match, text, offset, full_str) {
			if (Markdown.is_in_url(full_match, text, offset, full_str, italic_in_url, italic_last_offset)) {
				italic_last_offset = offset;
				italic_in_url = true;
				return full_match;
			}
			italic_last_offset = offset;
			italic_in_url = false;
			return "" + text + "";
		}).
		replace(/__(\S[^__]*?\S)__/g, function(full_match, text, offset, full_str) {
			if (Markdown.is_in_url(full_match, text, offset, full_str, underline_in_url, underline_last_offset)) {
				underline_last_offset = offset;
				underline_in_url = true;
				return full_match;
			}
			underline_last_offset = offset;
			underline_in_url = false;
			return "" + text + "";
		}).
		replace(/~~(\S[^~~]*?\S)~~/g, function(full_match, text, offset, full_str) {
			if (Markdown.is_in_url(full_match, text, offset, full_str, strike_in_url, strike_last_offset)) {
				strike_last_offset = offset;
				strike_in_url = true;
				return full_match;
			}
			strike_last_offset = offset;
			strike_in_url = false;
			return "" + text + "";
		}).
		replace(/\{\{\[\[-([^\{\{\[\[]*?)-\]\]\}\}/g, function(full_match, text, offset, full_str) {
			return "" + text + "";
		}).
		replace(/(^|\n)> ([^\n]*)/g, function(full_match, start, text) {
			return start + "<" + quote_tag + ">" + text + "<" + end_quote_tag + ">";
		}).
		replace(/\[code_(\w+)\]/g, function(full_match, which) {
			return "
" + code_blocks['code_' + which] + "
";
		}).
		replace(/mailto:<a href=/g, function(full_match, which) {
			return "[^<]*$/) : start.match(/.*<[^>]*$/);
	if (inside_tag) { return true; }
	var last_str = /([A-Za-z0-9\!\#\$\%\&\'\*\+\-\/\=\?\%\_\`\{\|\}\~\.\:]+)$/g.exec(start);
	if (last_str) {
		var potential_url = last_str[0] + text;
		if (potential_url.match(Markdown.url_regex)) {
			return true;
		}
	}
	return false;
};

var Markdown_Is_Valid_Link = function(link) {
	return validLinkMarkDownRegEx.test(link);
}

Markdown.tld_url_regex = validLinkMarkDownRegEx;
Markdown.url_regex = /^((ftp|https?):\/\/)?[-\w]+\.([-\w]+\.)*(\d+\.\d+\.\d+|[-A-Za-z]+)(:\d+)?($|(\/\S?(\/\S)*\/?)|(\#\S?)|(\?\S?))/i;
Markdown.global_url_regex = /(([a-zA-Z0-9\!\#\$\%\&\'\*\+\-\/\=\?\%\_\`\{\|\}\~\.]+@)?)(((ftp|https?):\/\/)?[-\w]+\.([-\w]+\.)*(\d+\.\d+\.\d+|[-A-Za-z]+)(:\d+)?(((\/([A-Za-z0-9-\._~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=])*)+)\??([A-Za-z0-9-\._~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\%])*)?)([^A-Za-z]|$)/gi;

var Markdown_For_Search = function(raw, options) {
	options = options || {};
	if (!raw) { return ''; }
	if (!options.dont_escape) {
		raw = _.escape(raw);
	}
	return raw.replace(/\{\{\[\[-([^\{\{\[\[]*?)-\]\]\}\}/g, function(full_match, text) {
		return "" + text + "";
	});
};

var Remove_Markdown = function(raw, options) {
	options = options || {};
	return (options.dont_escape ? raw : _.escape(raw)).
		replace(/\&\#x2F;/g, '/'). // not sure why underscore replaces these...docs don't even claim that it does
		replace(/\[code\]/g, '').
		replace(/\[\/code\]/g,'').
		replace(/\|([^\n]*)\|/g, function(full_match, text) {
			var cols = text.split(/\|/);
			if (!cols.length) {
				return text;
			}
			return cols.join('\t');
		}).
		replace(/\*\*(\S[^\*\*]*?\S)\*\*/g, function(full_match, text) {
			return text;
		}).
		// replace(/\`(.*?)\`/g, function(full_match, text) {
		// 	return text;
		// }).
		replace(/\*(\S[^\*]*?\S)\*/g, function(full_match, text) {
			return text;
		}).
		replace(/__(\S[^__]*?\S)__/g, function(full_match, text) {
			return text;
		}).
		replace(/~~(\S[^~~]*?\S)~~/g, function(full_match, text) {
			return text;
		}).
		replace(/(^|\n)> ([^\n]*)/g, function(full_match, start, text) {
			return start + " " + text + " ";
		}).
		replace(/\[([^\]]*?)\]\(([\s\S]*?)\)/g, function(full_match, text, link) {
			return text;
		});
};

if (typeof exports == 'object') {
	exports.Markdown = Markdown;
	exports.Remove_Markdown = Remove_Markdown;
	exports.Markdown_For_Search = Markdown_For_Search;
	exports.Markdown_Is_Valid_Link = Markdown_Is_Valid_Link;
}
<|endoftext|>


<commit_before>var webpack = require('webpack');
var path = require('path');

module.exports = {
  devtool: 'cheap-module-eval-source-map',

  entry: ['webpack-hot-middleware/client',
          './client/index.js',
  ],

  output: {
    path: __dirname + '/dist/',
    filename: 'bundle.js',
    publicPath: '/dist/',
  },

  resolve: {
    extensions: ['', '.js', '.jsx'],
  },

  module: {
    loaders: [
      {
        test: /\.css$/,
        loader: 'style!css?modules',
      },
      {
        test: /\.jsx*$/,
        exclude: [/node_modules/, /.+\.config.js/],
        loader: 'babel',
        query: {
          presets: ['react-hmre'],
        },
      },
    ],
  },

  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ],
};
<commit_msg>Update webpack.config.dev.js<commit_after>var webpack = require('webpack');

module.exports = {
  devtool: 'cheap-module-eval-source-map',

  entry: ['webpack-hot-middleware/client',
          './client/index.js',
  ],

  output: {
    path: __dirname + '/dist/',
    filename: 'bundle.js',
    publicPath: '/dist/',
  },

  resolve: {
    extensions: ['', '.js', '.jsx'],
  },

  module: {
    loaders: [
      {
        test: /\.css$/,
        loader: 'style!css?modules',
      },
      {
        test: /\.jsx*$/,
        exclude: [/node_modules/, /.+\.config.js/],
        loader: 'babel',
        query: {
          presets: ['react-hmre'],
        },
      },
    ],
  },

  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ],
};
<|endoftext|>


<commit_before>var webpack = require('webpack');
var cssnext = require('postcss-cssnext');
var postcssFocus = require('postcss-focus');
var postcssReporter = require('postcss-reporter');

module.exports = {
  devtool: 'cheap-module-eval-source-map',

  entry: {
    app: [
      'eventsource-polyfill',
      'webpack-hot-middleware/client',
      'webpack/hot/only-dev-server',
      'react-hot-loader/patch',
      './client/index.js',
    ],
    vendor: [
      'react',
      'react-dom',
    ],
  },

  output: {
    path: __dirname,
    filename: 'app.js',
    publicPath: 'http://0.0.0.0:8000/',
  },

  resolve: {
    extensions: ['', '.js', '.jsx'],
    modules: [
      'client',
      'node_modules',
    ],
  },

  module: {
    loaders: [
      {
        test: /\.css$/,
        exclude: /node_modules/,
        loader: 'style-loader!css-loader?localIdentName=[name]__[local]__[hash:base64:5]&modules&importLoaders=1&sourceMap!postcss-loader',
      }, {
        test: /\.css$/,
        include: /node_modules/,
        loaders: ['style-loader', 'css-loader'],
      }, {
        test: /\.jsx*$/,
        exclude: [/node_modules/, /.+\.config.js/],
        loader: 'babel',
      }, {
        test: /\.(jpe?g|gif|png|svg)$/i,
        loader: 'url-loader?limit=10000',
      }, {
        test: /\.json$/,
        loader: 'json-loader',
      },
      /* Font awesome */
      {
        test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
        loader: "url?limit=10000&mimetype=application/font-woff"
      }, {
        test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
        loader: "url?limit=10000&mimetype=application/font-woff"
      }, {
        test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
        loader: "url?limit=10000&mimetype=application/octet-stream"
      }, {
        test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
        loader: "file"
      }, {
        test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
        loader: "url?limit=10000&mimetype=image/svg+xml"
      }
    ],
  },

  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: Infinity,
      filename: 'vendor.js',
    }),
    new webpack.DefinePlugin({
      'process.env': {
        CLIENT: JSON.stringify(true),
        'NODE_ENV': JSON.stringify('development'),
      }
    }),
  ],

  postcss: () => [
    postcssFocus(),
    cssnext({
      browsers: ['last 2 versions', 'IE > 10'],
    }),
    postcssReporter({
      clearMessages: true,
    }),
  ],
};
<commit_msg>Test for Heroku db<commit_after>var webpack = require('webpack');
var cssnext = require('postcss-cssnext');
var postcssFocus = require('postcss-focus');
var postcssReporter = require('postcss-reporter');

module.exports = {
  devtool: 'cheap-module-eval-source-map',

  entry: {
    app: [
      'eventsource-polyfill',
      'webpack-hot-middleware/client',
      'webpack/hot/only-dev-server',
      'react-hot-loader/patch',
      './client/index.js',
    ],
    vendor: [
      'react',
      'react-dom',
    ],
  },

  output: {
    path: __dirname,
    filename: 'app.js',
    publicPath: '/',
    // publicPath: 'http://0.0.0.0:8000/',
  },

  resolve: {
    extensions: ['', '.js', '.jsx'],
    modules: [
      'client',
      'node_modules',
    ],
  },

  module: {
    loaders: [
      {
        test: /\.css$/,
        exclude: /node_modules/,
        loader: 'style-loader!css-loader?localIdentName=[name]__[local]__[hash:base64:5]&modules&importLoaders=1&sourceMap!postcss-loader',
      }, {
        test: /\.css$/,
        include: /node_modules/,
        loaders: ['style-loader', 'css-loader'],
      }, {
        test: /\.jsx*$/,
        exclude: [/node_modules/, /.+\.config.js/],
        loader: 'babel',
      }, {
        test: /\.(jpe?g|gif|png|svg)$/i,
        loader: 'url-loader?limit=10000',
      }, {
        test: /\.json$/,
        loader: 'json-loader',
      },
      /* Font awesome */
      {
        test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
        loader: "url?limit=10000&mimetype=application/font-woff"
      }, {
        test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
        loader: "url?limit=10000&mimetype=application/font-woff"
      }, {
        test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
        loader: "url?limit=10000&mimetype=application/octet-stream"
      }, {
        test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
        loader: "file"
      }, {
        test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
        loader: "url?limit=10000&mimetype=image/svg+xml"
      }
    ],
  },

  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: Infinity,
      filename: 'vendor.js',
    }),
    new webpack.DefinePlugin({
      'process.env': {
        CLIENT: JSON.stringify(true),
        'NODE_ENV': JSON.stringify('development'),
      }
    }),
  ],

  postcss: () => [
    postcssFocus(),
    cssnext({
      browsers: ['last 2 versions', 'IE > 10'],
    }),
    postcssReporter({
      clearMessages: true,
    }),
  ],
};
<|endoftext|>