<commit_before>// X.509 Self-signed Certificate with Web Cryptography API and PKIjs
//
// Copyright (c) 2015 Info Tech, Inc.
// Provided under the MIT license.
// See LICENSE file for details.

document.addEventListener("DOMContentLoaded", function() {
    "use strict";

    // Fix Apple prefix if needed
    if (window.crypto && !window.crypto.subtle && window.crypto.webkitSubtle) {
        window.crypto.subtle = window.crypto.webkitSubtle;  // Won't work if subtle already exists
    }

    // Check that web crypto is even available
    if (!window.crypto || !window.crypto.subtle) {
        alert("Your browser does not support the Web Cryptography API! This page will not work.");
        return;
    }

    document.getElementById("create-certificate").addEventListener("click", createCertificate);

    function createCertificate() {
        var keyPair;

        var commonName       = document.getElementById("common-name").value;
        var organization     = document.getElementById("organization").value;
        var organizationUnit = document.getElementById("organization-unit").value;
        var countryCode      = document.getElementById("country-code").value;

        if (!commonName) {alert("You must enter a name for the certificate."); return;}
        if (countryCode.length !== 2) {alert("Country codes must be two characters long."); return;}
        countryCode = countryCode.toUpperCase();

        window.crypto.subtle.generateKey(
            {
                name: "RSASSA-PKCS1-v1_5",
                modulusLength: 2048,
                publicExponent: new Uint8Array([1, 0, 1]),  // 24 bit representation of 65537
                hash: {name: "SHA-256"}
            },
            true,   // Must extract private key to create PEM files later
            ["sign", "verify"]
        ).
        then(function(newKeyPair) {
            keyPair = newKeyPair;
            return keyPair;
        }) .
        then(function(keyPair) {
            return buildCertificateObject(commonName, organization, organizationUnit, countryCode, keyPair);
        }) .
        then(function(cert) {
            var pemCert = convertBinaryToPem(cert.toSchema(true).toBER(false), "CERTIFICATE");
            var pemUrl = "data:application/octet-stream;charset=UTF-8;base64," + btoa(pemCert);
            document.getElementById("pem-certificate").innerText = pemCert;
            document.getElementById("certificate-download").setAttribute("href", pemUrl);

            window.crypto.subtle.exportKey('spki', keyPair.publicKey).
            then(function(spki) {
                var pemPublicKey = convertBinaryToPem(spki, "PUBLIC KEY");
                var pemUrl = "data:application/octet-stream;charset=UTF-8;base64," + btoa(pemPublicKey);
                document.getElementById("pem-public-key").innerText = pemPublicKey;
                document.getElementById("public-key-download").setAttribute("href", pemUrl);
            });

            window.crypto.subtle.exportKey('pkcs8', keyPair.privateKey).
            then(function(pkcs8) {
                var pemPrivateKey = convertBinaryToPem(pkcs8, "PRIVATE KEY");
                var pemUrl = "data:application/octet-stream;charset=UTF-8;base64," + btoa(pemPrivateKey);
                document.getElementById("pem-private-key").innerText = pemPrivateKey;
                document.getElementById("private-key-download").setAttribute("href", pemUrl);
            });
        }).
        catch(function(err) {
            alert("Error creating certificate: " + err.message);
        });
    }

    // Returns a Promise yielding the certificate object
    function buildCertificateObject(commonName, organization, organizationUnit, countryCode, keyPair) {
        var cert = new org.pkijs.simpl.CERT();

        setSerialNumber(cert, Date.now());
        setSubject(cert, countryCode, organization, organizationUnit, commonName);
        setIssuer(cert, countryCode, organization, organizationUnit, commonName);
        setValidityPeriod(cert, new Date(), 730);  // Good from today for 730 days
        setEmptyExtensions(cert);
        setCABit(cert, false);
        setKeyUsage(cert, true, true, false, false, false, true, true); // digitalSignature, nonRepudiation, keyCertSign, cRLSign
        setSignatureAlgorithm(cert, "1.2.840.113549.1.1.11"); // RSA with SHA-256

        return setPublicKey(cert, keyPair.publicKey).
            then(function() {return signCert(cert, "1.2.840.113549.1.1.11", keyPair.privateKey)}).
            then(function() {return cert});

        // Helper functions

        function setSerialNumber(cert, serialNumber) {
            cert.serialNumber = new org.pkijs.asn1.INTEGER({value: serialNumber});;
        }

        function setSubject(cert, countryCode, organization, organizationUnit, commonName) {
            setEntity(cert.subject, countryCode, organization, organizationUnit, commonName);
        }

        function setIssuer(cert, countryCode, organization, organizationUnit, commonName) {
            setEntity(cert.issuer, countryCode, organization, organizationUnit, commonName);
        }

        function setEntity(entity, countryCode, organization, organizationUnit, commonName) {
            if (countryCode) {
                entity.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({
                        type: "2.5.4.6", //countryCode
                        value: new org.pkijs.asn1.PRINTABLESTRING({value: countryCode})
                }));
            }

            if (organization) {
                entity.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({
                    type: "2.5.4.10", //Organization
                    value: new org.pkijs.asn1.PRINTABLESTRING({value: organization})
                }));
            }

            if (organizationUnit) {
                entity.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({
                    type: "2.5.4.11", //Organization Unit
                    value: new org.pkijs.asn1.PRINTABLESTRING({value: organizationUnit})
                }));
            }

            if (commonName) {
                entity.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({
                    type: "2.5.4.3", //commonName
                    value: new org.pkijs.asn1.PRINTABLESTRING({value: commonName})
                }));
            }
        }

        function setValidityPeriod(cert, startDate, durationInDays) {
            // Normalize to midnight
            var start = new Date(startDate);
            start.setHours(0);
            start.setMinutes(0);
            start.setSeconds(0);
            var end   = new Date(start.getTime() + durationInDays * 24 * 60 * 60 * 1000);

            cert.notBefore.value = start;
            cert.notAfter.value  = end;
        }

        function setEmptyExtensions(cert) {
            cert.extensions = new Array();
        }

        function setCABit(cert, isCA) {
            var basicConstraints = new org.pkijs.simpl.x509.BasicConstraints({
                cA: isCA,
                pathLenConstraint: 3
            });

            cert.extensions.push(new org.pkijs.simpl.EXTENSION({
                extnID: "2.5.29.19",
                critical: false,
                extnValue: basicConstraints.toSchema().toBER(false),
                parsedValue: basicConstraints
            }));
        }

        function setKeyUsage(cert, digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign) {
            var keyUsageBits = new ArrayBuffer(1);
            var keyUsageBytes = new Uint8Array(keyUsageBits);

            keyUsageBytes[0] = 0;
            if (digitalSignature)   {keyUsageBytes[0] |= 0x80;}
            if (nonRepudiation)     {keyUsageBytes[0] |= 0x40;}
            if (keyEncipherment)    {keyUsageBytes[0] |= 0x20;}
            if (dataEncipherment)   {keyUsageBytes[0] |= 0x10;}
            if (keyAgreement)       {keyUsageBytes[0] |= 0x08;}
            if (keyCertSign)        {keyUsageBytes[0] |= 0x04;}
            if (cRLSign)            {keyUsageBytes[0] |= 0x02;}

            var keyUsage = new org.pkijs.asn1.BITSTRING({value_hex: keyUsageBits});
            cert.extensions.push(new org.pkijs.simpl.EXTENSION({
                extnID: "2.5.29.15",
                critical: false,
                extnValue: keyUsage.toBER(false),
                parsedValue: keyUsage
            }));
        }

        function setSignatureAlgorithm(cert, oid) {
            cert.signatureAlgorithm.algorithm_id = oid; // In tbsCert
        }

        function setPublicKey(cert, publicKey) {
            return cert.subjectPublicKeyInfo.importKey(publicKey);
        }

        function signCert(cert, oid, privateKey) {
            cert.signature.algorithm_id = oid; // In actual signature
            return cert.sign(privateKey);
        }
    }

    // General helper functions

    function arrayBufferToBase64String(arrayBuffer) {
        var byteArray = new Uint8Array(arrayBuffer)
        var byteString = '';

        for (var i=0; i<byteArray.byteLength; i++) {
            byteString += String.fromCharCode(byteArray[i]);
        }

        return btoa(byteString);
    }

    function convertBinaryToPem(binaryData, label) {
        var base64Cert = arrayBufferToBase64String(binaryData);

        var pemCert = "-----BEGIN " + label + "-----\r\n";

        var nextIndex = 0;
        var lineLength;
        while (nextIndex < base64Cert.length) {
            if (nextIndex + 64 <= base64Cert.length) {
                pemCert += base64Cert.substr(nextIndex, 64) + "\r\n";
            } else {
                pemCert += base64Cert.substr(nextIndex) + "\r\n";
            }
            nextIndex += 64;
        }

        pemCert += "-----END " + label + "-----\r\n";
        return pemCert;
    }

});
<commit_msg>Now using standard textContent property instead of non-standard innerText. Displays results in Firefox now<commit_after>// X.509 Self-signed Certificate with Web Cryptography API and PKIjs
//
// Copyright (c) 2015 Info Tech, Inc.
// Provided under the MIT license.
// See LICENSE file for details.

