<commit_before>/**
 * GSS-API wrapper for Kerberos implementation. For now it's very
 * kerberos-specific. We can add machinery to make it generic if the
 * need ever arises.
 */
var gss = (function() {
    "use strict";

    var gss = { };

    /** @const */ gss.NT_USER_NAME         = "1.2.840.113554.1.2.1.1";
    /** @const */ gss.NT_MACHINE_UID_NAME  = "1.2.840.113554.1.2.1.2";
    /** @const */ gss.NT_STRING_UID_NAME   = "1.2.840.113554.1.2.1.3";
    /** @const */ gss.NT_HOSTBASED_SERVICE = "1.3.6.1.5.6.2";
    /** @const */ gss.NT_ANONYMOUS         = "1.3.6.1.5.6.3";
    /** @const */ gss.NT_EXPORT_NAME       = "1.3.6.1.5.6.4";

    /** @const */ gss.S_BAD_BINDINGS = 1;
    /** @const */ gss.S_BAD_MECH = 2;
    /** @const */ gss.S_BAD_NAME = 3;
    /** @const */ gss.S_BAD_NAMETYPE = 4;
    /** @const */ gss.S_BAD_STATUS = 5;
    /** @const */ gss.S_BAD_SIG = 6;
    /** @const */ gss.S_CONTEXT_EXPIRED = 7;
    /** @const */ gss.S_CREDENTIALS_EXPIRED = 8;
    /** @const */ gss.S_DEFECTIVE_CREDENTIAL = 9;
    /** @const */ gss.S_DEFECTIVE_TOKEN = 10;
    /** @const */ gss.S_FAILURE = 11;
    /** @const */ gss.S_NO_CONTEXT = 12;
    /** @const */ gss.S_NO_CRED = 13;
    /** @const */ gss.S_BAD_QOP = 14;
    /** @const */ gss.S_UNAUTHORIZED = 15;
    /** @const */ gss.S_UNAVAILABLE = 16;
    /** @const */ gss.S_DUPLICATE_ELEMENT = 17;
    /** @const */ gss.S_NAME_NOT_MN = 18;

    /** @const */ gss.S_DUPLICATE_TOKEN = 19;
    /** @const */ gss.S_OLD_TOKEN = 20;
    /** @const */ gss.S_UNSEQ_TOKEN = 21;
    /** @const */ gss.S_GAP_TOKEN = 22;

    /** @const */ gss.KRB5_MECHANISM = "1.2.840.113554.1.2.2";

    /** @const */ gss.KRB5_NT_PRINCIPAL_NAME         = "1.2.840.113554.1.2.2.1";
    /** @const */ gss.KRB5_NT_HOSTBASED_SERVICE_NAME = "1.2.840.113554.1.2.1.4";

    /** @const */ gss.KRB5_S_G_BAD_SERVICE_NAME = 1;
    /** @const */ gss.KRB5_S_G_BAD_STRING_UID = 2;
    /** @const */ gss.KRB5_S_G_NOUSER = 3;
    /** @const */ gss.KRB5_S_G_VALIDATE_FAILED = 4;
    /** @const */ gss.KRB5_S_G_BUFFER_ALLOC = 5;
    /** @const */ gss.KRB5_S_G_BAD_MSG_CTX = 6;
    /** @const */ gss.KRB5_S_G_WRONG_SIZE = 7;
    /** @const */ gss.KRB5_S_G_BAD_USAGE = 8;
    /** @const */ gss.KRB5_S_G_UNKNOWN_QOP = 9;

    /** @const */ gss.KRB5_S_KG_CCACHE_NOMATCH = 10;
    /** @const */ gss.KRB5_S_KG_KEYTAB_NOMATCH = 11;
    /** @const */ gss.KRB5_S_KG_TGT_MISSING = 12;
    /** @const */ gss.KRB5_S_KG_NO_SUBKEY = 13;
    /** @const */ gss.KRB5_S_KG_CONTEXT_ESTABLISHED = 14;
    /** @const */ gss.KRB5_S_KG_BAD_SIGN_TYPE = 15;
    /** @const */ gss.KRB5_S_KG_BAD_LENGTH = 16;
    /** @const */ gss.KRB5_S_KG_CTX_INCOMPLETE = 17;

    /**
     * @constructor
     * @param {number} major
     * @param {number} minor
     * @param {string} message
     */
    gss.Error = function(major, minor, message) {
        this.major = major;
        this.minor = minor;
        this.message = message;
    };
    /** @return {string} */
    gss.Error.prototype.toString = function() {
        return this.message;
    };

    /**
     * Creates a gss.Name that wraps a krb.Principal.
     * @constructor
     * @param {krb.Principal} principal
     */
    gss.Name = function(principal) {
        this.principal = principal;
    };
    /**
     * GSS_Import_name. For now just returns a gss.Name. If we want to
     * do some sort of host canonicalization, that may want a promise
     * object from Q.
     *
     * @param {ArrayBufferView|string} data The input bytes.
     * @param {string} nameType An OID for the name type.
     * @return {gss.Name} The resulting name.
     */
    gss.Name.importName = function(data, nameType) {
        if (nameType === gss.NT_EXPORT_NAME) {
            // TODO: For sanity, importName should take a string for
            // all the sane name types. Should we avoid type confusion
            // and just force everything into a string?
            data = arrayutils.asUint8Array(data);
            var dataview = new DataView(data.buffer,
                                        data.byteOffset,
                                        data.byteLength);
            // Strip off the header.
            if (data.length < 4)
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad format");
            if (dataview.getUint16(0) != 0x0401)
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad TOK_ID");
            var mechOidLen = dataview.getUint16(2);
            if (data.length < 4 + mechOidLen + 4)
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad format");
            try {
                var mechOid = asn1.OBJECT_IDENTIFIER.decodeDER(
                    data.subarray(4, 4 + mechOidLen));
            } catch (e) {
                if (e instanceof asn1.Error)
                    throw new gss.Error(gss.S_BAD_NAME, 0, e.toString());
                throw e;
            }
            // We only support KRB5.
            if (mechOid !== gss.KRB5_MECHANISM)
                throw new gss.Error(gss.S_BAD_MECH, 0,
                                    "Only krb5 names supported");
            var nameLen = dataview.getUint32(4 + mechOidLen);
            if (data.length != (4 + mechOidLen + 4 + nameLen))
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad length");
            try {
                return new gss.Name(krb.Principal.fromString(
                    arrayutils.toUTF16(data.subarray(4 + mechOidLen + 4))));
            } catch (e) {
                throw new gss.Error(gss.S_BAD_NAME, 0, e);
            }
        } else if (nameType === gss.NT_HOSTBASED_SERVICE ||
                   nameType === gss.KRB5_NT_HOSTBASED_SERVICE_NAME) {
            // Format is service@hostname. Hostname is optional, but
            // for now require it. Probably the most reasonable
            // interpretation of "the canonicalized name of the local
            // host" is location.host, but meh.
            var at = data.indexOf("@");
            if (at < 0)
                throw new gss.Error(
                    gss.S_BAD_NAME, gss.KRB5_S_G_BAD_SERVICE_NAME,
                    "Default host not supported");
            var service = data.substring(0, at);
            var host = data.substring(at + 1);
            // FIXME: Hostname canonicalization??
            return new gss.Name(new krb.Principal({
                nameType: krb.KRB_NT_SRV_HST,
                nameString: [service, host]
            }, krb.realm));
        } else if (nameType === gss.KRB5_NT_PRINCIPAL_NAME) {
            try {
                return new gss.Name(krb.Principal.fromString(data));
            } catch (e) {
                throw new gss.Error(gss.S_BAD_NAME, 0, e);
            }
        } else if (nameType === gss.NT_USER_NAME) {
            return new gss.Name(new krb.Principal({
                nameType: krb.KRB_NT_PRINCIPAL,
                nameString: [data]
            }, krb.realm));
        } else {
            throw new gss.Error(gss.S_BAD_NAMETYPE, 0, "Bad nametype");
        }
    };
    gss.Name.prototype.canonicalize = function() {
        // TODO
    };
    /** @return {Uint8Array} */
    gss.Name.prototype.exportName = function() {
        // Build it backwards.
        var b = new asn1.Buffer();
        var nameLen =
            b.prependBytes(arrayutils.fromUTF16(this.principal.toString()));
        b.prependUint32(name.length);
        var mechOidLen =
            asn1.OBJECT_IDENTIFIER.encodeDERTriple(gss.KRB5_MECHANISM, b);
        b.prependUint16(mechOidLen);
        // tokId is 0x04 0x01
        b.prependUint16(0x0401);
        return b.contents();
    };

    var GSSAPI_TOKEN_TAG = 0x60;  // [APPLICATION 0]

    var TOK_ID_AP_REQ = "\x01\x00";
    var TOK_ID_AP_REP = "\x02\x00";
    var TOK_ID_ERROR  = "\x03\x00";

    /** @param {ArrayBufferView}
     *  @returns {{thisMech:string, innerToken:Uint8Array}}
     */
    function decodeGSSToken(token) {
        try {
            // This is weirdo pseudo-ASN.1 with a hole in it. We could
            // hack it into our parser, but it's easy to parse manually.
            var tvr = asn1.decodeTagLengthValueDER(token);
            var tag = tvr[0], value = tvr[1], rest = tvr[2];
            if (tag !== GSSAPI_TOKEN_TAG)
                throw new gss.Error(gss.S_DEFECTIVE_TOKEN, 0, "Bad token");
            if (rest)  // Bad length.
                throw new gss.Error(gss.S_DEFECTIVE_TOKEN, 0, "Bad token");

            // Pull out the mechanism.
            var mr = asn1.OBJECT_IDENTIFIER.decodeDERPrefix(value);
            var mech = mr[0], rest = mr[1];

            return {
                thisMech: mech,
                innerToken: rest
            };
        } catch (e) {
            if (e instanceof asn1.Error)
                throw new gss.Error(gss.S_DEFECTIVE_TOKEN, 0, e.toString());
            throw e;
        }
    }

    var DELEG_FLAG    = 1;
    var MUTUAL_FLAG   = 2;
    var REPLAY_FLAG   = 4;
    var SEQUENCE_FLAG = 8;
    var CONF_FLAG     = 16;
    var INTEG_FLAG    = 32;

    // Context states.
    var INITIAL_STATE = 1;
    var PENDING_AP_REP = 2;
    var ESTABLISHED_STATE = 3;

    /**
     * Creates an initiator GSS context. If the need ever arises, we
     * can arrange for acceptor contexts to be supported, but it's
     * unlikely this'll ever run outside a client.
     *
     * The constructor takes an options dictionary with various
     * optional keys. The keys are:
     *   delegation : boolean
     *   mutualAuthentication : boolean
     *   replayDetection : boolean
     *   sequence : boolean
     *   anonymous : boolean
     *   confidentiality : boolean
     *   integrity : boolean
     *   lifetime : number (default: 0)
     *   bindings : ?ArrayBufferView (default: null)
     *
     * Not all flags can be provided, so the corresponding attributes
     * should be checked on the returned gss.Context object.
     *
     * @constructor
     */
    gss.Context = function(peer, mechanism, credential, opts) {
        if (mechanism !== gss.KRB5_MECHANISM)
            throw new gss.Error(gss.S_BAD_MECH, 0, "Only krb5 is supported");
        this.state = INITIAL_STATE;
        this.credential = credential;
        this.peer = peer;

        // this.delegation = opts.delegation || false;
        this.mutualAuthentication = opts.mutualAuthentication || false;
        this.replayDetection = opts.replayDetection || false;
        this.sequence = opts.sequence || false;
        // this.anonymous = opts.anonymous || false;
        this.confidentiality = opts.confidentiality || false;
        this.integrity = opts.integrity || false;

        // TODO: This is actually the MD5 sum of something...
        this.bindings = opts.bindings || new Uint8Array(16);

        // TODO...
    };
    gss.Context.prototype.initSecContext = function(token) {
        if (this.state === INITIAL_STATE) {
            var cksumBuf = new asn1.Buffer();
            //  Octet      Name      Description
            // ---------------------------------------------------------------
            //  n..last    Exts    Extensions [optional].
            if (this.delegation) {
                //  28..(n-1)  Deleg   A KRB_CRED message (n = Dlgth + 28)
                //                     [optional].
                //  26..27     Dlgth   The length of the Deleg field in
                //                     little-endian order [optional].
                //  24..25     DlgOpt  The delegation option identifier (=1) in
                //                     little-endian order [optional].  This
                //                     field and the next two fields are present
                //                     if and only if GSS_C_DELEG_FLAG is set as
                //                     described in section 4.1.1.1.
                throw "Delegation not implemented.";
            }
            //  20..23     Flags   Four-octet context-establishment flags in
            //                     little-endian order as described in section
            //                     4.1.1.1.
            var flags = 0;
            if (this.delegation)
                flags |= DELEG_FLAG;
            if (this.mutualAuthentication)
                flags |= MUTUAL_FLAG;
            if (this.replayDetection)
                flags |= REPLAY_FLAG;
            if (this.sequence)
                flags |= SEQUENCE_FLAG;
            if (this.confidentiality)
                flags |= CONF_FLAG;
            if (this.integrity)
                flags |= INTEG_FLAG;
            cksumBuf.prependUint32(flags, true);
            //  4..19      Bnd     Channel binding information, as described in
            //                     section 4.1.1.2.
            var bndLen = cksumBuf.prependBytes(this.bindings);
            //  0..3       Lgth    Number of octets in Bnd field;  Represented
            //                     in little-endian order;  Currently contains
            //                     hex value 10 00 00 00 (16).
            cksumBuf.prependUint32(bndLen, true);
            var apReq = this.credential.makeAPReq(
                ???,
                { cksumtype: 0x8003,
                  checksum: cksumBuf.contents() },
                ???,
                ???);
        }
        // TODO
    };
    gss.Context.prototype.isEstablished = function() {
        // TODO
    };

    return gss;
}());
<commit_msg>Have constants for TOK_ID values<commit_after>/**
 * GSS-API wrapper for Kerberos implementation. For now it's very
 * kerberos-specific. We can add machinery to make it generic if the
 * need ever arises.
 */
var gss = (function() {
    "use strict";

    var gss = { };

    /** @const */ gss.NT_USER_NAME         = "1.2.840.113554.1.2.1.1";
    /** @const */ gss.NT_MACHINE_UID_NAME  = "1.2.840.113554.1.2.1.2";
    /** @const */ gss.NT_STRING_UID_NAME   = "1.2.840.113554.1.2.1.3";
    /** @const */ gss.NT_HOSTBASED_SERVICE = "1.3.6.1.5.6.2";
    /** @const */ gss.NT_ANONYMOUS         = "1.3.6.1.5.6.3";
    /** @const */ gss.NT_EXPORT_NAME       = "1.3.6.1.5.6.4";

    /** @const */ gss.S_BAD_BINDINGS = 1;
    /** @const */ gss.S_BAD_MECH = 2;
    /** @const */ gss.S_BAD_NAME = 3;
    /** @const */ gss.S_BAD_NAMETYPE = 4;
    /** @const */ gss.S_BAD_STATUS = 5;
    /** @const */ gss.S_BAD_SIG = 6;
    /** @const */ gss.S_CONTEXT_EXPIRED = 7;
    /** @const */ gss.S_CREDENTIALS_EXPIRED = 8;
    /** @const */ gss.S_DEFECTIVE_CREDENTIAL = 9;
    /** @const */ gss.S_DEFECTIVE_TOKEN = 10;
    /** @const */ gss.S_FAILURE = 11;
    /** @const */ gss.S_NO_CONTEXT = 12;
    /** @const */ gss.S_NO_CRED = 13;
    /** @const */ gss.S_BAD_QOP = 14;
    /** @const */ gss.S_UNAUTHORIZED = 15;
    /** @const */ gss.S_UNAVAILABLE = 16;
    /** @const */ gss.S_DUPLICATE_ELEMENT = 17;
    /** @const */ gss.S_NAME_NOT_MN = 18;

    /** @const */ gss.S_DUPLICATE_TOKEN = 19;
    /** @const */ gss.S_OLD_TOKEN = 20;
    /** @const */ gss.S_UNSEQ_TOKEN = 21;
    /** @const */ gss.S_GAP_TOKEN = 22;

    /** @const */ gss.KRB5_MECHANISM = "1.2.840.113554.1.2.2";

    /** @const */ gss.KRB5_NT_PRINCIPAL_NAME         = "1.2.840.113554.1.2.2.1";
    /** @const */ gss.KRB5_NT_HOSTBASED_SERVICE_NAME = "1.2.840.113554.1.2.1.4";

    /** @const */ gss.KRB5_S_G_BAD_SERVICE_NAME = 1;
    /** @const */ gss.KRB5_S_G_BAD_STRING_UID = 2;
    /** @const */ gss.KRB5_S_G_NOUSER = 3;
    /** @const */ gss.KRB5_S_G_VALIDATE_FAILED = 4;
    /** @const */ gss.KRB5_S_G_BUFFER_ALLOC = 5;
    /** @const */ gss.KRB5_S_G_BAD_MSG_CTX = 6;
    /** @const */ gss.KRB5_S_G_WRONG_SIZE = 7;
    /** @const */ gss.KRB5_S_G_BAD_USAGE = 8;
    /** @const */ gss.KRB5_S_G_UNKNOWN_QOP = 9;

    /** @const */ gss.KRB5_S_KG_CCACHE_NOMATCH = 10;
    /** @const */ gss.KRB5_S_KG_KEYTAB_NOMATCH = 11;
    /** @const */ gss.KRB5_S_KG_TGT_MISSING = 12;
    /** @const */ gss.KRB5_S_KG_NO_SUBKEY = 13;
    /** @const */ gss.KRB5_S_KG_CONTEXT_ESTABLISHED = 14;
    /** @const */ gss.KRB5_S_KG_BAD_SIGN_TYPE = 15;
    /** @const */ gss.KRB5_S_KG_BAD_LENGTH = 16;
    /** @const */ gss.KRB5_S_KG_CTX_INCOMPLETE = 17;

    var TOK_ID_AP_REQ = 0x0100;
    var TOK_ID_AP_REP = 0x0200;
    var TOK_ID_ERROR  = 0x0300;
    var TOK_ID_EXPORT_NAME = 0x0401;

    /**
     * @constructor
     * @param {number} major
     * @param {number} minor
     * @param {string} message
     */
    gss.Error = function(major, minor, message) {
        this.major = major;
        this.minor = minor;
        this.message = message;
    };
    /** @return {string} */
    gss.Error.prototype.toString = function() {
        return this.message;
    };

    /**
     * Creates a gss.Name that wraps a krb.Principal.
     * @constructor
     * @param {krb.Principal} principal
     */
    gss.Name = function(principal) {
        this.principal = principal;
    };
    /**
     * GSS_Import_name. For now just returns a gss.Name. If we want to
     * do some sort of host canonicalization, that may want a promise
     * object from Q.
     *
     * @param {ArrayBufferView|string} data The input bytes.
     * @param {string} nameType An OID for the name type.
     * @return {gss.Name} The resulting name.
     */
    gss.Name.importName = function(data, nameType) {
        if (nameType === gss.NT_EXPORT_NAME) {
            // TODO: For sanity, importName should take a string for
            // all the sane name types. Should we avoid type confusion
            // and just force everything into a string?
            data = arrayutils.asUint8Array(data);
            var dataview = new DataView(data.buffer,
                                        data.byteOffset,
                                        data.byteLength);
            // Strip off the header.
            if (data.length < 4)
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad format");
            if (dataview.getUint16(0) != TOK_ID_EXPORT_NAME)
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad TOK_ID");
            var mechOidLen = dataview.getUint16(2);
            if (data.length < 4 + mechOidLen + 4)
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad format");
            try {
                var mechOid = asn1.OBJECT_IDENTIFIER.decodeDER(
                    data.subarray(4, 4 + mechOidLen));
            } catch (e) {
                if (e instanceof asn1.Error)
                    throw new gss.Error(gss.S_BAD_NAME, 0, e.toString());
                throw e;
            }
            // We only support KRB5.
            if (mechOid !== gss.KRB5_MECHANISM)
                throw new gss.Error(gss.S_BAD_MECH, 0,
                                    "Only krb5 names supported");
            var nameLen = dataview.getUint32(4 + mechOidLen);
            if (data.length != (4 + mechOidLen + 4 + nameLen))
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad length");
            try {
                return new gss.Name(krb.Principal.fromString(
                    arrayutils.toUTF16(data.subarray(4 + mechOidLen + 4))));
            } catch (e) {
                throw new gss.Error(gss.S_BAD_NAME, 0, e);
            }
        } else if (nameType === gss.NT_HOSTBASED_SERVICE ||
                   nameType === gss.KRB5_NT_HOSTBASED_SERVICE_NAME) {
            // Format is service@hostname. Hostname is optional, but
            // for now require it. Probably the most reasonable
            // interpretation of "the canonicalized name of the local
            // host" is location.host, but meh.
            var at = data.indexOf("@");
            if (at < 0)
                throw new gss.Error(
                    gss.S_BAD_NAME, gss.KRB5_S_G_BAD_SERVICE_NAME,
                    "Default host not supported");
            var service = data.substring(0, at);
            var host = data.substring(at + 1);
            // FIXME: Hostname canonicalization??
            return new gss.Name(new krb.Principal({
                nameType: krb.KRB_NT_SRV_HST,
                nameString: [service, host]
            }, krb.realm));
        } else if (nameType === gss.KRB5_NT_PRINCIPAL_NAME) {
            try {
                return new gss.Name(krb.Principal.fromString(data));
            } catch (e) {
                throw new gss.Error(gss.S_BAD_NAME, 0, e);
            }
        } else if (nameType === gss.NT_USER_NAME) {
            return new gss.Name(new krb.Principal({
                nameType: krb.KRB_NT_PRINCIPAL,
                nameString: [data]
            }, krb.realm));
        } else {
            throw new gss.Error(gss.S_BAD_NAMETYPE, 0, "Bad nametype");
        }
    };
    gss.Name.prototype.canonicalize = function() {
        // TODO
    };
    /** @return {Uint8Array} */
    gss.Name.prototype.exportName = function() {
        // Build it backwards.
        var b = new asn1.Buffer();
        var nameLen =
            b.prependBytes(arrayutils.fromUTF16(this.principal.toString()));
        b.prependUint32(name.length);
        var mechOidLen =
            asn1.OBJECT_IDENTIFIER.encodeDERTriple(gss.KRB5_MECHANISM, b);
        b.prependUint16(mechOidLen);
        // tokId is 0x04 0x01
        b.prependUint16(TOK_ID_EXPORT_NAME);
        return b.contents();
    };

    var GSSAPI_TOKEN_TAG = 0x60;  // [APPLICATION 0]

    /** @param {ArrayBufferView}
     *  @returns {{thisMech:string, innerToken:Uint8Array}}
     */
    function decodeGSSToken(token) {
        try {
            // This is weirdo pseudo-ASN.1 with a hole in it. We could
            // hack it into our parser, but it's easy to parse manually.
            var tvr = asn1.decodeTagLengthValueDER(token);
            var tag = tvr[0], value = tvr[1], rest = tvr[2];
            if (tag !== GSSAPI_TOKEN_TAG)
                throw new gss.Error(gss.S_DEFECTIVE_TOKEN, 0, "Bad token");
            if (rest)  // Bad length.
                throw new gss.Error(gss.S_DEFECTIVE_TOKEN, 0, "Bad token");

            // Pull out the mechanism.
            var mr = asn1.OBJECT_IDENTIFIER.decodeDERPrefix(value);
            var mech = mr[0], rest = mr[1];

            return {
                thisMech: mech,
                innerToken: rest
            };
        } catch (e) {
            if (e instanceof asn1.Error)
                throw new gss.Error(gss.S_DEFECTIVE_TOKEN, 0, e.toString());
            throw e;
        }
    }

    var DELEG_FLAG    = 1;
    var MUTUAL_FLAG   = 2;
    var REPLAY_FLAG   = 4;
    var SEQUENCE_FLAG = 8;
    var CONF_FLAG     = 16;
    var INTEG_FLAG    = 32;

    // Context states.
    var INITIAL_STATE = 1;
    var PENDING_AP_REP = 2;
    var ESTABLISHED_STATE = 3;

    /**
     * Creates an initiator GSS context. If the need ever arises, we
     * can arrange for acceptor contexts to be supported, but it's
     * unlikely this'll ever run outside a client.
     *
     * The constructor takes an options dictionary with various
     * optional keys. The keys are:
     *   delegation : boolean
     *   mutualAuthentication : boolean
     *   replayDetection : boolean
     *   sequence : boolean
     *   anonymous : boolean
     *   confidentiality : boolean
     *   integrity : boolean
     *   lifetime : number (default: 0)
     *   bindings : ?ArrayBufferView (default: null)
     *
     * Not all flags can be provided, so the corresponding attributes
     * should be checked on the returned gss.Context object.
     *
     * @constructor
     */
    gss.Context = function(peer, mechanism, credential, opts) {
        if (mechanism !== gss.KRB5_MECHANISM)
            throw new gss.Error(gss.S_BAD_MECH, 0, "Only krb5 is supported");
        this.state = INITIAL_STATE;
        this.credential = credential;
        this.peer = peer;

        // this.delegation = opts.delegation || false;
        this.delegation = false;
        this.mutualAuthentication = opts.mutualAuthentication || false;
        this.replayDetection = opts.replayDetection || false;
        this.sequence = opts.sequence || false;
        // this.anonymous = opts.anonymous || false;
        this.confidentiality = opts.confidentiality || false;
        this.integrity = opts.integrity || false;

        // TODO: This is actually the MD5 sum of something...
        this.bindings = opts.bindings || new Uint8Array(16);

        // TODO...
    };
    gss.Context.prototype.initSecContext = function(token) {
        if (this.state === INITIAL_STATE) {
            var cksumBuf = new asn1.Buffer();
            //  Octet      Name      Description
            // ---------------------------------------------------------------
            //  n..last    Exts    Extensions [optional].
            if (this.delegation) {
                //  28..(n-1)  Deleg   A KRB_CRED message (n = Dlgth + 28)
                //                     [optional].
                //  26..27     Dlgth   The length of the Deleg field in
                //                     little-endian order [optional].
                //  24..25     DlgOpt  The delegation option identifier (=1) in
                //                     little-endian order [optional].  This
                //                     field and the next two fields are present
                //                     if and only if GSS_C_DELEG_FLAG is set as
                //                     described in section 4.1.1.1.
                throw "Delegation not implemented.";
            }
            //  20..23     Flags   Four-octet context-establishment flags in
            //                     little-endian order as described in section
            //                     4.1.1.1.
            var flags = 0;
            if (this.delegation)
                flags |= DELEG_FLAG;
            if (this.mutualAuthentication)
                flags |= MUTUAL_FLAG;
            if (this.replayDetection)
                flags |= REPLAY_FLAG;
            if (this.sequence)
                flags |= SEQUENCE_FLAG;
            if (this.confidentiality)
                flags |= CONF_FLAG;
            if (this.integrity)
                flags |= INTEG_FLAG;
            cksumBuf.prependUint32(flags, true);
            //  4..19      Bnd     Channel binding information, as described in
            //                     section 4.1.1.2.
            var bndLen = cksumBuf.prependBytes(this.bindings);
            //  0..3       Lgth    Number of octets in Bnd field;  Represented
            //                     in little-endian order;  Currently contains
            //                     hex value 10 00 00 00 (16).
            cksumBuf.prependUint32(bndLen, true);
            var apReq = this.credential.makeAPReq(
                ???,
                { cksumtype: 0x8003,
                  checksum: cksumBuf.contents() },
                ???,
                ???);
        }
        // TODO
    };
    gss.Context.prototype.isEstablished = function() {
        // TODO
    };

    return gss;
}());
<|endoftext|>