document.addEventListener("DOMContentLoaded", function() {
    "use strict";

    // Fix Apple prefix if needed
    if (window.crypto && !window.crypto.subtle && window.crypto.webkitSubtle) {
        window.crypto.subtle = window.crypto.webkitSubtle;  // Won't work if subtle already exists
    }

    // Check that web crypto is even available
    if (!window.crypto || !window.crypto.subtle) {
        alert("Your browser does not support the Web Cryptography API! This page will not work.");
        return;
    }

    document.getElementById("create-certificate").addEventListener("click", createCertificate);

    function createCertificate() {
        var keyPair;

        var commonName       = document.getElementById("common-name").value;
        var organization     = document.getElementById("organization").value;
        var organizationUnit = document.getElementById("organization-unit").value;
        var countryCode      = document.getElementById("country-code").value;

        if (!commonName) {alert("You must enter a name for the certificate."); return;}
        if (countryCode.length !== 2) {alert("Country codes must be two characters long."); return;}
        countryCode = countryCode.toUpperCase();

        window.crypto.subtle.generateKey(
            {
                name: "RSASSA-PKCS1-v1_5",
                modulusLength: 2048,
                publicExponent: new Uint8Array([1, 0, 1]),  // 24 bit representation of 65537
                hash: {name: "SHA-256"}
            },
            true,   // Must extract private key to create PEM files later
            ["sign", "verify"]
        ).
        then(function(newKeyPair) {
            keyPair = newKeyPair;
            return keyPair;
        }) .
        then(function(keyPair) {
            return buildCertificateObject(commonName, organization, organizationUnit, countryCode, keyPair);
        }) .
        then(function(cert) {
            var pemCert = convertBinaryToPem(cert.toSchema(true).toBER(false), "CERTIFICATE");
            var pemUrl = "data:application/octet-stream;charset=UTF-8;base64," + btoa(pemCert);
            document.getElementById("pem-certificate").textContent = pemCert;
            document.getElementById("certificate-download").setAttribute("href", pemUrl);

            window.crypto.subtle.exportKey('spki', keyPair.publicKey).
            then(function(spki) {
                var pemPublicKey = convertBinaryToPem(spki, "PUBLIC KEY");
                var pemUrl = "data:application/octet-stream;charset=UTF-8;base64," + btoa(pemPublicKey);
                document.getElementById("pem-public-key").textContent = pemPublicKey;
                document.getElementById("public-key-download").setAttribute("href", pemUrl);
            });

            window.crypto.subtle.exportKey('pkcs8', keyPair.privateKey).
            then(function(pkcs8) {
                var pemPrivateKey = convertBinaryToPem(pkcs8, "PRIVATE KEY");
                var pemUrl = "data:application/octet-stream;charset=UTF-8;base64," + btoa(pemPrivateKey);
                document.getElementById("pem-private-key").textContent = pemPrivateKey;
                document.getElementById("private-key-download").setAttribute("href", pemUrl);
            });
        }).
        catch(function(err) {
            alert("Error creating certificate: " + err.message);
        });
    }

    // Returns a Promise yielding the certificate object
    function buildCertificateObject(commonName, organization, organizationUnit, countryCode, keyPair) {
        var cert = new org.pkijs.simpl.CERT();

        setSerialNumber(cert, Date.now());
        setSubject(cert, countryCode, organization, organizationUnit, commonName);
        setIssuer(cert, countryCode, organization, organizationUnit, commonName);
        setValidityPeriod(cert, new Date(), 730);  // Good from today for 730 days
        setEmptyExtensions(cert);
        setCABit(cert, false);
        setKeyUsage(cert, true, true, false, false, false, true, true); // digitalSignature, nonRepudiation, keyCertSign, cRLSign
        setSignatureAlgorithm(cert, "1.2.840.113549.1.1.11"); // RSA with SHA-256

        return setPublicKey(cert, keyPair.publicKey).
            then(function() {return signCert(cert, "1.2.840.113549.1.1.11", keyPair.privateKey)}).
            then(function() {return cert});

        // Helper functions

        function setSerialNumber(cert, serialNumber) {
            cert.serialNumber = new org.pkijs.asn1.INTEGER({value: serialNumber});;
        }

        function setSubject(cert, countryCode, organization, organizationUnit, commonName) {
            setEntity(cert.subject, countryCode, organization, organizationUnit, commonName);
        }

        function setIssuer(cert, countryCode, organization, organizationUnit, commonName) {
            setEntity(cert.issuer, countryCode, organization, organizationUnit, commonName);
        }

        function setEntity(entity, countryCode, organization, organizationUnit, commonName) {
            if (countryCode) {
                entity.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({
                        type: "2.5.4.6", //countryCode
                        value: new org.pkijs.asn1.PRINTABLESTRING({value: countryCode})
                }));
            }

            if (organization) {
                entity.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({
                    type: "2.5.4.10", //Organization
                    value: new org.pkijs.asn1.PRINTABLESTRING({value: organization})
                }));
            }

            if (organizationUnit) {
                entity.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({
                    type: "2.5.4.11", //Organization Unit
                    value: new org.pkijs.asn1.PRINTABLESTRING({value: organizationUnit})
                }));
            }

            if (commonName) {
                entity.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({
                    type: "2.5.4.3", //commonName
                    value: new org.pkijs.asn1.PRINTABLESTRING({value: commonName})
                }));
            }
        }

        function setValidityPeriod(cert, startDate, durationInDays) {
            // Normalize to midnight
            var start = new Date(startDate);
            start.setHours(0);
            start.setMinutes(0);
            start.setSeconds(0);
            var end   = new Date(start.getTime() + durationInDays * 24 * 60 * 60 * 1000);

            cert.notBefore.value = start;
            cert.notAfter.value  = end;
        }

        function setEmptyExtensions(cert) {
            cert.extensions = new Array();
        }

        function setCABit(cert, isCA) {
            var basicConstraints = new org.pkijs.simpl.x509.BasicConstraints({
                cA: isCA,
                pathLenConstraint: 3
            });

            cert.extensions.push(new org.pkijs.simpl.EXTENSION({
                extnID: "2.5.29.19",
                critical: false,
                extnValue: basicConstraints.toSchema().toBER(false),
                parsedValue: basicConstraints
            }));
        }

        function setKeyUsage(cert, digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign) {
            var keyUsageBits = new ArrayBuffer(1);
            var keyUsageBytes = new Uint8Array(keyUsageBits);

            keyUsageBytes[0] = 0;
            if (digitalSignature)   {keyUsageBytes[0] |= 0x80;}
            if (nonRepudiation)     {keyUsageBytes[0] |= 0x40;}
            if (keyEncipherment)    {keyUsageBytes[0] |= 0x20;}
            if (dataEncipherment)   {keyUsageBytes[0] |= 0x10;}
            if (keyAgreement)       {keyUsageBytes[0] |= 0x08;}
            if (keyCertSign)        {keyUsageBytes[0] |= 0x04;}
            if (cRLSign)            {keyUsageBytes[0] |= 0x02;}

            var keyUsage = new org.pkijs.asn1.BITSTRING({value_hex: keyUsageBits});
            cert.extensions.push(new org.pkijs.simpl.EXTENSION({
                extnID: "2.5.29.15",
                critical: false,
                extnValue: keyUsage.toBER(false),
                parsedValue: keyUsage
            }));
        }

        function setSignatureAlgorithm(cert, oid) {
            cert.signatureAlgorithm.algorithm_id = oid; // In tbsCert
        }

        function setPublicKey(cert, publicKey) {
            return cert.subjectPublicKeyInfo.importKey(publicKey);
        }

        function signCert(cert, oid, privateKey) {
            cert.signature.algorithm_id = oid; // In actual signature
            return cert.sign(privateKey);
        }
    }

    // General helper functions

    function arrayBufferToBase64String(arrayBuffer) {
        var byteArray = new Uint8Array(arrayBuffer)
        var byteString = '';

        for (var i=0; i<byteArray.byteLength; i++) {
            byteString += String.fromCharCode(byteArray[i]);
        }

        return btoa(byteString);
    }

    function convertBinaryToPem(binaryData, label) {
        var base64Cert = arrayBufferToBase64String(binaryData);

        var pemCert = "-----BEGIN " + label + "-----\r\n";

        var nextIndex = 0;
        var lineLength;
        while (nextIndex < base64Cert.length) {
            if (nextIndex + 64 <= base64Cert.length) {
                pemCert += base64Cert.substr(nextIndex, 64) + "\r\n";
            } else {
                pemCert += base64Cert.substr(nextIndex) + "\r\n";
            }
            nextIndex += 64;
        }

        pemCert += "-----END " + label + "-----\r\n";
        return pemCert;
    }

});
<|endoftext|>


<commit_before>'use strict';

//var _ = require('lodash');
var Q = require('q');
var expand = require('glob-expand');

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var $28 = new (require('28').$28)('http://portal.28.io/api');

var Config = require('./config');

var credentials;

var Options = {
    OVERWRITE_ALWAYS: 0,
    OVERWRITE_NEVER: 1,
    OVERWRITE_ASK: 2,
    OVERWRITE_IF_NEWER: 3
};

var throwError = function (error) {
    var message = JSON.stringify(error);
    if(error.body){
        var body = error.body;
        if(typeof body === 'string'){
            try {
                body = JSON.parse(body);
            } catch (e) {

            }
        }
        message = JSON.stringify(body, null, '\t');
        if(typeof body === 'object' && (( body.length && body[0].context ) || body.context)){
            $.util.log(message);
            message = 'Compilation error';
        }
    }
    if(error.message){
        message = error.message;
    }
    if(message.length > 500){
        message = message.substring(0, 500) + ' ... (truncated)';
    }
    throw new $.util.PluginError(__filename, message);
};

var castToJson = function(obj){
    var result = obj;
    if(typeof obj === 'string'){
        try {
            result = JSON.parse(obj);
        } catch (e) {

        }
    }
    return result;
};

var summarizeTestError = function(error){
    var hasError = false;
    if(error.body) {
        var body = castToJson(error.body);
        if(typeof body.items === 'object' && body.items.length > 0){
            body = castToJson(body.items[0]);
        }
        if(body.content){
            body = castToJson(body.content);
        }
        for (var testName in body) {
            if (body.hasOwnProperty(testName)){
                var testResult = body[testName];
                if (typeof testResult === 'object') {
                    hasError = true;
                    $.util.log(testName.red + ': ' + testResult.url);
                    if (testResult.expectedFactTable && testResult.expectedFactTable.error === true) {
                        $.util.log(testName.red + ': ' + JSON.stringify(testResult.expectedFactTable, null, '\t'));
                    }
                    if (testResult.factTableDiff) {
                        for (var diff in testResult.factTableDiff) {
                            if (testResult.factTableDiff.hasOwnProperty(diff)) {
                                if (diff.expectedNumberOfFacts) {
                                    $.util.log(testName.red + ': ' + JSON.stringify(diff, null, '\t'));
                                }
                            }
                        }
                    }
                }
            }
        }
        if (hasError) {
            return new Error('some test queries failed');
        }
    }
    return error;
};

var login = function(email, password){
    $.util.log('Logging in as ' + email);
    return $28.login(email, password).then(function(response){
        $.util.log('Logged in.');
        credentials = response.body;
        return credentials;
    });
};

var removeProject = function(projectName, isIdempotent){
    /*jshint camelcase:false */
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        var token = credentials.access_token;
        $.util.log('Deleting project ' + projectName);
        $28.deleteProject(projectName, token).then(function () {
            $.util.log('Project deleted.');
            defered.resolve(credentials);
        }).catch(function (error) {
            if (!isIdempotent) {
                defered.reject(error);
            } else {
                defered.resolve(credentials);
            }
        });
    } else {
        $.util.log('Skipping project deletion for production: ' + projectName);
        defered.resolve(credentials);
    }
    return defered.promise;
};

var createProject = function(projectName){
    /*jshint camelcase:false */
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        var token = credentials.access_token;
        $.util.log('Creating project ' + projectName);
        $28.createProject(projectName, token).then(function (response) {
            $.util.log('Project  ' + projectName + ' created.');
            /*jshint camelcase:false */
            credentials.project_tokens['project_' + projectName] = response.body.projectToken;
            defered.resolve(credentials);
        }).catch(function (error) {
            $.util.log('Project creation failed: ' + error);
            defered.reject(error);
        });
    } else {
        $.util.log('Skipping project creation on production: ' + projectName);
        defered.resolve(credentials);
    }
    return defered.promise;
};

var upload = function(projectName){
    /*jshint camelcase:false */
    var projectToken = credentials.project_tokens['project_' + projectName];
    if(!projectToken) {
        throw new Error('project not found ' + projectName);
    }
    var projectPath = Config.paths.queries;
    var overwrite = Options.OVERWRITE_ALWAYS;
    var deleteOrphaned = true;
    var simulate = false;
    $.util.log('Uploading queries.');
    return $28.upload(projectName, projectToken, projectPath, overwrite, deleteOrphaned, simulate, []).then(function(){
        $.util.log('Queries uploaded.');
        return credentials;
    });
};

var download = function(projectName){
    /*jshint camelcase:false */
    var projectToken = credentials.project_tokens['project_' + projectName];
    if(!projectToken) {
        throw new Error('project not found ' + projectName);
    }
    var projectPath = Config.paths.queries;
    var overwrite = Options.OVERWRITE_ALWAYS;
    var deleteOrphaned = true;
    var simulate = false;
    $.util.log('Downloading queries.');
    return $28.download(projectName, projectToken, projectPath, overwrite, deleteOrphaned, simulate, []).then(function(){
        $.util.log('Queries downloaded.');
        return credentials;
    });
};

var runQueries = function(projectName, queriesToRun) {
    var sequenceOfQueries = [];
    queriesToRun.forEach(function(queries){
        queries = expand(queries);
        queries.forEach(function(query) {
            var queryPath = query.substring(Config.paths.queries.length + 1);
            sequenceOfQueries.push(queryPath);
        });
    });

    if (sequenceOfQueries.length === 0){
        $.util.log('At least 1 query to init and for the API tests need to be provided.'.red);
        throw new Error('No queries to run for: ' + JSON.stringify(queriesToRun));
    }

    var Queries = $28.api.Queries(projectName);
    /*jshint camelcase:false */
    var projectToken = credentials.project_tokens['project_' + projectName];
    return sequenceOfQueries.reduce(function(previousPromise, nextQuery){
        return previousPromise.then(function(){
            return Queries.executeQuery({
                accept: 'application/28.io+json',
                queryPath: nextQuery,
                format: '',
                token: projectToken
            }).then(function (data) {
                $.util.log(('✓ '.green) + nextQuery + ' returned with status code: ' + data.response.statusCode);
                return credentials;
            }).catch(function (error) {
                var requestUri = error.response.request.uri;
                var isTestQuery = (requestUri.pathname.lastIndexOf('/v1/_queries/public/test', 0) === 0);
                var href = isTestQuery ? requestUri.host + requestUri.pathname.substring('/v1/_queries/public'.length) : requestUri.host + requestUri.pathname;
                $.util.log(('✗ '.red) + href + ' returned with status code: ' + $.util.colors.red(error.response.statusCode));
                error = isTestQuery ? summarizeTestError(error) : error;
                throw error;
            });
        });
    }, /* init: */ Q.resolve());
};

var createDatasource = function(projectName, datasource){
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        $.util.log('Creating datasource ' + datasource.name);
        var difault = datasource.default ? datasource.default : false;
        /*jshint camelcase:false */
        var projectToken = credentials.project_tokens['project_' + projectName];
        $28.createDatasource(projectName, datasource.category, datasource.name, projectToken, difault, JSON.stringify(datasource.credentials))
        .then(function(){
            $.util.log(datasource.name + ' created');
            defered.resolve(credentials);
        })
        .catch(function (error) {
            $.util.log('datasource creation failed: ' + datasource.name);
            defered.reject(error);
        });
    } else {
        $.util.log('Skipping data source creation on production: ' + datasource.name);
        defered.resolve(credentials);
    }
    return defered.promise;
};

gulp.task('28:login', function(){
    return login(Config.credentials['28'].email, Config.credentials['28'].password).catch(throwError);
});

gulp.task('28:create-project', function(){
    return createProject(Config.projectName, true).catch(throwError);
});

gulp.task('28:remove-project', function(){
    return removeProject(Config.projectName, true).catch(throwError);
});

gulp.task('28:upload', function(){
    return upload(Config.projectName).catch(throwError);
});

gulp.task('28:download', function(){
    return download(Config.projectName).catch(throwError);
});

gulp.task('28:setup-datasource', function(){
    var promises = [];
    Config.credentials['28'].datasources.forEach(function(datasource){
        promises.push(createDatasource(Config.projectName, datasource).catch(throwError));
    });
    return Q.all(promises);
});

gulp.task('28:init', function(){
    return runQueries(Config.projectName, Config.paths.initQueries).catch(throwError);
});

gulp.task('28:test', function(){
    return runQueries(Config.projectName, Config.paths.apiTestQueries).catch(throwError);
});
<commit_msg>run all queries at once in travis.<commit_after>'use strict';

//var _ = require('lodash');
var Q = require('q');
var expand = require('glob-expand');

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var $28 = new (require('28').$28)('http://portal.28.io/api');

var Config = require('./config');

var credentials;