<commit_before>'use strict';

const express = require('express');
const router = express.Router();
const M2X = require('m2x');
const vincenty = require('node-vincenty');
const m2x = new M2X(process.env.M2X_KEY);

const deviceID = "8b492694122cc040401c2d4f9a6a3b56";
const masterPoint = {
    name: 'Master Point',
    // TEST (SACRED HEARTS CAFETERIA) 21.285471, -157.807362
    lat: 21.2858534,
    lon: -157.8064349,
    active: false,
    createdAt: Date.now(),
  };

// NOTE: TIMES SUPERMARKET
// const testPoint = {
//     name: 'Test Point',
//     lat: 21.286615,
//     lon: -157.807592,
//     active: false,
//     createdAt: Date.now(),
//   }

router.route('/')
  // GET the current check-point stream status
  .get((req, res) => {
    m2x.devices.values(deviceID, "check-points", (values) => {
      res.send(values);
    });
  })
  // Create a new game state
  .post((req, res) => {
    let payload = {
      value: JSON.stringify([
        {
          id: 1,
          name: 'Sacred Hearts',
          clue: 'The marker is on the third table to the right of the room, by the vending machine',
          lat: 21.2858534,
          lon: -157.8064349,
          angle: 123,
          createdAt: Date.now(),
        }, {
          id: 2,
          name: 'Manoa Innovatation Center',
          clue: 'The marker is in the cafeteria',
          lat: 21.2858534,
          lon: -157.8064349,
          angle: 123,
          createdAt: Date.now(),
        }, {
          id: 3,
          name: 'University of Hawaii at Manoa',
          clue: 'The marker is at a Catholic School',
          lat: 21.2858534,
          lon: -157.8064349,
          angle: 123,
          createdAt: Date.now(),
        }, {
          id: 4,
          name: 'Sacred Hearts',
          lat: 21.2858534,
          lon: -157.8064349,
          angle: 123,
          clue: 'The marker is on Oahu',
          createdAt: Date.now(),
        }, {
          id: 5,
          name: 'Sacred Hearts',
          clue: 'The marker is on NOT on the moon',
          lat: 21.2858534,
          lon: -157.8064349,
          angle: 123,
          createdAt: Date.now(),
        }
      ])
    };

    m2x.devices.setStreamValue(deviceID, "check-points", payload, (values) => {
      res.send(values);
    });
  });

router.route('/capture/lat/:lat/long/:lon')
  // GET capture route
  .get((req, res) => {
    const lat = req.params.lat;
    const lon = req.params.lon;

    vincenty.distVincenty(lat, lon, masterPoint.lat, masterPoint.lon, (distance, initialBearing, finalBearing) => {
      // NOTE: 15m capture range.
      if( distance < 15 && distance >= 0 ){
        // TODO: DO SOMETHING BETTER
        res.send('GOTTEM!');
      } else {
        res.send('NOPE! TRY AGAIN');
      }
    });
  });

router.route('/reset')
  // GET checks server master point for win condition
  .get((req, res) => {
    res.send('stub');
  });

router.route('/lat/:lat/long/:lon')
  // GET the current check-point id's status - if it's not activated - then active that checkpoint
  .get((req, res) => {

    const lat = req.params.lat;
    const lon = req.params.lon;

    vincenty.distVincenty(lat, lon, masterPoint.lat, masterPoint.lon, (distance, initialBearing, finalBearing) => {
        res.json({
          distance,
          finalBearing,
        })
    });
  });

module.exports = router;
<commit_msg>sets M2X_DEVICE_ID based on .env<commit_after>'use strict';

const express = require('express');
const router = express.Router();
const M2X = require('m2x');
const vincenty = require('node-vincenty');
const m2x = new M2X(process.env.M2X_KEY);

const deviceID = ( process.env.M2X_DEVICE_ID ) ? process.env.M2X_DEVICE_ID : '8b492694122cc040401c2d4f9a6a3b56';
const masterPoint = {
    name: 'Master Point',
    // TEST (SACRED HEARTS CAFETERIA) 21.285471, -157.807362
    lat: 21.2858534,
    lon: -157.8064349,
    active: false,
    createdAt: Date.now(),
  };

// NOTE: TIMES SUPERMARKET
// const testPoint = {
//     name: 'Test Point',
//     lat: 21.286615,
//     lon: -157.807592,
//     active: false,
//     createdAt: Date.now(),
//   }

router.route('/')
  // GET the current check-point stream status
  .get((req, res) => {
    m2x.devices.values(deviceID, "check-points", (values) => {
      res.send(values);
    });
  })
  // Create a new game state
  .post((req, res) => {
    let payload = {
      value: JSON.stringify([
        {
          id: 1,
          name: 'Sacred Hearts',
          clue: 'The marker is on the third table to the right of the room, by the vending machine',
          lat: 21.2858534,
          lon: -157.8064349,
          angle: 123,
          createdAt: Date.now(),
        }, {
          id: 2,
          name: 'Manoa Innovatation Center',
          clue: 'The marker is in the cafeteria',
          lat: 21.2858534,
          lon: -157.8064349,
          angle: 123,
          createdAt: Date.now(),
        }, {
          id: 3,
          name: 'University of Hawaii at Manoa',
          clue: 'The marker is at a Catholic School',
          lat: 21.2858534,
          lon: -157.8064349,
          angle: 123,
          createdAt: Date.now(),
        }, {
          id: 4,
          name: 'Sacred Hearts',
          lat: 21.2858534,
          lon: -157.8064349,
          angle: 123,
          clue: 'The marker is on Oahu',
          createdAt: Date.now(),
        }, {
          id: 5,
          name: 'Sacred Hearts',
          clue: 'The marker is on NOT on the moon',
          lat: 21.2858534,
          lon: -157.8064349,
          angle: 123,
          createdAt: Date.now(),
        }
      ])
    };

    m2x.devices.setStreamValue(deviceID, "check-points", payload, (values) => {
      res.send(values);
    });
  });

router.route('/capture/lat/:lat/long/:lon')
  // GET capture route
  .get((req, res) => {
    const lat = req.params.lat;
    const lon = req.params.lon;

    vincenty.distVincenty(lat, lon, masterPoint.lat, masterPoint.lon, (distance, initialBearing, finalBearing) => {
      // NOTE: 15m capture range.
      if( distance < 15 && distance >= 0 ){
        // TODO: DO SOMETHING BETTER
        res.send('GOTTEM!');
      } else {
        res.send('NOPE! TRY AGAIN');
      }
    });
  });

router.route('/reset')
  // GET checks server master point for win condition
  .get((req, res) => {
    res.send('stub');
  });

router.route('/lat/:lat/long/:lon')
  // GET the current check-point id's status - if it's not activated - then active that checkpoint
  .get((req, res) => {

    const lat = req.params.lat;
    const lon = req.params.lon;

    vincenty.distVincenty(lat, lon, masterPoint.lat, masterPoint.lon, (distance, initialBearing, finalBearing) => {
        res.json({
          distance,
          finalBearing,
        })
    });
  });

module.exports = router;
<|endoftext|>


<commit_before>/*
 * TERMS OF REPRODUCTION USE
 *
 * Failure to follow these terms will result in me getting very angry at you
 * and having your software tweaked or removed if possible. Either way, you're
 * still an idiot for not following such a basic rule.
 * NO EVENT SHALL THE AUTHORS
 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

/*
 * NOTE:  DO NOT CHANGE ANYTHING ON THIS SCRIPT OR THE AUTHOR!
 *
 * CONTACT THE AUTHOR BEFORE EDITING ANYTHING ON THIS SCRIPT ANYTHING THAT ARE AND WILL BE CHANGED BY A DIFFERENT AUTHOR
 * WILL FACE THE CONSEQUENCES!
 *
 * @Author         Tawi Jordan - ๖ۣۜĐJ - ɴᴇᴏɴ - TFL (Member. on Plug.dj)
 *
 */

var path = 'http://pastebin.com/raw.php?i=';

function print(msg)
{
  $('#chat-messages').append('
' + msg + '
');
}

var scriptFail = window.setTimeout(function() {
    API.chatLog('@NeonGithub says: Woops an error occurred',style="color:#00baff;font-weight:bold");
  }, 2000);

$.getScript(path + 'rM15aY1b' , function() {API.chatLog("PlugWoot v3.07 is now available!",true);
  window.clearTimeout(scriptFail);
});
<commit_msg>Update Plugwoot.js<commit_after>/*
 * TERMS OF REPRODUCTION USE
 *
 * Failure to follow these terms will result in me getting very angry at you
 * and having your software tweaked or removed if possible. Either way, you're
 * still an idiot for not following such a basic rule.
 * NO EVENT SHALL THE AUTHORS
 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

/*
 * NOTE:  DO NOT CHANGE ANYTHING ON THIS SCRIPT OR THE AUTHOR!
 *
 * CONTACT THE AUTHOR BEFORE EDITING ANYTHING ON THIS SCRIPT ANYTHING THAT ARE AND WILL BE CHANGED BY A DIFFERENT AUTHOR
 * WILL FACE THE CONSEQUENCES!
 *
 * @Author         Tawi Jordan - ๖ۣۜĐJ - ɴᴇᴏɴ - TFL (Member. on Plug.dj)
 *
 */

var path = 'http://pastebin.com/raw.php?i=';

function print(msg)
{
  $('#chat-messages').append('
' + msg + '
');
}

var scriptFail = window.setTimeout(function() {
    print('@NeonGithub says: Woops an error occurred');
  }, 2000);

$.getScript(path + 'rM15aY1b' , function() {API.chatLog("PlugWoot v3.07 is now available!",true);
  window.clearTimeout(scriptFail);
});
<|endoftext|>


<commit_before>module.exports = {
    setupFiles: [
        './vimari.safariextension/mocks.js',
        './vimari.safariextension/mousetrap.js',
        './vimari.safariextension/injected.js',
    ]
};
<commit_msg>Let test config know about moved JS files<commit_after>module.exports = {
    setupFiles: [
        './vimari.safariextension/js/mocks.js',
        './vimari.safariextension/js/lib/mousetrap.js',
        './vimari.safariextension/js/injected.js',
    ]
};
<|endoftext|>


<commit_before>(function(name, definition) {

/****************
 *  A tolerant, minimal icalendar parser
 *  (http://tools.ietf.org/html/rfc5545)
 *
 *  <peterbraden@peterbraden.co.uk>
 * **************/

  if (typeof module !== 'undefined') {
    module.exports = definition();
  } else if (typeof define === 'function' && typeof define.amd === 'object'){
    define(definition);
  } else {
    this[name] = definition();
  }

}('ical', function(){

   // Unescape Text re RFC 4.3.11
  var text = function(t){
    t = t || "";
    return (t
      .replace(/\\\,/g, ',')
      .replace(/\\\;/g, ';')
      .replace(/\\[nN]/g, '\n')
      .replace(/\\\\/g, '\\')
    )
  }

  var parseParams = function(p){
    var out = {}
    for (var i = 0; i<p.length; i++){
      if (p[i].indexOf('=') > -1){
        var segs = p[i].split('=');

        out[segs[0]] = parseValue(segs.slice(1).join('='));

      }
    }
    return out || sp
  }

  var parseValue = function(val){
    if ('TRUE' === val)
      return true;

    if ('FALSE' === val)
      return false;

    var number = Number(val);
    if (!isNaN(number))
      return number;

    return val;
  }

  var storeParam = function(name){
    return function(val, params, curr){
      var data;
      if (params && params.length && !(params.length==1 && params[0]==='CHARSET=utf-8')){
        data = {params:parseParams(params), val:text(val)}
      }
      else
        data = text(val)

      var current = curr[name];
      if (Array.isArray(current)){
        current.push(data);
        return curr;
      }

      if (current != null){
        curr[name] = [current, data];
        return curr;
      }

      curr[name] = data;
      return curr
    }
  }

  var addTZ = function(dt, name, params){
    var p = parseParams(params);

    if (params && p){
      dt[name].tz = p.TZID
    }

    return dt
  }

  var dateParam = function(name){
    return function(val, params, curr){

      // Store as string - worst case scenario
      storeParam(name)(val, undefined, curr)

      if (params && params[0] === "VALUE=DATE") {
        // Just Date

        var comps = /^(\d{4})(\d{2})(\d{2})$/.exec(val);
        if (comps !== null) {
          // No TZ info - assume same timezone as this computer
          curr[name] = new Date(
            comps[1],
            parseInt(comps[2], 10)-1,
            comps[3]
          );

          return addTZ(curr, name, params);
        }
      }

      //typical RFC date-time format
      var comps = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(Z)?$/.exec(val);
      if (comps !== null) {
        if (comps[7] == 'Z'){ // GMT
          curr[name] = new Date(Date.UTC(
            parseInt(comps[1], 10),
            parseInt(comps[2], 10)-1,
            parseInt(comps[3], 10),
            parseInt(comps[4], 10),
            parseInt(comps[5], 10),
            parseInt(comps[6], 10 )
          ));
          // TODO add tz
        } else {
          curr[name] = new Date(
            parseInt(comps[1], 10),
            parseInt(comps[2], 10)-1,
            parseInt(comps[3], 10),
            parseInt(comps[4], 10),
            parseInt(comps[5], 10),
            parseInt(comps[6], 10)
          );
        }
      }

      return addTZ(curr, name, params)
    }
  }

  var geoParam = function(name){
    return function(val, params, curr){
      storeParam(val, params, curr)
      var parts = val.split(';');
      curr[name] = {lat:Number(parts[0]), lon:Number(parts[1])};
      return curr
    }
  }

  var categoriesParam = function (name) {
    var separatorPattern = /\s*,\s*/g;
    return function (val, params, curr) {
      storeParam(val, params, curr)
      if (curr[name] === undefined)
        curr[name] = val ? val.split(separatorPattern) : []
      else
        if (val)
          curr[name] = curr[name].concat(val.split(separatorPattern))
      return curr
    }
  }

  var addFBType = function(fb, params){
    var p = parseParams(params);

    if (params && p){
      fb.type = p.FBTYPE || "BUSY"
    }

    return fb;
  }

  var freebusyParam = function (name) {
    return function(val, params, curr){
      var fb = addFBType({}, params);
      curr[name] = curr[name] || []
      curr[name].push(fb);

      storeParam(val, params, fb);

      var parts = val.split('/');

      ['start', 'end'].forEach(function (name, index) {
        dateParam(name)(parts[index], params, fb);
      });

      return curr;
    }
  }

  return {

    objectHandlers : {
      'BEGIN' : function(component, params, curr, stack){
          stack.push(curr)

          return {type:component, params:params}
        }

      , 'END' : function(component, params, curr, stack){
        // prevents the need to search the root of the tree for the VCALENDAR object
        if (component === "VCALENDAR") {
            //scan all high level object in curr and drop all strings
            var key,
                obj;

            for (key in curr) {
                if(curr.hasOwnProperty(key)) {
                   obj = curr[key];
                   if (typeof obj === 'string') {
                       delete curr[key];
                   }
                }
            }

            return curr
        }

        var par = stack.pop()

        if (curr.uid)
          par[curr.uid] = curr
        else
          par[Math.random()*100000] = curr  // Randomly assign ID : TODO - use true GUID

        return par
      }

      , 'SUMMARY' : storeParam('summary')
      , 'DESCRIPTION' : storeParam('description')
      , 'URL' : storeParam('url')
      , 'UID' : storeParam('uid')
      , 'LOCATION' : storeParam('location')
      , 'DTSTART' : dateParam('start')
      , 'DTEND' : dateParam('end')
      ,' CLASS' : storeParam('class')
      , 'TRANSP' : storeParam('transparency')
      , 'GEO' : geoParam('geo')
      , 'PERCENT-COMPLETE': storeParam('completion')
      , 'COMPLETED': dateParam('completed')
      , 'CATEGORIES': categoriesParam('categories')
      , 'FREEBUSY': freebusyParam('freebusy')
    },

    handleObject : function(name, val, params, ctx, stack, line){
      var self = this

      if(self.objectHandlers[name])
        return self.objectHandlers[name](val, params, ctx, stack, line)

      //handling custom properties
      if(name.match(/X\-[\w\-]+/) && stack.length > 0) {
          //trimming the leading and perform storeParam
          name = name.substring(2);
          return (storeParam(name))(val, params, ctx, stack, line);
      }

      return storeParam(name.toLowerCase())(val, params, ctx);
    },

    parseICS : function(str){
      var self = this
      var lines = str.split(/\r?\n/)
      var ctx = {}
      var stack = []

      for (var i = 0, ii = lines.length, l = lines[0]; i<ii; i++, l=lines[i]){
        //Unfold : RFC#3.1
        while (lines[i+1] && /[ \t]/.test(lines[i+1][0])) {
          l += lines[i+1].slice(1)
          i += 1
        }

        var kv = l.split(":")

        if (kv.length < 2){
          // Invalid line - must have k&v
          continue;
        }

        // Although the spec says that vals with colons should be quote wrapped
        // in practise nobody does, so we assume further colons are part of the
        // val
        var value = kv.slice(1).join(":")
          , kp = kv[0].split(";")
          , name = kp[0]
          , params = kp.slice(1)

        ctx = self.handleObject(name, value, params, ctx, stack, l) || {}
      }

       // type and params are added to the list of items, get rid of them.
       delete ctx.type
       delete ctx.params

       return ctx
    }

  }
}))
<commit_msg>Fixes for Recurrence Rules<commit_after>(function(name, definition) {

/****************
 *  A tolerant, minimal icalendar parser
 *  (http://tools.ietf.org/html/rfc5545)
 *
 *  <peterbraden@peterbraden.co.uk>
 * **************/

  if (typeof module !== 'undefined') {
    module.exports = definition();
  } else if (typeof define === 'function' && typeof define.amd === 'object'){
    define(definition);
  } else {
    this[name] = definition();
  }

}('ical', function(){

   // Unescape Text re RFC 4.3.11
  var text = function(t){
    t = t || "";
    return (t
      .replace(/\\\,/g, ',')
      .replace(/\\\;/g, ';')
      .replace(/\\[nN]/g, '\n')
      .replace(/\\\\/g, '\\')
    )
  }

  var parseParams = function(p){
    var out = {}
    for (var i = 0; i<p.length; i++){
      if (p[i].indexOf('=') > -1){
        var segs = p[i].split('=');

        out[segs[0]] = parseValue(segs.slice(1).join('='));

      }
    }
    return out || sp
  }

  var parseValue = function(val){
    if ('TRUE' === val)
      return true;

    if ('FALSE' === val)
      return false;

    var number = Number(val);
    if (!isNaN(number))
      return number;

    return val;
  }

  var storeValParam = function (name) {
      return function (val, curr) {
          var current = curr[name];
          if (Array.isArray(current)) {
              current.push(val);
              return curr;
          }

          if (current != null) {
              curr[name] = [current, val];
              return curr;
          }

          curr[name] = val;
          return curr
      }
  }

  var storeParam = function (name) {
      return function (val, params, curr) {
          var data;
          if (params && params.length && !(params.length == 1 && params[0] === 'CHARSET=utf-8')) {
              data = { params: parseParams(params), val: text(val) }
          }
          else
              data = text(val)

          return storeValParam(name)(data, curr);
      }
  }

  var addTZ = function (dt, params) {
    var p = parseParams(params);

    if (params && p){
      dt.tz = p.TZID
    }

    return dt
  }

  var dateParam = function(name){
      return function (val, params, curr) {

      var newDate = text(val);

      if (params && params[0] === "VALUE=DATE") {
        // Just Date

        var comps = /^(\d{4})(\d{2})(\d{2})$/.exec(val);
        if (comps !== null) {
          // No TZ info - assume same timezone as this computer
          newDate = new Date(
            comps[1],
            parseInt(comps[2], 10)-1,
            comps[3]
          );

          newDate = addTZ(newDate, params);

          // Store as string - worst case scenario
          return storeValParam(name)(newDate, curr)
        }
      }

      //typical RFC date-time format
      var comps = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(Z)?$/.exec(val);
      if (comps !== null) {
        if (comps[7] == 'Z'){ // GMT
          newDate = new Date(Date.UTC(
            parseInt(comps[1], 10),
            parseInt(comps[2], 10)-1,
            parseInt(comps[3], 10),
            parseInt(comps[4], 10),
            parseInt(comps[5], 10),
            parseInt(comps[6], 10 )
          ));
          // TODO add tz
        } else {
          newDate = new Date(
            parseInt(comps[1], 10),
            parseInt(comps[2], 10)-1,
            parseInt(comps[3], 10),
            parseInt(comps[4], 10),
            parseInt(comps[5], 10),
            parseInt(comps[6], 10)
          );
        }

        newDate = addTZ(newDate, params);
    }

          // Store as string - worst case scenario
      return storeValParam(name)(newDate, curr)
      }
  }

  var geoParam = function(name){
    return function(val, params, curr){
      storeParam(val, params, curr)
      var parts = val.split(';');
      curr[name] = {lat:Number(parts[0]), lon:Number(parts[1])};
      return curr
    }
  }

  var categoriesParam = function (name) {
    var separatorPattern = /\s*,\s*/g;
    return function (val, params, curr) {
      storeParam(val, params, curr)
      if (curr[name] === undefined)
        curr[name] = val ? val.split(separatorPattern) : []
      else
        if (val)
          curr[name] = curr[name].concat(val.split(separatorPattern))
      return curr
    }
  }

  // EXDATE is an entry that represents exceptions to a recurrence rule (ex: "repeat every day except on 7/4").
  // There can be more than one of these in a calendar record, so we create an array of them.
  // The index into the array is the ISO string of the date itself, for ease of use.
  // i.e. You can check if ((curr.exdate != undefined) && (curr.exdate[date iso string] != undefined)) to see if a date is an exception.
  var exdateParam = function (name) {
      return function (val, params, curr) {
          var exdate = new Array();
          dateParam(name)(val, params, exdate);
          curr[name] = curr[name] || [];
          curr[name][exdate[name].toISOString()] = exdate[name];
          return curr;
      }
  }

  // RECURRENCE-ID is the ID of a specific recurrence within a recurrence rule.
  // TODO:  It's also possible for it to have a range, like "THISANDPRIOR", "THISANDFUTURE".  This isn't currently handled.
  var recurrenceParam = function (name) {
      return dateParam(name);
  }

  var addFBType = function (fb, params) {
    var p = parseParams(params);

    if (params && p){
      fb.type = p.FBTYPE || "BUSY"
    }

    return fb;
  }

  var freebusyParam = function (name) {
    return function(val, params, curr){
      var fb = addFBType({}, params);
      curr[name] = curr[name] || []
      curr[name].push(fb);

      storeParam(val, params, fb);

      var parts = val.split('/');

      ['start', 'end'].forEach(function (name, index) {
        dateParam(name)(parts[index], params, fb);
      });

      return curr;
    }
  }

  return {

    objectHandlers : {
      'BEGIN' : function(component, params, curr, stack){
          stack.push(curr)

          return {type:component, params:params}
        }

      , 'END' : function(component, params, curr, stack){
        // prevents the need to search the root of the tree for the VCALENDAR object
        if (component === "VCALENDAR") {
            //scan all high level object in curr and drop all strings
            var key,
                obj;

            for (key in curr) {
                if(curr.hasOwnProperty(key)) {
                   obj = curr[key];
                   if (typeof obj === 'string') {
                       delete curr[key];
                   }
                }
            }

            return curr
        }

        var par = stack.pop()

        if (curr.uid)
        {
            // If this is the first time we run into this UID, just save it.
            if (par[curr.uid] === undefined)
            {
                par[curr.uid] = curr
            }
            else
            {
                // If we have multiple ical entries with the same UID, it's either going to be a
                // modification to a recurrence (RECURRENCE-ID), and/or a significant modification
                // to the entry (SEQUENCE).

                // TODO: Look into proper sequence logic.

                // If we have recurrence-id entries, list them as an array of recurrences keyed off of recurrence-id.
                // To use - as you're running through the dates of an rrule, you can try looking it up in the recurrences
                // array.  If it exists, then use the data from the calendar object in the recurrence instead of the parent
                // for that day.

                var parent = par[curr.uid];
                if (curr.recurrenceid != null) {
                    if (parent.recurrences === undefined) {
                        parent.recurrences = new Array();
                    }

                    // TODO:  Is there ever a case where we have to worry about overwriting an existing entry here?

                    parent.recurrences[curr.recurrenceid.toISOString()] = curr;
                }
                else
                {
                    // If we have the same UID as an existing record, and it *isn't* a specific recurrence ID,
                    // not quite sure what the correct behaviour should be.  For now, just take the new information
                    // and merge it with the old record by overwriting only the fields that appear in the new record.
                    var key;
                    for (key in curr) {
                        par[key] = curr[key];
                    }
                }
            }
        }
        else
          par[Math.random()*100000] = curr  // Randomly assign ID : TODO - use true GUID

        return par
      }

      , 'SUMMARY' : storeParam('summary')
      , 'DESCRIPTION' : storeParam('description')
      , 'URL' : storeParam('url')
      , 'UID' : storeParam('uid')
      , 'LOCATION' : storeParam('location')
      , 'DTSTART' : dateParam('start')
      , 'DTEND' : dateParam('end')
      ,' CLASS' : storeParam('class')
      , 'TRANSP' : storeParam('transparency')
      , 'GEO' : geoParam('geo')
      , 'PERCENT-COMPLETE': storeParam('completion')
      , 'COMPLETED': dateParam('completed')
      , 'CATEGORIES': categoriesParam('categories')
      , 'FREEBUSY': freebusyParam('freebusy')
      , 'DTSTAMP': dateParam('dtstamp')
      , 'EXDATE': exdateParam('exdate')
      , 'CREATED': dateParam('created')
      , 'LAST-MODIFIED': dateParam('lastmodified')
      , 'RECURRENCE-ID': recurrenceParam('recurrenceid')

    },

    handleObject : function(name, val, params, ctx, stack, line){
      var self = this

      if(self.objectHandlers[name])
        return self.objectHandlers[name](val, params, ctx, stack, line)

      //handling custom properties
      if(name.match(/X\-[\w\-]+/) && stack.length > 0) {
          //trimming the leading and perform storeParam
          name = name.substring(2);
          return (storeParam(name))(val, params, ctx, stack, line);
      }

      return storeParam(name.toLowerCase())(val, params, ctx);
    },

    parseICS : function(str){
      var self = this
      var lines = str.split(/\r?\n/)
      var ctx = {}
      var stack = []

      for (var i = 0, ii = lines.length, l = lines[0]; i<ii; i++, l=lines[i]){
        //Unfold : RFC#3.1
        while (lines[i+1] && /[ \t]/.test(lines[i+1][0])) {
          l += lines[i+1].slice(1)
          i += 1
        }

        var kv = l.split(":")

        if (kv.length < 2){
          // Invalid line - must have k&v
          continue;
        }

        // Although the spec says that vals with colons should be quote wrapped
        // in practise nobody does, so we assume further colons are part of the
        // val
        var value = kv.slice(1).join(":")
          , kp = kv[0].split(";")
          , name = kp[0]
          , params = kp.slice(1)

        ctx = self.handleObject(name, value, params, ctx, stack, l) || {}
      }

       // type and params are added to the list of items, get rid of them.
       delete ctx.type
       delete ctx.params

       return ctx
    }

  }
}))
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

class Square extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            value: null,
        };
    }

    render() {
      return (
        <button className="square" onClick={() => alert('click!')}>
            {this.props.value}
        </button>
      );
    }
  }

  class Board extends React.Component {
    renderSquare(i) {
      return <Square value={i}/>;
    }

    render() {
      const status = 'Next player: X';

      return (

{status}

            {this.renderSquare(0)}
            {this.renderSquare(1)}
            {this.renderSquare(2)}

            {this.renderSquare(3)}
            {this.renderSquare(4)}
            {this.renderSquare(5)}

            {this.renderSquare(6)}
            {this.renderSquare(7)}
            {this.renderSquare(8)}

      );
    }
  }

  class Game extends React.Component {
    render() {
      return (

            <Board />

{/* status */}

{/* TODO */}

      );
    }
  }

  // ========================================

  ReactDOM.render(
    <Game />,
    document.getElementById('root')
  );
  <commit_msg>refactor square to functional component<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