var Options = {
    OVERWRITE_ALWAYS: 0,
    OVERWRITE_NEVER: 1,
    OVERWRITE_ASK: 2,
    OVERWRITE_IF_NEWER: 3
};

var throwError = function (error) {
    var message = JSON.stringify(error);
    if(error.body){
        var body = error.body;
        if(typeof body === 'string'){
            try {
                body = JSON.parse(body);
            } catch (e) {

            }
        }
        message = JSON.stringify(body, null, '\t');
        if(typeof body === 'object' && (( body.length && body[0].context ) || body.context)){
            $.util.log(message);
            message = 'Compilation error';
        }
    }
    if(error.message){
        message = error.message;
    }
    if(message.length > 500){
        message = message.substring(0, 500) + ' ... (truncated)';
    }
    throw new $.util.PluginError(__filename, message);
};

var castToJson = function(obj){
    var result = obj;
    if(typeof obj === 'string'){
        try {
            result = JSON.parse(obj);
        } catch (e) {

        }
    }
    return result;
};

var summarizeTestError = function(error){
    var hasError = false;
    if(error.body) {
        var body = castToJson(error.body);
        if(typeof body.items === 'object' && body.items.length > 0){
            body = castToJson(body.items[0]);
        }
        if(body.content){
            body = castToJson(body.content);
        }
        for (var testName in body) {
            if (body.hasOwnProperty(testName)){
                var testResult = body[testName];
                if (typeof testResult === 'object') {
                    hasError = true;
                    $.util.log(testName.red + ': ' + testResult.url);
                    if (testResult.expectedFactTable && testResult.expectedFactTable.error === true) {
                        $.util.log(testName.red + ': ' + JSON.stringify(testResult.expectedFactTable, null, '\t'));
                    }
                    if (testResult.factTableDiff) {
                        for (var diff in testResult.factTableDiff) {
                            if (testResult.factTableDiff.hasOwnProperty(diff)) {
                                if (diff.expectedNumberOfFacts) {
                                    $.util.log(testName.red + ': ' + JSON.stringify(diff, null, '\t'));
                                }
                            }
                        }
                    }
                }
            }
        }
        if (hasError) {
            return new Error('some test queries failed');
        }
    }
    return error;
};

var login = function(email, password){
    $.util.log('Logging in as ' + email);
    return $28.login(email, password).then(function(response){
        $.util.log('Logged in.');
        credentials = response.body;
        return credentials;
    });
};

var removeProject = function(projectName, isIdempotent){
    /*jshint camelcase:false */
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        var token = credentials.access_token;
        $.util.log('Deleting project ' + projectName);
        $28.deleteProject(projectName, token).then(function () {
            $.util.log('Project deleted.');
            defered.resolve(credentials);
        }).catch(function (error) {
            if (!isIdempotent) {
                defered.reject(error);
            } else {
                defered.resolve(credentials);
            }
        });
    } else {
        $.util.log('Skipping project deletion for production: ' + projectName);
        defered.resolve(credentials);
    }
    return defered.promise;
};

var createProject = function(projectName){
    /*jshint camelcase:false */
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        var token = credentials.access_token;
        $.util.log('Creating project ' + projectName);
        $28.createProject(projectName, token).then(function (response) {
            $.util.log('Project  ' + projectName + ' created.');
            /*jshint camelcase:false */
            credentials.project_tokens['project_' + projectName] = response.body.projectToken;
            defered.resolve(credentials);
        }).catch(function (error) {
            $.util.log('Project creation failed: ' + error);
            defered.reject(error);
        });
    } else {
        $.util.log('Skipping project creation on production: ' + projectName);
        defered.resolve(credentials);
    }
    return defered.promise;
};

var upload = function(projectName){
    /*jshint camelcase:false */
    var projectToken = credentials.project_tokens['project_' + projectName];
    if(!projectToken) {
        throw new Error('project not found ' + projectName);
    }
    var projectPath = Config.paths.queries;
    var overwrite = Options.OVERWRITE_ALWAYS;
    var deleteOrphaned = true;
    var simulate = false;
    $.util.log('Uploading queries.');
    return $28.upload(projectName, projectToken, projectPath, overwrite, deleteOrphaned, simulate, []).then(function(){
        $.util.log('Queries uploaded.');
        return credentials;
    });
};

var download = function(projectName){
    /*jshint camelcase:false */
    var projectToken = credentials.project_tokens['project_' + projectName];
    if(!projectToken) {
        throw new Error('project not found ' + projectName);
    }
    var projectPath = Config.paths.queries;
    var overwrite = Options.OVERWRITE_ALWAYS;
    var deleteOrphaned = true;
    var simulate = false;
    $.util.log('Downloading queries.');
    return $28.download(projectName, projectToken, projectPath, overwrite, deleteOrphaned, simulate, []).then(function(){
        $.util.log('Queries downloaded.');
        return credentials;
    });
};

var runQueries = function(projectName, queriesToRun) {
    var sequenceOfQueries = [];
    queriesToRun.forEach(function(queries){
        queries = expand(queries);
        queries.forEach(function(query) {
            var queryPath = query.substring(Config.paths.queries.length + 1);
            sequenceOfQueries.push(queryPath);
        });
    });

    if (sequenceOfQueries.length === 0){
        $.util.log('At least 1 query to init and for the API tests need to be provided.'.red);
        throw new Error('No queries to run for: ' + JSON.stringify(queriesToRun));
    }

    var Queries = $28.api.Queries(projectName);
    /*jshint camelcase:false */
    var errors = [];
    var projectToken = credentials.project_tokens['project_' + projectName];
    return sequenceOfQueries.reduce(function(previousPromise, nextQuery){
        return previousPromise.then(function(){
            return Queries.executeQuery({
                accept: 'application/28.io+json',
                queryPath: nextQuery,
                format: '',
                token: projectToken
            }).then(function (data) {
                $.util.log(('✓ '.green) + nextQuery + ' returned with status code: ' + data.response.statusCode);
                return credentials;
            }).catch(function (error) {
                var requestUri = error.response.request.uri;
                var isTestQuery = (requestUri.pathname.lastIndexOf('/v1/_queries/public/test', 0) === 0);
                var href = isTestQuery ? requestUri.host + requestUri.pathname.substring('/v1/_queries/public'.length) : requestUri.host + requestUri.pathname;
                $.util.log(('✗ '.red) + href + ' returned with status code: ' + $.util.colors.red(error.response.statusCode));
                error = isTestQuery ? summarizeTestError(error) : error;
                errors.push(error);
                return credentials;
            });
        });
    }, /* init: */ Q.resolve()).then(function(){
        if(errors.length > 0){
            $.util.log(errors.length + ' queries failed');
            throw errors[0];
        }
    });
};

var createDatasource = function(projectName, datasource){
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        $.util.log('Creating datasource ' + datasource.name);
        var difault = datasource.default ? datasource.default : false;
        /*jshint camelcase:false */
        var projectToken = credentials.project_tokens['project_' + projectName];
        $28.createDatasource(projectName, datasource.category, datasource.name, projectToken, difault, JSON.stringify(datasource.credentials))
        .then(function(){
            $.util.log(datasource.name + ' created');
            defered.resolve(credentials);
        })
        .catch(function (error) {
            $.util.log('datasource creation failed: ' + datasource.name);
            defered.reject(error);
        });
    } else {
        $.util.log('Skipping data source creation on production: ' + datasource.name);
        defered.resolve(credentials);
    }
    return defered.promise;
};

gulp.task('28:login', function(){
    return login(Config.credentials['28'].email, Config.credentials['28'].password).catch(throwError);
});

gulp.task('28:create-project', function(){
    return createProject(Config.projectName, true).catch(throwError);
});

gulp.task('28:remove-project', function(){
    return removeProject(Config.projectName, true).catch(throwError);
});

gulp.task('28:upload', function(){
    return upload(Config.projectName).catch(throwError);
});

gulp.task('28:download', function(){
    return download(Config.projectName).catch(throwError);
});

gulp.task('28:setup-datasource', function(){
    var promises = [];
    Config.credentials['28'].datasources.forEach(function(datasource){
        promises.push(createDatasource(Config.projectName, datasource).catch(throwError));
    });
    return Q.all(promises);
});

gulp.task('28:init', function(){
    return runQueries(Config.projectName, Config.paths.initQueries).catch(throwError);
});

gulp.task('28:test', function(){
    return runQueries(Config.projectName, Config.paths.apiTestQueries).catch(throwError);
});
<|endoftext|>


<commit_before>"use strict";