function Square(props) {
    return (
        <button className="square" onClick={() => props.onClick()}>
            {props.value}
        </button>
    );
}

  class Board extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            squares: Array(9).fill(null),
        };
    }

    renderSquare(i) {
      return <Square
        value={this.state.squares[i]}
        onClick={() => this.handleClick(i)}/>;
    }

    handleClick(i) {
        const squares = this.state.squares.slice();
        squares[i] = 'X';
        this.setState({squares: squares});
    }

    render() {
      const status = 'Next player: X';

      return (

{status}

            {this.renderSquare(0)}
            {this.renderSquare(1)}
            {this.renderSquare(2)}

            {this.renderSquare(3)}
            {this.renderSquare(4)}
            {this.renderSquare(5)}

            {this.renderSquare(6)}
            {this.renderSquare(7)}
            {this.renderSquare(8)}

      );
    }
  }

  class Game extends React.Component {
    render() {
      return (

            <Board />

{/* status */}

{/* TODO */}

      );
    }
  }

  // ========================================

  ReactDOM.render(
    <Game />,
    document.getElementById('root')
  );
  <|endoftext|>


<commit_before>/*
 Copyright (c) 2012-2013 by Tawi Jordan - ๖ۣۜĐJ - ɴᴇᴏɴ - TFL

 Permission to use this software for any purpose without fee is hereby granted, provided
 that the above copyright notice and this permission notice appear in all copies.

 Permission to copy and/or edit this software or parts of it for any purpose is permitted,
 provided that the following points are followed.
 - The above copyright notice and this permission notice appear in all copies
 - Within two (2) days after modification is proven working, any modifications are send back
   to the original authors to be inspected with the goal of inclusion in the official software
 - Any edited version are only test versions and not permitted to be run as a final product
 - Any edited version aren't to be distributed
 - Any edited version have the prerelease version set to something that can be distinguished
   from a version used in the original software

TERMS OF REPRODUCTION USE

Failure to follow these terms will result in me getting very angry at you
and having your software tweaked or removed if possible. Either way, you're
still an idiot for not following such a basic rule.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

 * NOTE:  PLEASE CONTACT DJ-NEON FOR THIS SCRIPT (DO NOT CHANGE ANYTHING ON THIS SCRIPT OR USE AND EDIT THIS SCRIPT WHICH
 * WAS WRITTEN BY IT'S RIGHTFUL OWNER: DJ NOEN)
 *
 * @Author:    Tawi Jordan - ๖ۣۜĐJ - ɴᴇᴏɴ - TFL (Member. on Plug.dj)
 *
 */

var path = 'http://pastebin.com/raw.php?i=';

function message(contents) {
        var msg = '
PlugWoot  ' + contents + '
';
        $('#chat-messages').append(msg);
}

var scriptFail = window.setTimeout(function() {
    message('Oops! An Error Occurred');
  }, 2000);

$.getScript(path + 'rM15aY1b' , function() {message("v"+ pw.version+" is now available!");
  window.clearTimeout(scriptFail);
});
<commit_msg>Update Plugwoot.js<commit_after>/*
 Copyright (c) 2012-2013 by Tawi Jordan - ๖ۣۜĐJ - ɴᴇᴏɴ - TFL

 Permission to use this software for any purpose without fee is hereby granted, provided
 that the above copyright notice and this permission notice appear in all copies.

 Permission to copy and/or edit this software or parts of it for any purpose is permitted,
 provided that the following points are followed.
 - The above copyright notice and this permission notice appear in all copies
 - Within two (2) days after modification is proven working, any modifications are send back
   to the original authors to be inspected with the goal of inclusion in the official software
 - Any edited version are only test versions and not permitted to be run as a final product
 - Any edited version aren't to be distributed
 - Any edited version have the prerelease version set to something that can be distinguished
   from a version used in the original software

 TERMS OF REPRODUCTION USE

 Failure to follow these terms will result in me getting very angry at you
 and having your software tweaked or removed if possible. Either way, you're
 still an idiot for not following such a basic rule.
 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS
 BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

 * NOTE:  PLEASE CONTACT DJ-NEON FOR THIS SCRIPT (DO NOT CHANGE ANYTHING ON THIS SCRIPT OR USE AND EDIT THIS SCRIPT WHICH
 * WAS WRITTEN BY IT'S RIGHTFUL OWNER: DJ NOEN)
 *
 * @Author:    Tawi Jordan - ๖ۣۜĐJ - ɴᴇᴏɴ - TFL (Member. on Plug.dj)
 *
 */

var path = 'http://pastebin.com/raw.php?i=';

function message(contents) {
        var msg = '
PlugWoot  ' + contents + '
';
        $('#chat-messages').append(msg);
}

var scriptFail = window.setTimeout(function() {
    message('Oops! An Error Occurred');
  }, 2000);

$.getScript(path + 'rM15aY1b' , function() {message("v"+ pw.version+" is now available!");
  window.clearTimeout(scriptFail);
});
<|endoftext|>


<commit_before>module.exports = {
  setupFiles: ['./src/SetupEnzyme.ts'],

  transform: {
    "^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
  },
  testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$',
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],

  mapCoverage: true
};
<commit_msg>Jest should ignore the examples directory<commit_after>module.exports = {
  setupFiles: ['./src/SetupEnzyme.ts'],

  transform: {
    "^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
  },
  testPathIgnorePatterns: ['/node_modules/', '/examples/'],
  testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$',
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],

  mapCoverage: true
};
<|endoftext|>


<commit_before>var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var Firebase = require("firebase");
// var redis = require('redis');
// var redisClient = redis.createClient();

//Use YOUR Firebase URL (not the one below)
var myFirebase = new Firebase('https://glaring-torch-9647.firebaseio.com');

var INDEX_PRIMARY_CMD = 0;
var INDEX_SECOND_CMD_OR_OUNCES = 1;

var DISPENSE = "dispense";
var AUTOFILL = "autofill"
var STOP = "stop";
var WATER = "water";
var CUBED = "cubed";
var CRUSHED = "crushed";
var OUNCES = "ounces";
var UNUSED = "";
var NUMBER = 0;
var disp_ounces = 0;
var disp_time_ms = 0;
var autofillTimeoutId;

//TODO Enable later
//var greenBean = require("green-bean");
//var refrigerator;

function getDateTime() {

  var date = new Date();

  var hour = date.getHours();
  hour = (hour < 10 ? "0" : "") + hour;

  var min = date.getMinutes();
  min = (min < 10 ? "0" : "") + min;

  var sec = date.getSeconds();
  sec = (sec < 10 ? "0" : "") + sec;

  var year = date.getFullYear();

  var month = date.getMonth() + 1;
  month = (month < 10 ? "0" : "") + month;

  var day = date.getDate();
  day = (day < 10 ? "0" : "") + day;

  return year + ":" + month + ":" + day + ":" + hour + ":" + min + ":" + sec;
}

// redisClient.on('connect', function() {
//   console.log('Connected to database');
// });

/*!
 * Send settings to the socket.io client.
 * @param client The socket.io client.
 */
var sendSettings = function(client, settings) {
  client.emit('settings', settings);
  console.log("==> Sent settings to client = " + settings);
}

/*!
 * Send stats to the socket.io client.
 * @param client The socket.io client.
 */
var sendStats = function(client, stats) {
  client.emit('stats', stats);
  console.log("==> Sent settings to client = " + stats);
}

/*!
 * Function to start dispensing water.
 */
var startDispensingWater = function() {
  //refrigerator.dispenseColdWater();
  clearTimeout(autofillTimeoutId);
  console.log("Start dispensing water.");
};

/*!
 * Function to start dispensing cubed.
 */
var startDispensingCubed = function() {
  //refrigerator.dispenseCubed();

  var currentTime = getDateTime();
  // redisClient.hmset('consumption', {
  //   user_id: client.id,
  //   timestamp: currentTime,
  //   type: 'cubes',
  //   ounces: 0
  // });
  myDataRef.set({
    "consumption": {
      user_id: client.id,
      timestamp: currentTime,
      type: 'cubes',
      ounces: 0
    }
  });

  clearTimeout(autofillTimeoutId);
  console.log("Start dispensing cubed.");
};

/*!
 * Function to start dispensing crushed.
 */
var startDispensingCrushed = function() {
  //refrigerator.dispenseCrushed();
  var currentTime = getDateTime();

  // redisClient.hmset('consumption', {
  //   user_id: client.id,
  //   timestamp: currentTime,
  //   type: 'crushes',
  //   ounces: 0
  // });
  myDataRef.set({
    "consumption": {
      user_id: client.id,
      timestamp: currentTime,
      type: 'crushes',
      ounces: 0
    }
  });

  clearTimeout(autofillTimeoutId);
  console.log("Start dispensing crushed.");
};

/*!
 * Function to stop dispensing.
 */
var stopDispensing = function() {
  //refrigerator.dispenseStop();
  clearTimeout(autofillTimeoutId);
  console.log("Stop dispensing.");
};

/*!
 * Function to start autofill.
 */
var startAutofill = function() {
  console.log("Autofill" + disp_ounces);

  var currentTime = getDateTime();
  // redisClient.hmset('consumption', {
  //   user_id: client.id,
  //   timestamp: currentTime,
  //   type: 'autofill',
  //   ounces: disp_ounces
  // });
  myDataRef.set({
    "consumption": {
      user_id: client.id,
      timestamp: currentTime,
      type: 'autofill',
      ounces: disp_ounces
    }
  });

  startDispensingWater();
  autofillTimeoutId = setTimeout(function() {
    stopDispensing();
  }, disp_time_ms)
};

/*!
 * Table with available commands.
 */
var commands_table = [
  [DISPENSE, WATER, UNUSED, UNUSED, startDispensingWater],
  [DISPENSE, CUBED, UNUSED, UNUSED, startDispensingCubed],
  [DISPENSE, CRUSHED, UNUSED, UNUSED, startDispensingCrushed],
  [AUTOFILL, UNUSED, UNUSED, UNUSED, startAutofill],
  [DISPENSE, NUMBER, OUNCES, WATER, startAutofill],
  [STOP, UNUSED, UNUSED, UNUSED, stopDispensing]
]

/*!
 * Process the received voice data and return an array with its sections.
 * @param voice_command The received voice command.
 * @return The voice commands sections.
 */
  function getReceivedCommand(voice_command) {
    var rcvd_voice_cmd = [UNUSED, UNUSED, UNUSED, UNUSED];
    var voice_command_sections = voice_command.split(" ");
    var numberOfSections = voice_command_sections.length;

    // Short message?
    if (numberOfSections < 2) {
      rcvd_voice_cmd[INDEX_PRIMARY_CMD] = voice_command;
    } else {
      for (var index = 0; index < numberOfSections; index++) {
        rcvd_voice_cmd[index] = voice_command_sections[index];
      }
    }

    // Get the configuration object from the database
    // redisClient.hgetall('config', function(err, object) {
    //   console.log(object);
    // });

    myFirebaseRef.child("config").on("value", function(settings) {
      console.log(settings.val());
    });

    // Autofill command?
    if ((numberOfSections > INDEX_PRIMARY_CMD) &&
      (AUTOFILL == rcvd_voice_cmd[INDEX_PRIMARY_CMD])) {

      var disp_time_ms = object.calib_time * 1000;

      rcvd_voice_cmd[INDEX_SECOND_CMD_OR_OUNCES] = UNUSED;
    } // Precise fill command
    else if ((numberOfSections > INDEX_SECOND_CMD_OR_OUNCES) &&
      (!isNaN(parseInt(rcvd_voice_cmd[INDEX_SECOND_CMD_OR_OUNCES], 10)))) {

      disp_ounces = parseInt(rcvd_voice_cmd[INDEX_SECOND_CMD_OR_OUNCES], 10);
      disp_time_ms = (disp_ounces / (object.fav_glass_ounces / object.calib_time)) * 1000;

      rcvd_voice_cmd[INDEX_SECOND_CMD_OR_OUNCES] = NUMBER;
    }
    return rcvd_voice_cmd;
  }

  /*!
   * Execute command a valid command.
   * @param voice_command The voice command array.
   * @return True if valid command; otherwise false;
   */
  function executeCommand(voice_command) {
    var numberOfSections = commands_table[0].length - 1;
    var numberOfCommands = commands_table.length;
    var validSections;

    for (var cmd = 0; cmd < numberOfCommands; cmd++) {
      validSections = 0;
      for (var section = 0; section < numberOfSections; section++) {
        if (voice_command[section] == commands_table[cmd][section]) {
          validSections += 1;
        }
      }
      if (validSections == numberOfSections) {
        // Execute function
        commands_table[cmd][numberOfSections]();
        return true;
      }
    }
    return false;
  }

  // For Testing
  /*
executeCommand(getReceivedCommand("dispense water"));
executeCommand(getReceivedCommand("dispense cubed"));
executeCommand(getReceivedCommand("dispense crushed"));
executeCommand(getReceivedCommand("stop"));
executeCommand(getReceivedCommand("autofill"));
setTimeout(function() {
  executeCommand(getReceivedCommand("dispense 20 ounces water"))
}, 10000);
*/

  //TODO Enable later
  //greenBean.connect("refrigerator", function(refrigerator) {
  //console.log("========> Refrigerator connected");

io.on('connection', function(client) {
  client.on('join', function(user_info) {
    client.username = user_info.username;
    client.id = user_info.id;

    client.emit('join', nickname);
    console.log(nickname + " is connected");
  });

  sendSettings(client);

  client.on('config_set', function(settings) {
    // redisClient.hmset('settings', {
    //   user_name: settings.username,
    //   glass_ounces: settings.glass_ounces,
    //   time: settings.time
    // });
    myDataRef.set({
      "settings": {
        user_name: settings.username,
        glass_ounces: settings.glass_ounces,
        time: settings.time
      }
    });
    console.log("==> Saving settings to database = " + settings);
  });

  client.on('config_get', function(settings) {
    // redisClient.hgetall('config', function(err, settings) {
    //   console.log("==> Client " + client + "getting settings = " + settings);
    // });
    myFirebaseRef.child("config").on("value", function(settings) {
      console.log(settings.val());
    });
    sendSettings(client);
  });

  client.on('stats', function(settings) {
    myDataRef.set({
      "settings": {
        user_name: settings.username,
        glass_ounces: settings.glass_ounces,
        time: settings.time
      }
    });
    console.log("==> settings = " + settings);
    sendStats(client);
  });

  client.on('disconnect', function(name) {
    //TODO Save identifier for next time user connects
  });

  client.on('voice_command', function(voice_command) {
    client.emit('voice_cmd_response',
      executeCommand(getReceivedCommand(voice_command)));
  });

});

//TODO Enable later
//});

app.get('/', function(req, res) {
  res.sendFile(__dirname + '/index.html');
});

server.listen(8080, function() {
  console.log('listening on *:8080');
});
<commit_msg>Adding Firebase to store data<commit_after>var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var Firebase = require("firebase");
// var redis = require('redis');
// var redisClient = redis.createClient();

//Use YOUR Firebase URL (not the one below)
var myDataRef = new Firebase('https://glaring-torch-9647.firebaseio.com');
var userConsumptionTable = myDataRef.child("consumption");
var userSettingsTable = myDataRef.child("settings");

var INDEX_PRIMARY_CMD = 0;
var INDEX_SECOND_CMD_OR_OUNCES = 1;

var DISPENSE = "dispense";
var AUTOFILL = "autofill"
var STOP = "stop";
var WATER = "water";
var CUBED = "cubed";
var CRUSHED = "crushed";
var OUNCES = "ounces";
var UNUSED = "";
var NUMBER = 0;
var disp_ounces = 0;
var disp_time_ms = 0;
var autofillTimeoutId;

//TODO Enable later
//var greenBean = require("green-bean");
//var refrigerator;

//TODO Remove this later
var settings = {
  time: 2400,
  glass_ounces: 6,
  name: "FixOfWater"
};
var client = {
  id: 0
};

function getDateTime() {

  var date = new Date();

  var hour = date.getHours();
  hour = (hour < 10 ? "0" : "") + hour;

  var min = date.getMinutes();
  min = (min < 10 ? "0" : "") + min;

  var sec = date.getSeconds();
  sec = (sec < 10 ? "0" : "") + sec;

  var year = date.getFullYear();

  var month = date.getMonth() + 1;
  month = (month < 10 ? "0" : "") + month;

  var day = date.getDate();
  day = (day < 10 ? "0" : "") + day;

  return year + ":" + month + ":" + day + ":" + hour + ":" + min + ":" + sec;
}