function escapeTeamcityString(message) {
	if (!message) {
		return "";
	}

	return message.replace(/\|/g, "||")
		.replace(/\'/g, "|\'")
		.replace(/\n/g, "|n")
		.replace(/\r/g, "|r")
		.replace(/\u0085/g, "|x")
		.replace(/\u2028/g, "|l")
		.replace(/\u2029/g, "|p")
		.replace(/\[/g, "|[")
		.replace(/\]/g, "|]");
}

module.exports = {
	reporter: function (results) {
		var output = [];

		// Categorise each error by filename
		var errors = results.reduce(function (previous, current) {
			var error = current.error;

			if (!previous[current.file]) {
				previous[current.file] = [];
			}

			previous[current.file].push({
				name: escapeTeamcityString(current.file + ": line " + error.line + ", col " + error.character + ", " + error.reason),
				message: escapeTeamcityString(error.code + ": " + error.reason),
				detailed: escapeTeamcityString(error.evidence)
			});

			return previous;
		}, {});

		// Collate teamcity output into test suites (by filename)
		Object.keys(errors).forEach(function (key) {
			var suite = "JSHint: " + key;
			output.push("##teamcity[testSuiteStarted name='" + suite + "']");
			errors[key].forEach(function (test) {
				output.push("##teamcity[testStarted name='" + test.name + "']");
				output.push("##teamcity[testFailed name='" + test.name + "' message='" + test.message + "' detailed='" + test.detailed + "']");
			});
			output.push("##teamcity[testSuiteFinished name='" + suite + "']");
		});

		// If there were no output, tell TeamCity that tests ran successfully
		if (output.length === 0) {
			output.push("##teamcity[testStarted name='JSHint']");
			output.push("##teamcity[testFinished name='JSHint']");
		}

		// Print to process.stdout
		console.log(output.join("\n"));
	}
};
<commit_msg>Add testFinished message.<commit_after>"use strict";

function escapeTeamcityString(message) {
	if (!message) {
		return "";
	}

	return message.replace(/\|/g, "||")
		.replace(/\'/g, "|\'")
		.replace(/\n/g, "|n")
		.replace(/\r/g, "|r")
		.replace(/\u0085/g, "|x")
		.replace(/\u2028/g, "|l")
		.replace(/\u2029/g, "|p")
		.replace(/\[/g, "|[")
		.replace(/\]/g, "|]");
}

module.exports = {
	reporter: function (results) {
		var output = [];

		// Categorise each error by filename
		var errors = results.reduce(function (previous, current) {
			var error = current.error;

			if (!previous[current.file]) {
				previous[current.file] = [];
			}

			previous[current.file].push({
				name: escapeTeamcityString(current.file + ": line " + error.line + ", col " + error.character + ", " + error.reason),
				message: escapeTeamcityString(error.code + ": " + error.reason),
				detailed: escapeTeamcityString(error.evidence)
			});

			return previous;
		}, {});

		// Collate teamcity output into test suites (by filename)
		Object.keys(errors).forEach(function (key) {
			var suite = "JSHint: " + key;
			output.push("##teamcity[testSuiteStarted name='" + suite + "']");
			errors[key].forEach(function (test) {
				output.push("##teamcity[testStarted name='" + test.name + "']");
				output.push("##teamcity[testFailed name='" + test.name + "' message='" + test.message + "' detailed='" + test.detailed + "']");
				output.push("##teamcity[testFinished name='" + test.name + "']");
			});
			output.push("##teamcity[testSuiteFinished name='" + suite + "']");
		});

		// If there were no output, tell TeamCity that tests ran successfully
		if (output.length === 0) {
			output.push("##teamcity[testStarted name='JSHint']");
			output.push("##teamcity[testFinished name='JSHint']");
		}

		// Print to process.stdout
		console.log(output.join("\n"));
	}
};
<|endoftext|>


<commit_before>var fs = require("fs");

var templates = {};

function make_safe(text) {
    return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/\'/g, "'").replace(/\"/g, """);
}

exports.render = function(template_path, content, escape_html) {
    var output, prop, c;

    if(!templates[template_path]) {
        templates[template_path] = fs.readFileSync(template_path, "utf8");
    }

    output = templates[template_path];

    for(prop in content) {
        c = "" + content[prop];

        if(escape_html) {
            c = make_safe(c);
        }
        output = output.replace(new RegExp("\\{\\{\\s*" + prop + "\\s*\\}\\}", "ig"), c);
    }

    return output;
};
<commit_msg>Extend template to use object hierarchies<commit_after>var fs = require("fs");

var templates = {};

function make_safe(text) {
    return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/\'/g, "'").replace(/\"/g, """);
}

function flatten_object(object) {
    var output = {},
        prop,
        subobject,
        subprop;

    for(prop in object) {
        if(typeof(object[prop]) === "string" || typeof(object[prop]) === "number") {
            output[prop] = object[prop];
        } else if(typeof(object[prop]) === "object") {
            subobject = flatten_object(object[prop]);

            for(subprop in subobject) {
                output[prop + "." + subprop] = subobject[subprop];
            }
        }
    }

    return output;
}

exports.render = function(template_path, content, escape_html) {
    var output, prop, c;

    if(!templates[template_path]) {
        templates[template_path] = fs.readFileSync(template_path, "utf8");
    }

    output = templates[template_path];

    content = flatten_object(content);

    for(prop in content) {
        c = "" + content[prop];

        if(escape_html) {
            c = make_safe(c);
        }
        output = output.replace(new RegExp("\\{\\{\\s*" + prop + "\\s*\\}\\}", "ig"), c);
    }

    return output;
};
<|endoftext|>


<commit_before>/*
 * Observing wrapper v0.3
 * https://github.com/ytiurin/observingwrapperjs
 *
 * Copyright (c) 2015 Yevhen Tiurin
 * Licensed under MIT (https://github.com/ytiurin/observingwrapperjs/blob/master/LICENSE)
 *
 * February 25, 2015
 */

!function(window){

  !function checkECMAScript51Features()
  {
    ['defineProperty','getPrototypeOf','getOwnPropertyNames'].forEach(
      function(method) {
        if (Object[method] === undefined)
          throw 'Object.'+method+' method does not exist. ObservingWrapper will not work.';
      });
  }()

  function getDeepPropertyNames(obj)
  {
    var proto,names,protoNames,reduceNames,i,n;

    names=Object.getOwnPropertyNames(obj);
    for(i=0,n=names.length;i<n;i++)
      if(names[i].indexOf('__')===0&&names[i].lastIndexOf('__')===names[i].length-2){
        names.splice(i,1);
        i--;
        n--;
      }

    (proto=Object.getPrototypeOf(obj)) && (names=names.concat(
      getDeepPropertyNames(proto)));

    return names;
  }

  function ObservingWrapper(sourceObject,initHandler)
  {
    this.sourceObject=sourceObject||undefined;
    this.observingKeys={};
    this.changeHandlers=[];
    this.specificHandlers={};

    Object.defineProperty(this.observingKeys,'__observingWrapper',{value:this});
    this.defineObservableProperties();
  }

  ObservingWrapper.prototype.addChangeHandler=function(){
    var key,userPropertyName,userChangeHandler;

    if(['string','number'].indexOf(typeof arguments[0])>-1 && typeof arguments
      [1]==='function')
    {
      userPropertyName=arguments[0];
      userChangeHandler=arguments[1];
    }
    else
      userChangeHandler=arguments[0];

    if(userPropertyName!==undefined){
      this.specificHandlers[userPropertyName]||(this.specificHandlers[
        userPropertyName]=[]);
      if(this.specificHandlers[userPropertyName].indexOf(userChangeHandler)===-1)
      {
        this.specificHandlers[userPropertyName].push(userChangeHandler);
        typeof this.sourceObject[userPropertyName]!=='function'&&
          userChangeHandler.call(this.sourceObject,this.sourceObject[
          userPropertyName]);
      }
    }
    else{
      this.changeHandlers.indexOf(userChangeHandler)===-1&&this.changeHandlers
        .push(userChangeHandler);
      for(key in this.observingKeys)
        typeof this.sourceObject[key]!=='function'&&userChangeHandler.call(this.
          sourceObject,key,this.sourceObject[key]);
    }
  }

  ObservingWrapper.prototype.defineObservableProperties = function() {
    for(var propertyNames=getDeepPropertyNames(this.sourceObject,this.observingKeys),
      i=0,n=propertyNames.length; i<n; i++)
      this.defineObservableProperty(propertyNames[i]);
  }

  ObservingWrapper.prototype.defineObservableProperty = function(propertyName) {
    var ow=this,isEnum=typeof this.sourceObject[propertyName]!=='function';

    function get() {
      return ow.getPropertyValue(propertyName);
    }

    function set(userValue) {
      ow.setPropertyValue(propertyName, userValue);
    }

    Object.defineProperty(this.observingKeys, propertyName, {enumerable:isEnum,
      configurable:true, get:get, set:set});
  }

  ObservingWrapper.prototype.getPropertyValue = function(propertyName) {
    var ow=this;
    return typeof this.sourceObject[propertyName] !== 'function' ? this.
      sourceObject[propertyName] : function() {
        var
        length=ow.sourceObject.length,
        result=ow.sourceObject[propertyName].apply(ow.sourceObject,arguments);

        if(length&&length!==ow.sourceObject.length) {
          ow.undefineObservableProperties();
          ow.defineObservableProperties();
        }

        ow.notifyObservers(propertyName,arguments,result);

        return result;
      };
  }

  ObservingWrapper.prototype.notifyObservers = function() {
    var specificHandlers,i;

    function reduceArgs(args){
      return Array.prototype.slice.call(args,1);
    }

    if(specificHandlers=this.specificHandlers[arguments[0]])
      for(i=0,n=specificHandlers.length;i<n;i++)
        specificHandlers[i].apply(this.sourceObject,reduceArgs(arguments));

    for(i=0,n=this.changeHandlers.length;i<n;i++)
      this.changeHandlers[i].apply(this.sourceObject,arguments);
  }

  ObservingWrapper.prototype.removeChangeHandler = function() {
    var rmInd,key,userPropertyName,userChangeHandler;

    if(['string','number'].indexOf(typeof arguments[0])>-1 && typeof arguments
      [1]==='function')
    {
      userPropertyName=arguments[0];
      userChangeHandler=arguments[1];
    }
    else
      userChangeHandler=arguments[0];

    if(userPropertyName!==undefined){
      this.specificHandlers[userPropertyName]&&(rmInd=this.specificHandlers[
        userPropertyName].indexOf(userChangeHandler))>-1&&this.specificHandlers[
        userPropertyName].splice(rmInd,1);
    }
    else{
      (rmInd=this.changeHandlers.indexOf(userChangeHandler))>-1&&this.
        changeHandlers.splice(rmInd,1);

      for(key in this.specificHandlers)
        (rmInd=this.specificHandlers[key].indexOf(userChangeHandler))>-1&&this.
          specificHandlers[key].splice(rmInd,1);
    }
  }

  ObservingWrapper.prototype.setPropertyValue = function(propertyName,propertyValue) {
    if (this.sourceObject[propertyName] !== propertyValue) {
      this.sourceObject[propertyName] = propertyValue;
      this.notifyObservers(propertyName, propertyValue);
    }
  }

  ObservingWrapper.prototype.undefineObservableProperties = function() {
    for(var propertyNames=getDeepPropertyNames(this.observingKeys),i=0,n=
      propertyNames.length; i<n; i++)
      delete this.observingKeys[i];
  }

  function observingWrapper(userObject, userChangeHandler)
  {
    var owInstance=arguments[0]&&arguments[0].__observingWrapper;

    if(!owInstance)
      owInstance=new ObservingWrapper(arguments[0]||{});

    if(arguments[1]!==undefined)
      owInstance.addChangeHandler(arguments[1],arguments[2]);

    return owInstance.observingKeys;
  }

  observingWrapper.__constructor = ObservingWrapper;

  observingWrapper.remove = function(userObservingKeys,userChangeHandler) {
    var ow=userObservingKeys.__observingWrapper;

    if (userChangeHandler)
      ow.removeChangeHandler(userChangeHandler);
    else
      ow.changeHandlers=[];
  };

  window.define && define(function() {return observingWrapper});
  window.define === undefined && (window.observingWrapper = observingWrapper);

}(window)
<commit_msg>Add strict mode<commit_after>/*
 * Observing wrapper v0.3
 * https://github.com/ytiurin/observingwrapperjs
 *
 * Copyright (c) 2015 Yevhen Tiurin
 * Licensed under MIT (https://github.com/ytiurin/observingwrapperjs/blob/master/LICENSE)
 *
 * February 25, 2015
 */

!function(window){

  'use strict';

  !function checkECMAScript51Features()
  {
    ['defineProperty','getPrototypeOf','getOwnPropertyNames'].forEach(
      function(method) {
        if (Object[method] === undefined)
          throw 'Object.'+method+' method does not exist. ObservingWrapper will not work.';
      });
  }()

  function getDeepPropertyNames(obj)
  {
    var proto,names,protoNames,reduceNames,i,n;

    names=Object.getOwnPropertyNames(obj);
    for(i=0,n=names.length;i<n;i++)
      if(names[i].indexOf('__')===0&&names[i].lastIndexOf('__')===names[i].length-2){
        names.splice(i,1);
        i--;
        n--;
      }

    (proto=Object.getPrototypeOf(obj)) && (names=names.concat(
      getDeepPropertyNames(proto)));

    return names;
  }

  function ObservingWrapper(sourceObject,initHandler)
  {
    this.sourceObject=sourceObject||undefined;
    this.observingKeys={};
    this.changeHandlers=[];
    this.specificHandlers={};

    Object.defineProperty(this.observingKeys,'__observingWrapper',{value:this});
    this.defineObservableProperties();
  }

  ObservingWrapper.prototype.addChangeHandler=function(){
    var key,userPropertyName,userChangeHandler;

    if(['string','number'].indexOf(typeof arguments[0])>-1 && typeof arguments
      [1]==='function')
    {
      userPropertyName=arguments[0];
      userChangeHandler=arguments[1];
    }
    else
      userChangeHandler=arguments[0];

    if(userPropertyName!==undefined){
      this.specificHandlers[userPropertyName]||(this.specificHandlers[
        userPropertyName]=[]);
      if(this.specificHandlers[userPropertyName].indexOf(userChangeHandler)===-1)
      {
        this.specificHandlers[userPropertyName].push(userChangeHandler);
        typeof this.sourceObject[userPropertyName]!=='function'&&
          userChangeHandler.call(this.sourceObject,this.sourceObject[
          userPropertyName]);
      }
    }
    else{
      this.changeHandlers.indexOf(userChangeHandler)===-1&&this.changeHandlers
        .push(userChangeHandler);
      for(key in this.observingKeys)
        typeof this.sourceObject[key]!=='function'&&userChangeHandler.call(this.
          sourceObject,key,this.sourceObject[key]);
    }
  }

  ObservingWrapper.prototype.defineObservableProperties = function() {
    for(var propertyNames=getDeepPropertyNames(this.sourceObject,this.observingKeys),
      i=0,n=propertyNames.length; i<n; i++)
      this.defineObservableProperty(propertyNames[i]);
  }

  ObservingWrapper.prototype.defineObservableProperty = function(propertyName) {
    var ow=this,isEnum=typeof this.sourceObject[propertyName]!=='function';

    function get() {
      return ow.getPropertyValue(propertyName);
    }

    function set(userValue) {
      ow.setPropertyValue(propertyName, userValue);
    }

    Object.defineProperty(this.observingKeys, propertyName, {enumerable:isEnum,
      configurable:true, get:get, set:set});
  }

  ObservingWrapper.prototype.getPropertyValue = function(propertyName) {
    var ow=this;
    return typeof this.sourceObject[propertyName] !== 'function' ? this.
      sourceObject[propertyName] : function() {
        var
        length=ow.sourceObject.length,
        result=ow.sourceObject[propertyName].apply(ow.sourceObject,arguments);

        if(length&&length!==ow.sourceObject.length) {
          ow.undefineObservableProperties();
          ow.defineObservableProperties();
        }

        ow.notifyObservers(propertyName,arguments,result);

        return result;
      };
  }

  ObservingWrapper.prototype.notifyObservers = function() {
    var specificHandlers,i,n;

    function reduceArgs(args){
      return Array.prototype.slice.call(args,1);
    }

    if(specificHandlers=this.specificHandlers[arguments[0]])
      for(i=0,n=specificHandlers.length;i<n;i++)
        specificHandlers[i].apply(this.sourceObject,reduceArgs(arguments));

    for(i=0,n=this.changeHandlers.length;i<n;i++)
      this.changeHandlers[i].apply(this.sourceObject,arguments);
  }

  ObservingWrapper.prototype.removeChangeHandler = function() {
    var rmInd,key,userPropertyName,userChangeHandler;

    if(['string','number'].indexOf(typeof arguments[0])>-1 && typeof arguments
      [1]==='function')
    {
      userPropertyName=arguments[0];
      userChangeHandler=arguments[1];
    }
    else
      userChangeHandler=arguments[0];

    if(userPropertyName!==undefined){
      this.specificHandlers[userPropertyName]&&(rmInd=this.specificHandlers[
        userPropertyName].indexOf(userChangeHandler))>-1&&this.specificHandlers[
        userPropertyName].splice(rmInd,1);
    }
    else{
      (rmInd=this.changeHandlers.indexOf(userChangeHandler))>-1&&this.
        changeHandlers.splice(rmInd,1);

      for(key in this.specificHandlers)
        (rmInd=this.specificHandlers[key].indexOf(userChangeHandler))>-1&&this.
          specificHandlers[key].splice(rmInd,1);
    }
  }

  ObservingWrapper.prototype.setPropertyValue = function(propertyName,propertyValue) {
    if (this.sourceObject[propertyName] !== propertyValue) {
      this.sourceObject[propertyName] = propertyValue;
      this.notifyObservers(propertyName, propertyValue);
    }
  }

  ObservingWrapper.prototype.undefineObservableProperties = function() {
    for(var propertyNames=getDeepPropertyNames(this.observingKeys),i=0,n=
      propertyNames.length; i<n; i++)
      delete this.observingKeys[i];
  }

  function observingWrapper(userObject, userChangeHandler)
  {
    var owInstance=arguments[0]&&arguments[0].__observingWrapper;

    if(!owInstance)
      owInstance=new ObservingWrapper(arguments[0]||{});

    if(arguments[1]!==undefined)
      owInstance.addChangeHandler(arguments[1],arguments[2]);

    return owInstance.observingKeys;
  }

  observingWrapper.__constructor = ObservingWrapper;

  observingWrapper.remove = function(userObservingKeys,userChangeHandler) {
    var ow=userObservingKeys.__observingWrapper;

    if (userChangeHandler)
      ow.removeChangeHandler(userChangeHandler);
    else
      ow.changeHandlers=[];
  };

  window.define && define(function() {return observingWrapper});
  window.define === undefined && (window.observingWrapper = observingWrapper);

}(window)
<|endoftext|>