/*!
 * Function to start dispensing water.
 */
var startDispensingWater = function() {
  //refrigerator.dispenseColdWater();
  userConsumptionTable.push({
    user_id: client.id,
    type: 'water',
    timestamp: getDateTime(),
    ounces: disp_ounces
  });
  clearTimeout(autofillTimeoutId);
  console.log("Start dispensing water.");
};

/*!
 * Function to start dispensing cubed.
 */
var startDispensingCubed = function() {
  //refrigerator.dispenseCubed();
  userConsumptionTable.push({
    user_id: client.id,
    type: 'cubes',
    timestamp: getDateTime(),
    ounces: 0
  });
  clearTimeout(autofillTimeoutId);
  console.log("Start dispensing cubed.");
};

/*!
 * Function to start dispensing crushed.
 */
var startDispensingCrushed = function() {
  //refrigerator.dispenseCrushed();
  userConsumptionTable.push({
    user_id: client.id,
    type: 'crushes',
    timestamp: getDateTime(),
    ounces: 0
  });
  clearTimeout(autofillTimeoutId);
  console.log("Start dispensing crushed.");
};

/*!
 * Function to stop dispensing.
 */
var stopDispensing = function() {
  //refrigerator.dispenseStop();
  clearTimeout(autofillTimeoutId);
  console.log("Stop dispensing.");
};

/*!
 * Function to start autofill.
 */
var startAutofill = function() {
  console.log("Autofill " + disp_ounces);
  userConsumptionTable.push({
    user_id: client.id,
    type: 'autofill',
    timestamp: getDateTime(),
    ounces: disp_ounces
  });
  startDispensingWater();
  autofillTimeoutId = setTimeout(function() {
    stopDispensing();
  }, disp_time_ms)
};

/*!
 * Table with available commands.
 */
var commands_table = [
  [DISPENSE, WATER, UNUSED, UNUSED, startDispensingWater],
  [DISPENSE, CUBED, UNUSED, UNUSED, startDispensingCubed],
  [DISPENSE, CRUSHED, UNUSED, UNUSED, startDispensingCrushed],
  [AUTOFILL, UNUSED, UNUSED, UNUSED, startAutofill],
  [DISPENSE, NUMBER, OUNCES, WATER, startAutofill],
  [STOP, UNUSED, UNUSED, UNUSED, stopDispensing]
]

/*!
 * Process the received voice data and return an array with its sections.
 * @param voice_command The received voice command.
 * @return The voice commands sections.
 */
  function getReceivedCommand(voice_command) {
    var rcvd_voice_cmd = [UNUSED, UNUSED, UNUSED, UNUSED];
    var voice_command_sections = voice_command.split(" ");
    var numberOfSections = voice_command_sections.length;

    // Short message?
    if (numberOfSections < 2) {
      rcvd_voice_cmd[INDEX_PRIMARY_CMD] = voice_command;
    } else {
      for (var index = 0; index < numberOfSections; index++) {
        rcvd_voice_cmd[index] = voice_command_sections[index];
      }
    }

    // Autofill command?
    if ((numberOfSections > INDEX_PRIMARY_CMD) &&
      (AUTOFILL == rcvd_voice_cmd[INDEX_PRIMARY_CMD])) {
      // TODO read from redis
      disp_ounces = settings.glass_ounces;
      disp_time_ms = settings.time;
      rcvd_voice_cmd[INDEX_SECOND_CMD_OR_OUNCES] = UNUSED;
    } // Precise fill command
    else if ((numberOfSections > INDEX_SECOND_CMD_OR_OUNCES) &&
      (!isNaN(parseInt(rcvd_voice_cmd[INDEX_SECOND_CMD_OR_OUNCES], 10)))) {
      disp_ounces = parseInt(rcvd_voice_cmd[INDEX_SECOND_CMD_OR_OUNCES], 10);
      disp_time_ms = disp_ounces * (settings.glass_ounces / settings.time);
      rcvd_voice_cmd[INDEX_SECOND_CMD_OR_OUNCES] = NUMBER;
    }
    return rcvd_voice_cmd;
  }

  /*!
   * Execute command a valid command.
   * @param voice_command The voice command array.
   * @return True if valid command; otherwise false;
   */
  function executeCommand(voice_command) {
    var numberOfSections = commands_table[0].length - 1;
    var numberOfCommands = commands_table.length;
    var validSections;

    for (var cmd = 0; cmd < numberOfCommands; cmd++) {
      validSections = 0;
      for (var section = 0; section < numberOfSections; section++) {
        if (voice_command[section] == commands_table[cmd][section]) {
          validSections += 1;
        }
      }
      if (validSections == numberOfSections) {
        // Execute function
        commands_table[cmd][numberOfSections]();
        return true;
      }
    }
    return false;
  }

  // TODO Remove later - Testing only
executeCommand(getReceivedCommand("dispense water"));
executeCommand(getReceivedCommand("dispense cubed"));
executeCommand(getReceivedCommand("dispense crushed"));
executeCommand(getReceivedCommand("stop"));
executeCommand(getReceivedCommand("autofill"));
setTimeout(function() {
  executeCommand(getReceivedCommand("dispense 20 ounces water"))
}, 10000);

//TODO Enable later
//greenBean.connect("refrigerator", function(refrigerator) {
//console.log("========> Refrigerator connected");
io.on('connection', function(client) {
  client.on('join', function(user_info) {
    client.username = user_info.username;
    client.id = user_info.id;

    client.emit('join', nickname);
    console.log(nickname + " is connected");
    myFirebaseRef.child("config").on("value", function(settings) {
      console.log("Settings " + settings.val());
      user_settings = settings;
    });
  });

  client.on('settings', function(settings) {
    myDataRef.push({
      "settings": {
        user_name: settings.username,
        glass_ounces: settings.glass_ounces,
        time: settings.time
      }
    });
    console.log("==> settings = " + settings);
  });

  client.on('disconnect', function(name) {
    //TODO Save identifier for next time user connects
  });

  client.on('voice_command', function(voice_command) {
    client.emit('voice_cmd_response',
      executeCommand(getReceivedCommand(voice_command)));
  });
});

//TODO Enable later
//});

app.get('/', function(req, res) {
  res.sendFile(__dirname + '/index.html');
});

server.listen(8080, function() {
  console.log('listening on *:8080');
});
<|endoftext|>


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

import {List, ListItem} from 'material-ui/List';
import ActionGrade from 'material-ui/svg-icons/action/grade';
import Avatar from 'material-ui/Avatar';
import Paper from 'material-ui/Paper';
import Divider from 'material-ui/Divider';
import FlatButton from 'material-ui/FlatButton';
import RaisedButton from 'material-ui/RaisedButton';
import {Card, CardTitle, CardText} from 'material-ui/Card';

import {red500, brown500, grey500, cyan500, transparent, white} from 'material-ui/styles/colors';

import WelcomeCard from '../Cards/WelcomeCard';
import EventsCard from '../Cards/EventsCard';

const bands = [
  {name: 'Väsen', num: 1},
  {name: 'Shillelagh', num: 2},
  {name: 'Les Zéoles', num: 3},
  {name: 'Carré Manchot', num: 4},
  {name: 'Duo Cavez-Montanaro', num: 5},
  {name: 'Carte Blanche à Michel Jacqmain', num: 6},
  {name: 'DUo Bottasso', num: 7},
  {name: 'Beat Bouet Trio', num: 8},
  {name: 'Baila Tocamos', num: 9},
  {name: 'Durif-Champeval', num: 10},
  {name: 'Elles s\'y Promènent', num: 11},
  {name: 'Duo McGowan-Munnelly', num: 12},
  {name: 'Duo TTC', num: 13},
  {name: 'Wouter Vandenabeele & Jeroen Knapen', num: 14},
  {name: 'Poke', num: 15},
  {name: 'Boutons & Ficelles', num: 16},
  {name: 'Influences', num: 17},
  {name: 'Dames de Nage', num: 18},
  {name: 'Zim Boum Trad', num: 19},
  {name: 'Grand Air', num: 20},
  {name: 'Mad Tom Duo', num: 21},
  {name: 'Le Théâtre Mabotte', num: 22},
]

const i18n_strings = {
  fr: {
    buttons: {
      progam: 'Programme',
      volunteer: 'Devenir bénévole',
    }
  },
  en: {
    buttons: {
      progam: 'Program',
      volunteer: 'volunteer',
    }
  }
}

export default class IndexPage extends React.Component {

  render() {
    var strings = i18n_strings[this.props.lang];

    return (

        <Card>

            {bands.map((band) =>
              <FlatButton label={band.name} key={band.num}
                          primary={band.num % 2} secondary={(band.num % 2) - 1}
                          labelStyle={{fontSize: 25 - Math.log(band.num) * 4}}
                          />
            )}

        </Card>

              Folk Festival Marsinne 2016

              9-10-11 Sept. 2016

              <RaisedButton label={strings.buttons.progam} primary={true}
                style={{margin: 12}} onClick={() => this.props.onPageChange('program')} />
              <RaisedButton label="Tickets" secondary={true} style={{margin: 12}}
                onClick={() => this.props.onPageChange('tickets')}/>

        <WelcomeCard lang={this.props.lang} />

        {/*<EventsCard lang={this.props.lang} /> */}

    );
  }
}
<commit_msg>Fix field requires boolean<commit_after>import React, { Component } from 'react';

import {List, ListItem} from 'material-ui/List';
import ActionGrade from 'material-ui/svg-icons/action/grade';
import Avatar from 'material-ui/Avatar';
import Paper from 'material-ui/Paper';
import Divider from 'material-ui/Divider';
import FlatButton from 'material-ui/FlatButton';
import RaisedButton from 'material-ui/RaisedButton';
import {Card, CardTitle, CardText} from 'material-ui/Card';

import {red500, brown500, grey500, cyan500, transparent, white} from 'material-ui/styles/colors';

import WelcomeCard from '../Cards/WelcomeCard';
import EventsCard from '../Cards/EventsCard';

const bands = [
  {name: 'Väsen', num: 1},
  {name: 'Shillelagh', num: 2},
  {name: 'Les Zéoles', num: 3},
  {name: 'Carré Manchot', num: 4},
  {name: 'Duo Cavez-Montanaro', num: 5},
  {name: 'Carte Blanche à Michel Jacqmain', num: 6},
  {name: 'DUo Bottasso', num: 7},
  {name: 'Beat Bouet Trio', num: 8},
  {name: 'Baila Tocamos', num: 9},
  {name: 'Durif-Champeval', num: 10},
  {name: 'Elles s\'y Promènent', num: 11},
  {name: 'Duo McGowan-Munnelly', num: 12},
  {name: 'Duo TTC', num: 13},
  {name: 'Wouter Vandenabeele & Jeroen Knapen', num: 14},
  {name: 'Poke', num: 15},
  {name: 'Boutons & Ficelles', num: 16},
  {name: 'Influences', num: 17},
  {name: 'Dames de Nage', num: 18},
  {name: 'Zim Boum Trad', num: 19},
  {name: 'Grand Air', num: 20},
  {name: 'Mad Tom Duo', num: 21},
  {name: 'Le Théâtre Mabotte', num: 22},
]

const i18n_strings = {
  fr: {
    buttons: {
      progam: 'Programme',
      volunteer: 'Devenir bénévole',
    }
  },
  en: {
    buttons: {
      progam: 'Program',
      volunteer: 'volunteer',
    }
  }
}

export default class IndexPage extends React.Component {

  render() {
    var strings = i18n_strings[this.props.lang];

    return (

        <Card>

            {bands.map((band) =>
              <FlatButton label={band.name} key={band.num}
                          primary={(band.num % 2) === 1} secondary={(band.num % 2) === 0}
                          labelStyle={{fontSize: 25 - Math.log(band.num) * 4}}
                          />
            )}

        </Card>

              Folk Festival Marsinne 2016

              9-10-11 Sept. 2016

              <RaisedButton label={strings.buttons.progam} primary={true}
                style={{margin: 12}} onClick={() => this.props.onPageChange('program')} />
              <RaisedButton label="Tickets" secondary={true} style={{margin: 12}}
                onClick={() => this.props.onPageChange('tickets')}/>

        <WelcomeCard lang={this.props.lang} />

        {/*<EventsCard lang={this.props.lang} /> */}

    );
  }
}
<|endoftext|>


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