<commit_before>// jQuery.Class
// Mostly inspired by $.Class component of javascriptMVC (http://javascriptmvc.com/docs.html#!jQuery.Class)

(function( $ ) {

    /**
     * @param {String} className
     * @param {Object} properties
     */
    $.Class = function(className, properties)
    {
        var props = new Properties(properties);
        props.separate();

        var generator = new ClassGenerator(className);
        generator.setProperties(props);
        generator.create();

        if ($.Interface === undefined) {
            $.Interface = dummyInterface;
        }
	};

    /**
     * static
     *
     * @param {String} namespace the object to look for
     * @return {Object} The object.
     */
    $.Class.getObject = function(namespace)
    {
        if (namespace == '' || namespace == undefined) {
            return window;
        }

        var namespaceParts = namespace.split('.');

        var root = window;

        for (var i in namespaceParts) {
            if (typeof root[namespaceParts[i]] == 'undefined') {
                root[namespaceParts[i]] = {};
            }

            root = root[namespaceParts[i]];
        }

        return root;
    };

    // define regex outside of ClassGenerator to define them once only
    var privatePropertyRegEx = /\b(this._)+\w+\b/g;
        isSuperCalledInFunctionRegEx = /xyz/.test(function() {
			xyz;
		}) ? /\b_super\b/ : /.*/,
        isPrivateCalledInFunctionRegEx = /xyz/.test(function() {
			xyz;
        }) ? privatePropertyRegEx : /.*/,

        /**
         * @return {Boolean}
         */
        interfaceExists = function()
        {
            if ($.Interface === undefined || $.Interface === dummyInterface) {
                return false;
            }
            return true;
        };

    /**
     * @constructor
     * @param {String} className
     */
    function ClassGenerator(className)
    {
        if (className == '' || !className) {
            throw new Error('Invalid class name.');
        }
        this.props = null;
        this.name = className;
    };

    ClassGenerator.prototype =
    {
        /**
         * @param {Object} properties
         */
        setProperties: function(properties)
        {
            this.props = properties;
        },

        /**
         * overwrites an object with methods
         *
         * @param {Object} newProps
         * @param {Object} oldProps (where the old properties might be)
         * @param {Object} addTo (what we are adding to)
         */
        _inheritProps: function(newProps, oldProps, addTo)
        {
            addTo = addTo || newProps;
            for (var name in newProps) {
                // Check if we're overwriting an existing function
                if ($.isFunction(newProps[name])
                    && $.isFunction(oldProps[name])
                    && isSuperCalledInFunctionRegEx.test(newProps[name]))
                {
                    addTo[name] = this._getOverriddenMethodWithSuper(newProps[name], oldProps[name]);
                }
                else {
                    addTo[name] = newProps[name];
                }
            }
        },

        /**
         * @param {Function} newMethod
         * @param {Function} oldMethod
         * @return {Function}
         */
        _getOverriddenMethodWithSuper: function(newMethod, oldMethod)
        {
            return function() {
                var tmp = this._super,
                    ret;

                // Add a new ._super() method that is the same method
                // but on the super-class
                this._super = oldMethod;

                // The method only need to be bound temporarily, so we
                // remove it when we're done executing
                ret = newMethod.apply(this, arguments);
                delete this._super;
                return ret;
            }
        },

        /**
         * register class
         * @param {Function} class
         */
        _registerClassInWindowNamespace: function (Class)
        {
            var parts = this.name.split(/\./),
                shortName = parts.pop(),
                current = $.Class.getObject(parts.join('.')),
                namespace = current;

            current[shortName] = Class;
        },

        /**
         * @param {Object} instance
         * @param {Array} arguments
         * @return {class} instance of the class
         */
        newInstance: function(instance, arguments)
        {
            if (interfaceExists()) {
                this.ensureInterfaces(instance);
            }

            // call init if there is an init, if setup returned args, use those as the arguments
            if ( instance.init ) {
                instance.init.apply(instance, arguments);
            }

            return instance;
        },

        /**
         * @param {Object} object
         */
        ensureInterfaces: function(object)
        {
            if (!object['___interfaces']) {
                return;
            }

            $.Interface.ensureImplementation(object, object['___interfaces']);
        },

        _inheritInterfaces: function()
        {
            if (this.props.parentPrototype['___interfaces'] && this.props.publics['___interfaces']) {
                this.props.publics['___interfaces'] =
                    this.props.parentPrototype['___interfaces'].concat(this.props.publics['___interfaces']);
            }
        },

        _inheritStatics: function()
        {
            if (!this.props.parentClass) {
                return;
            }

            for (name in this.props.parentClass) {
                this.props.statics[name] = this.props.parentClass[name];
            }
        },

        /**
         * @param {Function} func
         */
        _inheritPrototype: function(func)
        {
            if (!this.props.parentClass) {
                return;
            }

            function parent() {};

            parent.prototype = this.props.parentPrototype;
            func.prototype = new parent();

        },

        create: function()
        {
            var generator = this;

             // The dummy class constructor
            function Class() {
                return generator.newInstance(this, arguments);
            }

            this._inheritPrototype(Class);
            this._inheritStatics();
            this._inheritInterfaces();
            $.extend(Class.prototype, this.props.publics);
            // Copy the properties over onto the new prototype
            this._inheritProps(this.props.publics, this.props.parentPrototype, Class['prototype']);
            // copy new static props on class
            this._inheritProps(this.props.statics, this.props.parentClass || function() {}, Class);
            this._registerClassInWindowNamespace(Class);

            /* @Prototype*/
            return Class;
        }
    };

    /**
     * Helper class for separating properties
     * @constructor
     * @param {Object} properties
     */
    function Properties(properties)
    {
        if (!properties) {
            throw new Error('Properties are required');
        }

        this.properties = properties;
        this.secrets = {};
        this.publics = {};
        this.statics = {};
        this.parentClass = null;
        this.parentPrototype = {};
        this.implement = [];
    };

    Properties.prototype =
    {
        isPrivatePropertyRegEx: /^_\w/,

        separate: function()
        {
            this._separateInheritance();
            this._separateInterfaces();

            var name;

            for (name in this.properties) {
                if (name[0] == '$') {
                    this.statics[name.substr(1,name.length)] = this.properties[name];
                    continue;
                }
                if (this.isPrivatePropertyRegEx.test(name)) {
                    this.secrets[name] = this.properties[name];
                    continue;
                }

                this.publics[name] = this.properties[name];
            }

            this._attachPrivateMethods();
        },

        _separateInheritance: function()
        {
            if (this.properties.extend === undefined) {
                return;
            }

            if (!$.isFunction(this.properties.extend)) {
                return;
            }

            this.parentClass = this.properties.extend;
            this.parentPrototype = this.parentClass['prototype'];
            delete this.properties.extend;
        },

        _separateInterfaces: function()
        {
            if (this.properties.implement === undefined) {
                return;
            }

            if (interfaceExists()) {
                this.implement = $.isArray(this.properties.implement) ? this.properties.implement : [this.properties.implement];
                this.publics['___interfaces'] = this.implement;
            }

            delete this.properties.implement;
        },

        _getMethodWithPrivateMethodsAttached: function(method, privatePropName, privateProp)
        {
            return function() {
                this[privatePropName] = privateProp;
                var value = method.apply(this, arguments);
                delete this[privatePropName];
                return value;
            };

        },

        _attachPrivateMethods: function()
        {
            var name;
            for (name in this.publics) {
                if (!$.isFunction(this.publics[name])) {
                    continue;
                }
                var privateFunctionsToAttach = this.publics[name].toString().match(privatePropertyRegEx);

                for (var i in privateFunctionsToAttach) {
                    var privatePropName = this._getPrivateMethodName(privateFunctionsToAttach[i]);
                    if (this.secrets[privatePropName] === undefined) {
                        continue;
                    }

                    this.publics[name] = this._getMethodWithPrivateMethodsAttached(
                        this.publics[name], privatePropName, this.secrets[privatePropName]
                    );
                }
            }
        },

        _getPrivateMethodName: function(name)
        {
            return name.replace(/(this.)/, '').replace(/\(/, '');
        },
    };

    function dummyInterface() {};

    dummyInterface.ensure = function() {};
    dummyInterface.ensureImplementation = function() {};

})(jQuery);
<commit_msg>changed private property detection<commit_after>// jQuery.Class
// Mostly inspired by $.Class component of javascriptMVC (http://javascriptmvc.com/docs.html#!jQuery.Class)

(function( $ ) {
    /**
     * @param {String} className
     * @param {Object} properties
     */
    $.Class = function(className, properties)
    {
        var props = new Properties(properties);
        props.separate();

        var generator = new ClassGenerator(className);
        generator.setProperties(props);
        generator.create();

        if ($.Interface === undefined) {
            $.Interface = dummyInterface;
        }
	};

    /**
     * static
     *
     * @param {String} namespace the object to look for
     * @return {Object} The object.
     */
    $.Class.getObject = function(namespace)
    {
        if (namespace == '' || namespace == undefined) {
            return window;
        }

        var namespaceParts = namespace.split('.'),
            root = window;

        for (var i in namespaceParts) {
            if (typeof root[namespaceParts[i]] == 'undefined') {
                root[namespaceParts[i]] = {};
            }

            root = root[namespaceParts[i]];
        }

        return root;
    };

    // define regex outside of ClassGenerator to define them once only
    var privatePropertyRegEx = /\b(this._)+\w+\b/g,
        privateSetterMethodRegEx = /\b(this.___set)+\w+\b/g,
        isSuperCalledInFunctionRegEx = /xyz/.test(function() {
			xyz;
		}) ? /\b_super\b/ : /.*/,
        isPrivateCalledInFunctionRegEx = /xyz/.test(function() {
			xyz;
        }) ? privatePropertyRegEx : /.*/,

        /**
         * @return {Boolean}
         */
        interfaceExists = function()
        {
            if ($.Interface === undefined || $.Interface === dummyInterface) {
                return false;
            }
            return true;
        };

    /**
     * @constructor
     * @param {String} className
     */
    function ClassGenerator(className)
    {
        if (className == '' || !className) {
            throw new Error('Invalid class name.');
        }
        this.props = null;
        this.name = className;
    };

    ClassGenerator.prototype =
    {
        /**
         * @param {Object} properties
         */
        setProperties: function(properties)
        {
            this.props = properties;
        },

        /**
         * overwrites an object with methods
         *
         * @param {Object} newProps
         * @param {Object} oldProps (where the old properties might be)
         * @param {Object} addTo (what we are adding to)
         */
        _inheritProps: function(newProps, oldProps, addTo)
        {
            addTo = addTo || newProps;
            for (var name in newProps) {
                if ($.isFunction(newProps[name])
                    && $.isFunction(oldProps[name])
                    && isSuperCalledInFunctionRegEx.test(newProps[name]))
                {
                    addTo[name] = this._getOverriddenMethodWithSuper(newProps[name], oldProps[name]);
                }
                else {
                    addTo[name] = newProps[name];
                }
            }
        },

        /**
         * @param {Function} newMethod
         * @param {Function} oldMethod
         * @return {Function}
         */
        _getOverriddenMethodWithSuper: function(newMethod, oldMethod)
        {
            return function() {
                var tmp = this._super,
                    ret;

                // Add a new ._super() method that is the same method
                // but on the super-class
                this._super = oldMethod;

                // The method only need to be bound temporarily, so we
                // remove it when we're done executing
                ret = newMethod.apply(this, arguments);
                delete this._super;
                return ret;
            }
        },

        /**
         * register class
         * @param {Function} class
         */
        _registerClassInWindowNamespace: function (Class)
        {
            var parts = this.name.split(/\./),
                shortName = parts.pop(),
                current = $.Class.getObject(parts.join('.')),
                namespace = current;

            current[shortName] = Class;
        },

        /**
         * @param {Object} instance
         * @param {Array} arguments
         * @return {class} instance of the class
         */
        newInstance: function(instance, arguments)
        {
            if (interfaceExists()) {
                this.ensureInterfaces(instance);
            }

            // call init if there is an init, if setup returned args, use those as the arguments
            if ( instance.init ) {
                instance.init.apply(instance, arguments);
            }

            return instance;
        },

        /**
         * @param {Object} object
         */
        ensureInterfaces: function(object)
        {
            if (!object['___interfaces']) {
                return;
            }

            $.Interface.ensureImplementation(object, object['___interfaces']);
        },

        _inheritInterfaces: function()
        {
            if (this.props.parentPrototype['___interfaces'] && this.props.publics['___interfaces']) {
                this.props.publics['___interfaces'] =
                    this.props.parentPrototype['___interfaces'].concat(this.props.publics['___interfaces']);
            }
        },

        _inheritStatics: function()
        {
            if (!this.props.parentClass) {
                return;
            }

            for (name in this.props.parentClass) {
                this.props.statics[name] = this.props.parentClass[name];
            }
        },

        /**
         * @param {Function} func
         */
        _inheritPrototype: function(func)
        {
            if (!this.props.parentClass) {
                return;
            }

            function parent() {};

            parent.prototype = this.props.parentPrototype;
            func.prototype = new parent();

        },

        create: function()
        {
            var generator = this;

             // The dummy class constructor
            function Class() {
                return generator.newInstance(this, arguments);
            }

            this._inheritPrototype(Class);
            this._inheritStatics();
            this._inheritInterfaces();
            $.extend(Class.prototype, this.props.publics);
            // Copy the properties over onto the new prototype
            this._inheritProps(this.props.publics, this.props.parentPrototype, Class['prototype']);
            // copy new static props on class
            this._inheritProps(this.props.statics, this.props.parentClass || function() {}, Class);
            this._registerClassInWindowNamespace(Class);

            /* @Prototype*/
            return Class;
        }
    };

    /**
     * Helper class for separating properties
     * @constructor
     * @param {Object} properties
     */
    function Properties(properties)
    {
        if (!properties) {
            throw new Error('Properties are required');
        }

        this.properties = properties;
        this.secrets = {};
        this.publics = {};
        this.statics = {};
        this.parentClass = null;
        this.parentPrototype = {};
        this.implement = [];

        var me = this;
        this.secrets.___set = function(name, value) {
            me.secrets[name] = value;
        }
    };

    Properties.prototype =
    {
        isPrivatePropertyRegEx: /^_\w/,

        separate: function()
        {
            this._separateInheritance();
            this._separateInterfaces();

            var name;

            for (name in this.properties) {
                if (name[0] == '$') {
                    this.statics[name.substr(1,name.length)] = this.properties[name];
                    continue;
                }
                if (this.isPrivatePropertyRegEx.test(name)) {
                    this.secrets[name] = this.properties[name];
                    continue;
                }

                this.publics[name] = this.properties[name];
            }

            this._attachPrivateMethods();
        },

        _separateInheritance: function()
        {
            if (this.properties.extend === undefined) {
                return;
            }

            if (!$.isFunction(this.properties.extend)) {
                return;
            }

            this.parentClass = this.properties.extend;
            this.parentPrototype = this.parentClass['prototype'];
            delete this.properties.extend;
        },

        _separateInterfaces: function()
        {
            if (this.properties.implement === undefined) {
                return;
            }

            if (interfaceExists()) {
                this.implement = $.isArray(this.properties.implement) ? this.properties.implement : [this.properties.implement];
                this.publics['___interfaces'] = this.implement;
            }

            delete this.properties.implement;
        },

        _getMethodWithPrivateMethodsAttached: function(method, privateProperties)
        {
            var me = this;
            return function() {
                for (var name in privateProperties) {
                    this[name] = privateProperties[name];
                }
                var value = method.apply(this, arguments);

                for (var name in privateProperties) {
                    delete this[name];
                }

                return value;
            };

        },

        _attachPrivateMethods: function()
        {
            var name;
            for (name in this.publics) {
                if (!$.isFunction(this.publics[name])) {
                    continue;
                }
                var methodString = this.publics[name].toString(),
                    privatePropertyNames = methodString.match(privatePropertyRegEx),
                    privateProperties = {},
                    attach = false;

                for (var i in privatePropertyNames) {
                    var propertyName = this._getPrivateMethodName(privatePropertyNames[i]);

                    if (this.secrets[propertyName] == undefined) {
                        continue;
                    }
                    attach = true;
                    privateProperties[propertyName] = this.secrets[propertyName];
                }

                if (!attach) {
                    continue;
                }

                this.publics[name] = this._getMethodWithPrivateMethodsAttached(this.publics[name], privateProperties);
            }
        },

        _getPrivateMethodName: function(name)
        {
            return name.replace(/(this.)/, '').replace(/\(/, '');
        },
    };

    function dummyInterface() {};

    dummyInterface.ensure = function() {};
    dummyInterface.ensureImplementation = function() {};

})(jQuery);
<|endoftext|>