module.exports = {
    devtool: 'source-map',
    entry: {
        "index": "./src/index.js",
    },
    output: {
        path: __dirname + "/build/lib",
	    filename: 'fluder.js',
	    library: 'Fluder',
	    libraryTarget: 'umd',
	    umdNamedDefine: true
    },
    module: {
        loaders: [{
            test: /\.js$/,
            loader: 'babel-loader',
            query: {
                presets: [ 'es2015', 'react' ]
            }
        },{test: /\.css$/, loader: 'style-loader!css-loader'}]
    },resolve: {
        extensions: ['', '.js', '.jsx', '.md', '.txt']
    },plugins: [
        //压缩
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            }
        }),
    ]
};
<commit_msg>refactor fluder lib config<commit_after>
var webpack = require('webpack');

module.exports = {
    devtool: 'source-map',
    entry: {
        "index": "./src/index.js",
    },
    output: {
        path: __dirname + "/build/lib",
	    filename: 'fluder.js',
	    library: 'Fluder',
	    libraryTarget: 'umd',
	    umdNamedDefine: true
    },
    module: {
        loaders: [{
            test: /\.js$/,
            loader: 'babel-loader',
            query: {
                presets: [ 'es2015', 'react' ]
            }
        }]
    },resolve: {
        extensions: ['', '.js', '.jsx']
    },plugins: [
        //压缩
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            }
        }),
    ]
};
<|endoftext|>


<commit_before>var express = require('express');
var bodyParser = require('body-parser');

var promoRouter = express.Router();
promoRouter.use(bodyParser.json());

promoRouter.route('/')
    .all(function(req,res,next) {
          res.writeHead(200, { 'Content-Type': 'text/plain' });
          next();
    })

    .get(function(req,res,next){
            res.end('Will send all the promotions to you!');
    })

    .post(function(req, res, next){
        res.end('Will add the promotion: ' + req.body.name + ' with details: ' + req.body.description);
    })

    .delete(function(req, res, next){
            res.end('Deleting all promotions');
    });

promoRouter.route('/:promoId')
    .all(function(req,res,next) {
          res.writeHead(200, { 'Content-Type': 'text/plain' });
          next();
    })

    .get(function(req,res,next){
            res.end('Will send details of the promotion: ' + req.params.promoId +' to you!');
    })

    .put(function(req, res, next){
            res.write('Updating the promotion: ' + req.params.promoId + '\n');
        res.end('Will update the promotion: ' + req.body.name +
                ' with details: ' + req.body.description);
    })

    .delete(function(req, res, next){
            res.end('Deleting promotion: ' + req.params.promoId);
    });

module.exports = promoRouter;
<commit_msg>update promo route to use mongoose<commit_after>var express = require('express');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');

var Promos = require('../models/leadership');

var promoRouter = express.Router();
promoRouter.use(bodyParser.json());

promoRouter.route('/')
.get(function (req, res, next) {
    Promos.find({}, function (err, promo) {
        if (err) throw err;
        res.json(promo);
    });
})

.post(function (req, res, next) {
    Promos.create(req.body, function (err, promo) {
        if (err) throw err;
        console.log('promo created!');
        var id = promo._id;

        res.writeHead(200, {
            'Content-Type': 'text/plain'
        });
        res.end('Added the promo with id: ' + id);
    });
})

.delete(function (req, res, next) {
    Promos.remove({}, function (err, resp) {
        if (err) throw err;
        res.json(resp);
    });
});

promoRouter.route('/:promoId')
.get(function (req, res, next) {
    Promos.findById(req.params.promoId, function (err, promo) {
        if (err) throw err;
        res.json(promo);
    });
})

.put(function (req, res, next) {
    Promos.findByIdAndUpdate(req.params.promoId, {
        $set: req.body
    }, {
        new: true
    }, function (err, promo) {
        if (err) throw err;
        res.json(promo);
    });
})

.delete(function (req, res, next) {
    Promos.findByIdAndRemove(req.params.promoId, function (err, resp) {        if (err) throw err;
        res.json(resp);
    });
});

module.exports = promoRouter;
<|endoftext|>


<commit_before>"use strict";

var CACHE = "odymaterialy-v20";
var APIURI = "https://odymaterialy.skauting.cz/API/v0.9"
var cacheBlocking = [
	"/index.html",
	"/styles/fontello.css",
	"/styles/competenceBubble.css",
	"/styles/lesson.css",
	"/styles/main.css",
	"/styles/mainPage.css",
	"/styles/nav.css",
	"/styles/offlineSwitch.css",
	"/styles/topUI.css",
	"/styles/handheld.css",
	"/styles/computer.css",
	"/client-config.json",
	"/scripts/tools/AfterLoadEvent.js",
	"/scripts/tools/cacheThenNetworkRequest.js",
	"/scripts/tools/config.js",
	"/scripts/tools/getLessonById.js",
	"/scripts/tools/OdyMarkdown.js",
	"/scripts/tools/request.js",
	"/scripts/tools/urlEscape.js",
	"/scripts/UI/header.js",
	"/scripts/UI/lessonView.js",
	"/scripts/UI/navigation.js",
	"/scripts/UI/TOC.js",
	"/scripts/views/competence.js",
	"/scripts/views/competenceList.js",
	"/scripts/views/field.js",
	"/scripts/views/lesson.js",
	"/scripts/views/lessonList.js",
	"/scripts/authentication.js",
	"/scripts/history.js",
	"/scripts/main.js",
	"/scripts/metadata.js"
];
var cacheNonBlocking = [
	"/node_modules/showdown/dist/showdown.min.js",
	"/node_modules/xss/dist/xss.min.js",
	"/font/fontello.woff"
];

var cacheUpdating = [
	APIURI + "/lesson",
	APIURI + "/competence"
];

function startsWith(haystack, needle)
{
	return haystack.substr(0, needle.length) === needle;
}

self.addEventListener("install", function(event)
	{
		event.waitUntil(
			caches.open(CACHE).then(function(cache)
				{
					cache.addAll(cacheNonBlocking);
					return cache.addAll(cacheBlocking);
				})
		);
	});

self.addEventListener("fetch", function(event)
	{
		var url = new URL(event.request.url);
		if(cacheUpdating.indexOf(url.pathname) !== -1)
		{
			event.respondWith(cacheUpdatingResponse(event.request));
		}
		else if(startsWith(url.pathname, APIURI + "/lesson"))
		{
			event.respondWith(cacheOnDemandResponse(event.request));
		}
		else
		{
			event.respondWith(genericResponse(event.request));
		}
	});

function cacheUpdatingResponse(request)
{
	if(request.headers.get("Accept") === "x-cache/only")
	{
		return new Promise((resolve) => {
				caches.match(request).then(function(response)
					{
						if(response)
						{
							resolve(response);
						}
						else
						{
							resolve(new Response(new Blob(["{\"status\": 404}"]), {"status": 404, "statusText": "Not Found"}));
						}
					});
			});
	}
	else
	{
		return fetch(request).then(function(response)
			{
				return cacheClone(request, response);
			});
	}
}

function cacheOnDemandResponse(request)
{
	if(request.headers.get("Accept") === "x-cache/only")
	{
		return caches.open(CACHE).then(function(cache)
			{
				return cache.match(request);
			});
	}
	else
	{
		return fetch(request).then(function(response)
			{
				return caches.open(CACHE).then(function(cache)
					{
						return cache.match(request).then(function(cachedResponse)
							{
								if(cachedResponse === undefined)
								{
									return response
								}
								return cacheClone(request, response);
							});
					});
			});
	}
}

function genericResponse(request)
{
	return caches.open(CACHE).then(function(cache)
		{
			return cache.match(request).then(function(response)
				{
					if(response)
					{
						return response;
					}
					return fetch(request);
				})
		});
}

function cacheClone(request, response)
{
	return caches.open(CACHE).then(function(cache)
		{
			cache.put(request, response.clone());
			return response;
		});
}
<commit_msg>Fixed SW not cache hitting lesson and competence lists<commit_after>"use strict";

var CACHE = "odymaterialy-v20";
var APIPATH = "/API/v0.9"
var cacheBlocking = [
	"/index.html",
	"/styles/fontello.css",
	"/styles/competenceBubble.css",
	"/styles/lesson.css",
	"/styles/main.css",
	"/styles/mainPage.css",
	"/styles/nav.css",
	"/styles/offlineSwitch.css",
	"/styles/topUI.css",
	"/styles/handheld.css",
	"/styles/computer.css",
	"/client-config.json",
	"/scripts/tools/AfterLoadEvent.js",
	"/scripts/tools/cacheThenNetworkRequest.js",
	"/scripts/tools/config.js",
	"/scripts/tools/getLessonById.js",
	"/scripts/tools/OdyMarkdown.js",
	"/scripts/tools/request.js",
	"/scripts/tools/urlEscape.js",
	"/scripts/UI/header.js",
	"/scripts/UI/lessonView.js",
	"/scripts/UI/navigation.js",
	"/scripts/UI/TOC.js",
	"/scripts/views/competence.js",
	"/scripts/views/competenceList.js",
	"/scripts/views/field.js",
	"/scripts/views/lesson.js",
	"/scripts/views/lessonList.js",
	"/scripts/authentication.js",
	"/scripts/history.js",
	"/scripts/main.js",
	"/scripts/metadata.js"
];
var cacheNonBlocking = [
	"/node_modules/showdown/dist/showdown.min.js",
	"/node_modules/xss/dist/xss.min.js",
	"/font/fontello.woff"
];

var cacheUpdating = [
	APIPATH + "/lesson",
	APIPATH + "/competence"
];

function startsWith(haystack, needle)
{
	return haystack.substr(0, needle.length) === needle;
}

self.addEventListener("install", function(event)
	{
		event.waitUntil(
			caches.open(CACHE).then(function(cache)
				{
					cache.addAll(cacheNonBlocking);
					return cache.addAll(cacheBlocking);
				})
		);
	});

self.addEventListener("fetch", function(event)
	{
		var url = new URL(event.request.url);
		if(cacheUpdating.indexOf(url.pathname) !== -1)
		{
			event.respondWith(cacheUpdatingResponse(event.request));
		}
		else if(startsWith(url.pathname, APIPATH + "/lesson"))
		{
			event.respondWith(cacheOnDemandResponse(event.request));
		}
		else
		{
			event.respondWith(genericResponse(event.request));
		}
	});

function cacheUpdatingResponse(request)
{
	if(request.headers.get("Accept") === "x-cache/only")
	{
		return new Promise((resolve) => {
				caches.match(request).then(function(response)
					{
						if(response)
						{
							resolve(response);
						}
						else
						{
							resolve(new Response(new Blob(["{\"status\": 404}"]), {"status": 404, "statusText": "Not Found"}));
						}
					});
			});
	}
	else
	{
		return fetch(request).then(function(response)
			{
				return cacheClone(request, response);
			});
	}
}

function cacheOnDemandResponse(request)
{
	if(request.headers.get("Accept") === "x-cache/only")
	{
		return caches.open(CACHE).then(function(cache)
			{
				return cache.match(request);
			});
	}
	else
	{
		return fetch(request).then(function(response)
			{
				return caches.open(CACHE).then(function(cache)
					{
						return cache.match(request).then(function(cachedResponse)
							{
								if(cachedResponse === undefined)
								{
									return response
								}
								return cacheClone(request, response);
							});
					});
			});
	}
}

function genericResponse(request)
{
	return caches.open(CACHE).then(function(cache)
		{
			return cache.match(request).then(function(response)
				{
					if(response)
					{
						return response;
					}
					return fetch(request);
				})
		});
}

function cacheClone(request, response)
{
	return caches.open(CACHE).then(function(cache)
		{
			cache.put(request, response.clone());
			return response;
		});
}
<|endoftext|>