<commit_before>var _ = require('lodash'),
    async = require('async'),
    sdk = require('postman-collection'),

    createAuthInterface = require('../authorizer/auth-interface'),
    AuthLoader = require('../authorizer/index').AuthLoader,
    ReplayController = require('./replay-controller'),

    DOT_AUTH = '.auth';

module.exports = [
    // Variable resolution
    function (context, run, done) {
        if (!context.item) { return done(new Error('Nothing to resolve variables for.')); }

        // @todo - resolve variables in a more graceful way
        // @todo - no need to sync vatiables when SDK starts supporting resolution from scope directly
        // @todo remove this hack of using empty variableList once it's fixed in sdk
        context.item = new sdk.Item(context.item.toObjectResolved({variables: new sdk.VariableList(null, [])}, [
            context.data,
            context.environment.syncVariablesTo({}),
            context.collectionVariables.syncVariablesTo({}),
            context.globals.syncVariablesTo({})
        ]));

        var item = context.item,
            auth = context.auth;

        // Re-parse the URL, because variables have been resolved now, and things might be moved around
        item.request.url = new (sdk.Url)(item.request.url.toString());

        // resolve variables in auth
        auth && (context.auth = new sdk.RequestAuth(auth.toObjectResolved(
            {variables: new sdk.VariableList(null, [])}, // @todo remove this hack once it's fixed in sdk
            [
                context.data,
                context.environment.syncVariablesTo({}),
                context.collectionVariables.syncVariablesTo({}),
                context.globals.syncVariablesTo({})
            ]
        )));

        done();
    },

    // Authorization
    function (context, run, done) {
        // validate all stuff. dont ask.
        if (!context.item) { return done(new Error('runtime: nothing to authorize.')); }

        // bail out if there is no auth
        if (!(context.auth && context.auth.type)) { return done(null); }

        // get auth handler
        var auth = context.auth,
            authType = auth.type,
            authHandler = AuthLoader.getHandler(authType),
            authPreHook,
            authInterface,
            authSignHook = function () {
                try {
                    authHandler.sign(authInterface, context.item.request, function (err) {
                        // handle all types of errors in one place, see catch block
                        if (err) { throw err; }

                        done();
                    });
                }
                catch (err) {
                    // handles synchronous and asynchronous errors in auth.sign
                    run.triggers.console(context.coords,
                        'warn',
                        'runtime~' + authType + '.auth: could not sign the request: ' + (err.message || err),
                        err
                    );

                    // swallow the error, we've warned the user
                    done();
                }
            };

        // bail out if there is no matching auth handler for the type
        if (!authHandler) {
            run.triggers.console(context.coords, 'warn', 'runtime: could not find a handler for auth: ' + auth.type);
            return done();
        }

        authInterface = createAuthInterface(auth);

        /**
         * We go through the `pre` request send validation for the auth. In this step one of the three things can happen
         *
         * If the Auth `pre` hook
         * 1. gives a go, we sign the request and proceed to send the request.
         * 2. gives a no go, we don't sign the request, but proceed to send the request.
         * 3. gives a no go, with a intermediate request,
         *      a. we suspend current request, send the intermediate request
         *      b. invoke Auth `init` hook with the response of the intermediate request
         *      c. invoke Auth `pre` hook, and repeat from 1
         */
        authPreHook = function () {
            authHandler.pre(authInterface, function (err, success, request) {
                // there was an error in pre hook of auth
                if (err) {
                    // warn the user
                    run.triggers.console(context.coords,
                        'warn',
                        'runtime~' + authType + '.auth: could not validate the request: ' + (err.message || err),
                        err
                    );

                    // swallow the error, we've warned the user
                    return done();
                }

                // authHandler gave a go, sign the request
                if (success) { return authSignHook(); }

                // auth gave a no go, but no intermediate request
                if (!request) { return done(); }

                // prepare for sending intermediate request
                var replayController = new ReplayController(context.replayState, run),
                    item = new sdk.Item({request: request});

                // auth handler gave a no go, and an intermediate request.
                // make the intermediate request the response is passed to `init` hook
                replayController.requestReplay(context,
                    item,
                    // marks the auth as source for intermediate request
                    {source: auth.type + DOT_AUTH},
                    function (err, response) {
                        // errors for intermediate requests are passed to request callback
                        // passing it here will add it to original request as well, so don't do it
                        if (err) { return done(); }

                        // pass the response to Auth `init` hook
                        authHandler.init(authInterface, response, function (error) {
                            if (error) {
                                // warn about the err
                                run.triggers.console(context.coords, 'warn', 'runtime~' + authType + '.auth: ' +
                                    'could not initialize auth: ' + (error.message || error), error);

                                // swallow the error, we've warned the user
                                return done();
                            }

                            // schedule back to pre hook
                            authPreHook();
                        });
                    },
                    function (err) {
                        // warn users that maximum retries have exceeded
                        if (err) {
                            run.triggers.console(
                                context.coords, 'warn', 'runtime~' + authType + '.auth: ' + (err.message || err)
                            );
                        }
                        // but don't bubble up the error with the request
                        done();
                    }
                );
            });
        };

        // start the by calling the pre hook of the auth
        authPreHook();
    },

    // File loading
    function (context, run, done) {
        if (!context.item) { return done(new Error('Nothing to resolve files for.')); }

        var triggers = run.triggers,
            cursor = context.coords,
            sourceReadable,
            resolver,
            request,
            mode,
            data;

        resolver = run.options.fileResolver;

        // this has changed a bit from the old implementation, a bug is fixed.
        sourceReadable = resolver && _.isFunction(resolver.createReadStream);

        request = context.item.request;

        if (!request) { return done(new Error('No request to send.')); }

        // todo: add helper functions in the sdk to do this cleanly for us
        mode = _.get(request, 'body.mode');
        data = _.get(request, ['body', mode]);

        // if there is no mode specified, or no data for the specified mode we cannot resolve anything!
        // @note that if source is not readable, there is no point reading anything, yet we need to warn that file
        // upload was not done. hence we will have to proceed even without an unreadable source
        if (!data) { // we do not need to check `mode` here since false mode returns no `data`
            return done();
        }

        // in this block, we simply use async.waterfall to ensure that all form of file reading is async. essentially,
        // we first determine the data mode and based on it pass the waterfall functions.
        async.waterfall([async.constant(data), {
            // form data parsing simply "enriches" all form parameters having file data type by replacing / setting the
            // value as a read stream
            formdata: function (formdata, next) {
                // ensure that we only process the file type
                async.eachSeries(_.filter(formdata.all(), {type: 'file'}), function (formparam, callback) {
                    var stream;

                    try {
                        sourceReadable && formparam.src && (stream = resolver.createReadStream(formparam.src));
                    }
                    // eslint-disable-next-line no-empty
                    catch (e) { } // we do not need to forward error here since next line we throw warning

                    if (!stream) { // lack of stream also determines lack of `formparam.src` and source being readable
                        // eslint-disable-next-line max-len
                        triggers.console(cursor, 'warn', 'unable to load form file for upload: "' + formparam.src + '"');
                        // @todo - do enabled: false instead of removing it
                        formdata.remove(formparam); // remove from list since it will interfere with requester
                    }
                    // otherwise, replace the value with stream for making it usable in requester
                    else {
                        formparam.value = stream;
                    }
                    callback();
                }, next);
            },
            // file data
            file: function (filedata, next) {
                var stream;

                try {
                    sourceReadable && filedata.src && (stream = resolver.createReadStream(filedata.src));
                }
                // eslint-disable-next-line no-empty
                catch (e) { }

                if (!stream) {
                    triggers.console(cursor, 'warn', 'unable to load raw file for upload: "' + filedata.src + '"');
                    filedata.value = null; // ensure this does not mess with requester
                    delete filedata.content; // @todo - why content?
                }
                // stream is valid, so replace the value in data
                else {
                    // @todo: why is this not `value` like formdata. it would have made it easy to pass through
                    // a common logic
                    filedata.content = stream;
                }

                next();
            }
        }[mode] || async.constant()], function (err) {
            // just as a precaution, show the error in console. each resolver anyway should handle their own console
            // warnings.
            // @todo - get cursor here.
            err && triggers.console(cursor, 'warn', 'file data resolution error: ' + (err.message || err));
            done(null); // absorb the error since a console has been trigerred
        });
    },
    // Proxy lookup
    function (context, run, done) {
        var proxies = run.options.proxies,
            request = context.item.request,

            url;

        if (!request) { return done(new Error('No request to resolve proxy for.')); }

        url = request.url && request.url.toString();

        async.waterfall([
            // try resolving custom proxies before falling-back to system proxy
            function (cb) {
                if (_.isFunction(_.get(proxies, 'resolve'))) {
                    return cb(null, proxies.resolve(url));
                }
                return cb(null, undefined);
            },
            // fallback to system proxy
            function (config, cb) {
                if (config) {
                    return cb(null, config);
                }
                return _.isFunction(run.options.systemProxy) ? run.options.systemProxy(url, cb) : cb(null, undefined);
            }
        ], function (err, config) {
            if (err) {
                run.triggers.console(context.coords, 'warn', 'proxy lookup error: ' + (err.message || err));
            }

            config && (request.proxy = sdk.ProxyConfig.isProxyConfig(config) ? config : new sdk.ProxyConfig(config));
            return done();
        });
    },
    // Certificate lookup + reading from whichever file resolver is provided
    function (context, run, done) {
        var request,
            keyPath,
            certPath,
            fileResolver,

            certificate;

        // A. Check if we have the file resolver
        fileResolver = run.options.fileResolver;

        if (!fileResolver) { return done(); } // No point going ahead

        // B. Ensure we have the request
        request = _.get(context.item, 'request');
        if (!request) { return done(new Error('No request to resolve certificates for.')); }

        // C. See if any cert should be sent, by performing a URL matching
        certificate = run.options.certificates && run.options.certificates.resolveOne(request.url);
        if (!certificate) { return done(); }

        // D. Fetch the paths
        keyPath = _.get(certificate, 'key.src');
        certPath = _.get(certificate, 'cert.src');

        // E. Read from the path, and add the values to the certificate, also associate
        // the certificate with the current request.
        async.mapValues({
            key: keyPath,
            cert: certPath
        }, function (value, key, cb) {
            fileResolver.readFile(value, cb);
        }, function (err, fileContents) {
            if (err) {
                // Swallow the error after triggering a warning message for the user.
                run.triggers.console(context.coords, 'warn', 'certificate load error: ' + (err.message || err));
                return done();
            }

            _.set(certificate, 'key.value', fileContents.key);
            _.set(certificate, 'cert.value', fileContents.cert);

            request.certificate = certificate;
            done();
        });
    }
];
<commit_msg>Remove workaround for variable resolution `toObjectResolved`, fix has been moved upstream<commit_after>var _ = require('lodash'),
    async = require('async'),
    sdk = require('postman-collection'),

    createAuthInterface = require('../authorizer/auth-interface'),
    AuthLoader = require('../authorizer/index').AuthLoader,
    ReplayController = require('./replay-controller'),

    DOT_AUTH = '.auth';

module.exports = [
    // Variable resolution
    function (context, run, done) {
        if (!context.item) { return done(new Error('Nothing to resolve variables for.')); }

        // @todo - resolve variables in a more graceful way
        // @todo - no need to sync variables when SDK starts supporting resolution from scope directly
        context.item = new sdk.Item(context.item.toObjectResolved(null, [context.data,
            context.environment.syncVariablesTo({}), context.collectionVariables.syncVariablesTo({}),
            context.globals.syncVariablesTo({})], {ignoreOwnVariables: true}));

        var item = context.item,
            auth = context.auth;

        // Re-parse the URL, because variables have been resolved now, and things might be moved around
        item.request.url = new (sdk.Url)(item.request.url.toString());

        // resolve variables in auth
        auth && (context.auth = new sdk.RequestAuth(auth.toObjectResolved(null, [context.data,
            context.environment.syncVariablesTo({}), context.collectionVariables.syncVariablesTo({}),
            context.globals.syncVariablesTo({})], {ignoreOwnVariables: true})));

        done();
    },

    // Authorization
    function (context, run, done) {
        // validate all stuff. dont ask.
        if (!context.item) { return done(new Error('runtime: nothing to authorize.')); }

        // bail out if there is no auth
        if (!(context.auth && context.auth.type)) { return done(null); }

        // get auth handler
        var auth = context.auth,
            authType = auth.type,
            authHandler = AuthLoader.getHandler(authType),
            authPreHook,
            authInterface,
            authSignHook = function () {
                try {
                    authHandler.sign(authInterface, context.item.request, function (err) {
                        // handle all types of errors in one place, see catch block
                        if (err) { throw err; }

                        done();
                    });
                }
                catch (err) {
                    // handles synchronous and asynchronous errors in auth.sign
                    run.triggers.console(context.coords,
                        'warn',
                        'runtime~' + authType + '.auth: could not sign the request: ' + (err.message || err),
                        err
                    );

                    // swallow the error, we've warned the user
                    done();
                }
            };

        // bail out if there is no matching auth handler for the type
        if (!authHandler) {
            run.triggers.console(context.coords, 'warn', 'runtime: could not find a handler for auth: ' + auth.type);
            return done();
        }

        authInterface = createAuthInterface(auth);

        /**
         * We go through the `pre` request send validation for the auth. In this step one of the three things can happen
         *
         * If the Auth `pre` hook
         * 1. gives a go, we sign the request and proceed to send the request.
         * 2. gives a no go, we don't sign the request, but proceed to send the request.
         * 3. gives a no go, with a intermediate request,
         *      a. we suspend current request, send the intermediate request
         *      b. invoke Auth `init` hook with the response of the intermediate request
         *      c. invoke Auth `pre` hook, and repeat from 1
         */
        authPreHook = function () {
            authHandler.pre(authInterface, function (err, success, request) {
                // there was an error in pre hook of auth
                if (err) {
                    // warn the user
                    run.triggers.console(context.coords,
                        'warn',
                        'runtime~' + authType + '.auth: could not validate the request: ' + (err.message || err),
                        err
                    );

                    // swallow the error, we've warned the user
                    return done();
                }

                // authHandler gave a go, sign the request
                if (success) { return authSignHook(); }

                // auth gave a no go, but no intermediate request
                if (!request) { return done(); }

                // prepare for sending intermediate request
                var replayController = new ReplayController(context.replayState, run),
                    item = new sdk.Item({request: request});

                // auth handler gave a no go, and an intermediate request.
                // make the intermediate request the response is passed to `init` hook
                replayController.requestReplay(context,
                    item,
                    // marks the auth as source for intermediate request
                    {source: auth.type + DOT_AUTH},
                    function (err, response) {
                        // errors for intermediate requests are passed to request callback
                        // passing it here will add it to original request as well, so don't do it
                        if (err) { return done(); }

                        // pass the response to Auth `init` hook
                        authHandler.init(authInterface, response, function (error) {
                            if (error) {
                                // warn about the err
                                run.triggers.console(context.coords, 'warn', 'runtime~' + authType + '.auth: ' +
                                    'could not initialize auth: ' + (error.message || error), error);

                                // swallow the error, we've warned the user
                                return done();
                            }

                            // schedule back to pre hook
                            authPreHook();
                        });
                    },
                    function (err) {
                        // warn users that maximum retries have exceeded
                        if (err) {
                            run.triggers.console(
                                context.coords, 'warn', 'runtime~' + authType + '.auth: ' + (err.message || err)
                            );
                        }
                        // but don't bubble up the error with the request
                        done();
                    }
                );
            });
        };

        // start the by calling the pre hook of the auth
        authPreHook();
    },

    // File loading
    function (context, run, done) {
        if (!context.item) { return done(new Error('Nothing to resolve files for.')); }

        var triggers = run.triggers,
            cursor = context.coords,
            sourceReadable,
            resolver,
            request,
            mode,
            data;

        resolver = run.options.fileResolver;

        // this has changed a bit from the old implementation, a bug is fixed.
        sourceReadable = resolver && _.isFunction(resolver.createReadStream);

        request = context.item.request;

        if (!request) { return done(new Error('No request to send.')); }

        // todo: add helper functions in the sdk to do this cleanly for us
        mode = _.get(request, 'body.mode');
        data = _.get(request, ['body', mode]);

        // if there is no mode specified, or no data for the specified mode we cannot resolve anything!
        // @note that if source is not readable, there is no point reading anything, yet we need to warn that file
        // upload was not done. hence we will have to proceed even without an unreadable source
        if (!data) { // we do not need to check `mode` here since false mode returns no `data`
            return done();
        }

        // in this block, we simply use async.waterfall to ensure that all form of file reading is async. essentially,
        // we first determine the data mode and based on it pass the waterfall functions.
        async.waterfall([async.constant(data), {
            // form data parsing simply "enriches" all form parameters having file data type by replacing / setting the
            // value as a read stream
            formdata: function (formdata, next) {
                // ensure that we only process the file type
                async.eachSeries(_.filter(formdata.all(), {type: 'file'}), function (formparam, callback) {
                    var stream;

                    try {
                        sourceReadable && formparam.src && (stream = resolver.createReadStream(formparam.src));
                    }
                    // eslint-disable-next-line no-empty
                    catch (e) { } // we do not need to forward error here since next line we throw warning

                    if (!stream) { // lack of stream also determines lack of `formparam.src` and source being readable
                        // eslint-disable-next-line max-len
                        triggers.console(cursor, 'warn', 'unable to load form file for upload: "' + formparam.src + '"');
                        // @todo - do enabled: false instead of removing it
                        formdata.remove(formparam); // remove from list since it will interfere with requester
                    }
                    // otherwise, replace the value with stream for making it usable in requester
                    else {
                        formparam.value = stream;
                    }
                    callback();
                }, next);
            },
            // file data
            file: function (filedata, next) {
                var stream;

                try {
                    sourceReadable && filedata.src && (stream = resolver.createReadStream(filedata.src));
                }
                // eslint-disable-next-line no-empty
                catch (e) { }

                if (!stream) {
                    triggers.console(cursor, 'warn', 'unable to load raw file for upload: "' + filedata.src + '"');
                    filedata.value = null; // ensure this does not mess with requester
                    delete filedata.content; // @todo - why content?
                }
                // stream is valid, so replace the value in data
                else {
                    // @todo: why is this not `value` like formdata. it would have made it easy to pass through
                    // a common logic
                    filedata.content = stream;
                }

                next();
            }
        }[mode] || async.constant()], function (err) {
            // just as a precaution, show the error in console. each resolver anyway should handle their own console
            // warnings.
            // @todo - get cursor here.
            err && triggers.console(cursor, 'warn', 'file data resolution error: ' + (err.message || err));
            done(null); // absorb the error since a console has been trigerred
        });
    },
    // Proxy lookup
    function (context, run, done) {
        var proxies = run.options.proxies,
            request = context.item.request,

            url;

        if (!request) { return done(new Error('No request to resolve proxy for.')); }

        url = request.url && request.url.toString();

        async.waterfall([
            // try resolving custom proxies before falling-back to system proxy
            function (cb) {
                if (_.isFunction(_.get(proxies, 'resolve'))) {
                    return cb(null, proxies.resolve(url));
                }
                return cb(null, undefined);
            },
            // fallback to system proxy
            function (config, cb) {
                if (config) {
                    return cb(null, config);
                }
                return _.isFunction(run.options.systemProxy) ? run.options.systemProxy(url, cb) : cb(null, undefined);
            }
        ], function (err, config) {
            if (err) {
                run.triggers.console(context.coords, 'warn', 'proxy lookup error: ' + (err.message || err));
            }

            config && (request.proxy = sdk.ProxyConfig.isProxyConfig(config) ? config : new sdk.ProxyConfig(config));
            return done();
        });
    },
    // Certificate lookup + reading from whichever file resolver is provided
    function (context, run, done) {
        var request,
            keyPath,
            certPath,
            fileResolver,

            certificate;

        // A. Check if we have the file resolver
        fileResolver = run.options.fileResolver;

        if (!fileResolver) { return done(); } // No point going ahead

        // B. Ensure we have the request
        request = _.get(context.item, 'request');
        if (!request) { return done(new Error('No request to resolve certificates for.')); }

        // C. See if any cert should be sent, by performing a URL matching
        certificate = run.options.certificates && run.options.certificates.resolveOne(request.url);
        if (!certificate) { return done(); }

        // D. Fetch the paths
        keyPath = _.get(certificate, 'key.src');
        certPath = _.get(certificate, 'cert.src');

        // E. Read from the path, and add the values to the certificate, also associate
        // the certificate with the current request.
        async.mapValues({
            key: keyPath,
            cert: certPath
        }, function (value, key, cb) {
            fileResolver.readFile(value, cb);
        }, function (err, fileContents) {
            if (err) {
                // Swallow the error after triggering a warning message for the user.
                run.triggers.console(context.coords, 'warn', 'certificate load error: ' + (err.message || err));
                return done();
            }

            _.set(certificate, 'key.value', fileContents.key);
            _.set(certificate, 'cert.value', fileContents.cert);

            request.certificate = certificate;
            done();
        });
    }
];
<|endoftext|>


<commit_before>import { COLORS } from './util/colors';

/**
 * Regular expression for capturing RGB channels.
 *
 * @type {RegExp}
 * @private
 */
const RGB_REGEX = /rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)/i;

/**
 * Regular expression for capturing HEX channels.
 *
 * @type {RegExp}
 * @private
 */
const HEX_REGEX = /#([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})/i;

/**
 * Color class responsible for converting colors between rgb and hex.
 *
 * @since 3.1.0
 */
export default class Color {
  /**
   * Create new Color instance.
   * You can use different formats of color: named, rgb or hex.
   * Class will try to parse your provided color, otherwise throws an error.
   *
   * @constructor
   * @param {String|Object} color String with named color, rgb, hex or object with {r, g, b} properties
   * @param {Number} color.r Red channel
   * @param {Number} color.g Green channel
   * @param {Number} color.b Blue channel
   * @returns {Color}
   *
   * @example
   * Color.create('black');
   * Color.create('rgb(0, 10, 20)');
   * Color.create('#AABBCC');
   * Color.create({r: 0, g: 10, b: 20});
   */
  constructor(color) {
    if (Color.isNamed(color)) return Color.fromHex(COLORS[color.toUpperCase()]);
    if (Color.isRgb(color)) return Color.fromRgb(color);
    if (Color.isHex(color)) return Color.fromHex(color);
    if (!(color.hasOwnProperty('r') || color.hasOwnProperty('g') || color.hasOwnProperty('b'))) throw new Error(`Color ${color} can't be parsed`);

    this.setR(color.r);
    this.setG(color.g);
    this.setB(color.b);
  }

  /**
   * Get rounded value of red channel.
   *
   * @returns {Number}
   */
  getR() {
    return Math.round(this._r);
  }

  /**
   * Set clamped value of red channel.
   *
   * @param {Number} value
   * @returns {Color}
   */
  setR(value) {
    this._r = Math.max(0, Math.min(value, 255));
    return this;
  }

  /**
   * Get rounded value of green channel.
   *
   * @returns {Number}
   */
  getG() {
    return Math.round(this._g);
  }

  /**
   * Set clamped value of green channel.
   *
   * @param {Number} value
   * @returns {Color}
   */
  setG(value) {
    this._g = Math.max(0, Math.min(value, 255));
    return this;
  }

  /**
   * Get rounded value of blue channel.
   *
   * @returns {Number}
   */
  getB() {
    return Math.round(this._b);
  }

  /**
   * Set clamped value of blue channel.
   *
   * @param {Number} value
   * @returns {Color}
   */
  setB(value) {
    this._b = Math.max(0, Math.min(value, 255));
    return this;
  }

  /**
   * Convert color to RGB representation.
   *
   * @returns {{r: (Number), g: Number, b: (Number)}}
   */
  toRgb() {
    return {r: this.getR(), g: this.getG(), b: this.getB()};
  }

  /**
   * Convert color to HEX representation.
   *
   * @returns {String}
   */
  toHex() {
    const pad2 = c => c.length === 1 ? '0' + c : c;
    return '#' + [pad2(this.getR().toString(16)), pad2(this.getG().toString(16)), pad2(this.getB().toString(16))].join('');
  }

  /**
   * Check if provided color is named color.
   *
   * @param {String} color
   * @returns {Boolean}
   */
  static isNamed(color) {
    return (typeof color === 'string' && COLORS[color.toUpperCase()]);
  }

  /**
   * Check if provided color written in RGB representation.
   *
   * @static
   * @param {String} rgb RGB color
   * @returns {Boolean}
   */
  static isRgb(rgb) {
    return RGB_REGEX.test(rgb);
  }

  /**
   * Check if provided color written in HEX representation.
   *
   * @static
   * @param {String} hex HEX color
   * @returns {Boolean}
   */
  static isHex(hex) {
    return HEX_REGEX.test(hex);
  }

  /**
   * Parse RGB color and return Color instance.
   *
   * @static
   * @param {String} rgb RGB color
   * @returns {Color}
   */
  static fromRgb(rgb) {
    const [_, r, g, b] = rgb.match(RGB_REGEX);
    return this.create({r, g, b});
  }

  /**
   * Parse HEX color and return Color instance.
   *
   * @static
   * @param {String} hex HEX color
   * @returns {Color}
   */
  static fromHex(hex) {
    const [_, r, g, b] = hex.match(HEX_REGEX);
    return this.create({r: parseInt(r, 16), g: parseInt(g, 16), b: parseInt(b, 16)});
  }

  /**
   * Wrapper around `new Color()`.
   *
   * @static
   * @returns {Color}
   */
  static create(...args) {
    return new this(...args);
  }
}
<commit_msg>refactor(color): Declare class properties in constructor<commit_after>import { COLORS } from './util/colors';

/**
 * Regular expression for capturing RGB channels.
 *
 * @type {RegExp}
 * @private
 */
const RGB_REGEX = /rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)/i;

/**
 * Regular expression for capturing HEX channels.
 *
 * @type {RegExp}
 * @private
 */
const HEX_REGEX = /#([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})/i;

/**
 * Color class responsible for converting colors between rgb and hex.
 *
 * @since 3.1.0
 */
export default class Color {
  /**
   * Create new Color instance.
   * You can use different formats of color: named, rgb or hex.
   * Class will try to parse your provided color, otherwise throws an error.
   *
   * @constructor
   * @param {String|Object} color String with named color, rgb, hex or object with {r, g, b} properties
   * @param {Number} color.r Red channel
   * @param {Number} color.g Green channel
   * @param {Number} color.b Blue channel
   * @returns {Color}
   *
   * @example
   * Color.create('black');
   * Color.create('rgb(0, 10, 20)');
   * Color.create('#AABBCC');
   * Color.create({r: 0, g: 10, b: 20});
   */
  constructor(color) {
    if (Color.isNamed(color)) return Color.fromHex(COLORS[color.toUpperCase()]);
    if (Color.isRgb(color)) return Color.fromRgb(color);
    if (Color.isHex(color)) return Color.fromHex(color);
    if (!(color.hasOwnProperty('r') || color.hasOwnProperty('g') || color.hasOwnProperty('b'))) throw new Error(`Color ${color} can't be parsed`);

    this._r = 0;
    this._g = 0;
    this._b = 0;

    this.setR(color.r);
    this.setG(color.g);
    this.setB(color.b);
  }

  /**
   * Get rounded value of red channel.
   *
   * @returns {Number}
   */
  getR() {
    return Math.round(this._r);
  }

  /**
   * Set clamped value of red channel.
   *
   * @param {Number} value
   * @returns {Color}
   */
  setR(value) {
    this._r = Math.max(0, Math.min(value, 255));
    return this;
  }

  /**
   * Get rounded value of green channel.
   *
   * @returns {Number}
   */
  getG() {
    return Math.round(this._g);
  }

  /**
   * Set clamped value of green channel.
   *
   * @param {Number} value
   * @returns {Color}
   */
  setG(value) {
    this._g = Math.max(0, Math.min(value, 255));
    return this;
  }

  /**
   * Get rounded value of blue channel.
   *
   * @returns {Number}
   */
  getB() {
    return Math.round(this._b);
  }

  /**
   * Set clamped value of blue channel.
   *
   * @param {Number} value
   * @returns {Color}
   */
  setB(value) {
    this._b = Math.max(0, Math.min(value, 255));
    return this;
  }

  /**
   * Convert color to RGB representation.
   *
   * @returns {{r: Number, g: Number, b: Number}}
   */
  toRgb() {
    return {r: this.getR(), g: this.getG(), b: this.getB()};
  }

  /**
   * Convert color to HEX representation.
   *
   * @returns {String}
   */
  toHex() {
    const pad2 = c => c.length === 1 ? '0' + c : c;
    return '#' + [pad2(this.getR().toString(16)), pad2(this.getG().toString(16)), pad2(this.getB().toString(16))].join('');
  }

  /**
   * Check if provided color is named color.
   *
   * @static
   * @param {String} color
   * @returns {Boolean}
   */
  static isNamed(color) {
    return (typeof color === 'string' && COLORS[color.toUpperCase()]);
  }

  /**
   * Check if provided color written in RGB representation.
   *
   * @static
   * @param {String} rgb RGB color
   * @returns {Boolean}
   */
  static isRgb(rgb) {
    return RGB_REGEX.test(rgb);
  }

  /**
   * Check if provided color written in HEX representation.
   *
   * @static
   * @param {String} hex HEX color
   * @returns {Boolean}
   */
  static isHex(hex) {
    return HEX_REGEX.test(hex);
  }

  /**
   * Parse RGB color and return Color instance.
   *
   * @static
   * @param {String} rgb RGB color
   * @returns {Color}
   */
  static fromRgb(rgb) {
    const [_, r, g, b] = rgb.match(RGB_REGEX);
    return this.create({r, g, b});
  }

  /**
   * Parse HEX color and return Color instance.
   *
   * @static
   * @param {String} hex HEX color
   * @returns {Color}
   */
  static fromHex(hex) {
    const [_, r, g, b] = hex.match(HEX_REGEX);
    return this.create({r: parseInt(r, 16), g: parseInt(g, 16), b: parseInt(b, 16)});
  }

  /**
   * Wrapper around `new Color()`.
   *
   * @static
   * @returns {Color}
   */
  static create(...args) {
    return new this(...args);
  }
}
<|endoftext|>


<commit_before>let objBrowser = chrome ? chrome : browser;
(function() {
    //Toggle the highlight option and set it in LocalStorage
    var objOptionAddHighlight = document.getElementById('ext-etheraddresslookup-show_style');
    if(objOptionAddHighlight) {
        objOptionAddHighlight.addEventListener('click', toggleMatchHighlight);
    }

    //Select the blockchain explorer set it in LocalStorage
    var objOptionBlockchainExplorer = document.getElementById('ext-etheraddresslookup-choose_blockchain');
    if(objOptionBlockchainExplorer) {
        objOptionBlockchainExplorer.addEventListener('change', toggleBlockchainExplorer);
    }

    //Toggle the address lookups option and set it in LocalStorage
    var objAddressLookups = document.getElementById('ext-etheraddresslookup-perform_address_lookups');
    if(objAddressLookups) {
        objAddressLookups.addEventListener('click', togglePerformAddressLookups);
    }

    //Toggle the blacklist domains option and set it in LocalStorage
    var objBlacklistDomains = document.getElementById('ext-etheraddresslookup-blacklist_domains');
    if(objBlacklistDomains) {
        objBlacklistDomains.addEventListener('click', toggleBlacklistDomains);
    }

    //Toggle the use 3rd party blacklist domains option and set it in LocalStorage
    var objBlacklistDomains = document.getElementById('ext-etheraddresslookup-3rd_party_blacklist_domains');
    if(objBlacklistDomains) {
        objBlacklistDomains.addEventListener('click', toggle3rdPartyBlacklistDomains);
    }

    //Get the extension version
    var objManifest = objBrowser.runtime.getManifest();
    var objManifestVersion = document.getElementById('ext-manifest_version');
    if(objManifestVersion) {
        objManifestVersion.innerHTML = objManifest.version;
    }

    //init getting blacklisted domains
    getBlacklistedDomains();
    setInterval(function() {
        console.log("Re-caching blacklisted domains");
        getBlacklistedDomains();
    }, 180000);

    getWhitelistedDomains();
    setInterval(function() {
        console.log("Re-caching whitelisted domains");
        getWhitelistedDomains();
    }, 180000);
})();

objBrowser.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        var strOption = request.func;
        var strResponse = "";

        switch(strOption) {
            case 'highlight_option' :
                strResponse = localStorage.getItem("ext-etheraddresslookup-show_style");
                break;
            case 'blockchain_explorer' :
                strResponse = localStorage.getItem("ext-etheraddresslookup-blockchain_explorer");
                if(strResponse === null) {
                    strResponse = "https://etherscan.io/address";
                }
                break;
            case 'blacklist_domains' :
                //This option is enabled by default
                if(localStorage.getItem("ext-etheraddresslookup-blacklist_domains") === null) {
                    strResponse = 1;
                } else {
                    strResponse = localStorage.getItem("ext-etheraddresslookup-blacklist_domains");
                }
                break;
            case '3rd_party_blacklist_domains' :
                //This option is enabled by defailt
                if(localStorage.getItem("ext-etheraddresslookup-3rd_party_blacklist_domains") === null) {
                    strResponse = 1;
                } else {
                    strResponse = localStorage.getItem("ext-etheraddresslookup-3rd_party_blacklist_domains");
                }
                break;
            case 'blacklist_domain_list' :
                console.log("Getting blacklisted domain list");
                strResponse = getBlacklistedDomains("eal");
                break;
            case '3p_blacklist_domain_list' :
                console.log("Getting 3p blacklisted domain list");
                strResponse = getBlacklistedDomains("3p");
                break;
            case 'use_3rd_party_blacklists' :
                //This option is enabled by default
                if(localStorage.getItem("ext-etheraddresslookup-use_3rd_party_blacklist") === null) {
                    strResponse = 1;
                } else {
                    strResponse = localStorage.getItem("ext-etheraddresslookup-use_3rd_party_blacklist");
                }
                break;
            case 'whitelist_domain_list' :
                console.log("Getting whitelisted domain list");
                strResponse = getWhitelistedDomains();
                break;
            case 'rpc_provider' :
                    if(localStorage.getItem("ext-etheraddresslookup-rpc_node") === null) {
                        strResponse = "https://freely-central-lark.quiknode.io/9fe4c4a0-2ea2-4ac1-ab64-f92990cd2914/118-xxADc8hKSSB9joCb-g==/";
                    } else {
                        strResponse = localStorage.getItem("ext-etheraddresslookup-rpc_node");
                    }
                break;
            case 'rpc_default_provider' :
                strResponse = "https://freely-central-lark.quiknode.io/9fe4c4a0-2ea2-4ac1-ab64-f92990cd2914/118-xxADc8hKSSB9joCb-g==/";
                break;
            case 'perform_address_lookups' :
                //This option is enabled by default
                if(localStorage.getItem("ext-etheraddresslookup-perform_address_lookups") === null) {
                    strResponse = 1;
                } else {
                    strResponse = localStorage.getItem("ext-etheraddresslookup-perform_address_lookups");
                }
                break;
            case 'blacklist_whitelist_domain_list' :
                var objDomainLists = {"blacklist": "", "whitelist": ""};
                var objBlacklist = JSON.parse(getBlacklistedDomains("eal"));
                objDomainLists.blacklist = objBlacklist.domains;
                objDomainLists.whitelist = getWhitelistedDomains();
                strResponse = JSON.stringify(objDomainLists);
                break;
            default:
                strResponse = "unsupported";
                break;
        }

        sendResponse({resp:strResponse});
    }
);

function getBlacklistedDomains(strType)
{
    var objEalBlacklistedDomains = {
        "eal": {
            "timestamp": 0,
            "domains": [],
            "format": "plain",
            "repo": "https://raw.githubusercontent.com/409H/EtherAddressLookup/master/blacklists/domains.json",
            "identifer": "eal"
        },
        "third_party": {
            "iosiro": {
                "timestamp": 0,
                "domains": [],
                "format": "plain",
                "repo": "https://raw.githubusercontent.com/iosiro/counter_phishing_blacklist/master/blacklists/domains.json",
                "identifer": "iosiro"
            },
            "segasec": {
                "timestamp": 0,
                "domains": [],
                "format": "sha256",
                "repo": "https://segasec.github.io/PhishingFeed/phishing-domains-sha256.json",
                "identifer": "segasec"
            }
        }
    };
    //See if we need to get the blacklisted domains - ie: do we have them cached?
    if(localStorage.getItem("ext-etheraddresslookup-blacklist_domains_list") === null) {
        updateAllBlacklists(objEalBlacklistedDomains);
    } else {
        var objBlacklistedDomains = localStorage.getItem("ext-etheraddresslookup-blacklist_domains_list");
        //Check to see if the cache is older than 5 minutes, if so re-cache it.
        objBlacklistedDomains = JSON.parse(objBlacklistedDomains);
        console.log("Domains last fetched: " + (Math.floor(Date.now() / 1000) - objBlacklistedDomains.timestamp) + " seconds ago");
        if (objBlacklistedDomains.timestamp == 0 || (Math.floor(Date.now() / 1000) - objBlacklistedDomains.timestamp) > 180) {
            updateAllBlacklists(objEalBlacklistedDomains);
        }
    }

    strType = strType || "eal";
    if(strType == "eal") {
        var objEalDomains = localStorage.getItem("ext-etheraddresslookup-blacklist_domains_list");
        return objEalDomains;
    } else {
        var objEalDomains = localStorage.getItem("ext-etheraddresslookup-3p_blacklist_domains_list");
        return objEalDomains;
    }
}

function updateAllBlacklists(objEalBlacklistedDomains)
{
    getBlacklistedDomainsFromSource(objEalBlacklistedDomains.eal).then(function (arrDomains) {
        objEalBlacklistedDomains.eal.timestamp = Math.floor(Date.now() / 1000);
        objEalBlacklistedDomains.eal.domains = arrDomains;

        localStorage.setItem("ext-etheraddresslookup-blacklist_domains_list", JSON.stringify(objEalBlacklistedDomains.eal));
    });

    if( [null, 1].indexOf(localStorage.getItem("ext-etheraddresslookup-use_3rd_party_blacklist")) >= 0) {
        getBlacklistedDomainsFromSource(objEalBlacklistedDomains.third_party.iosiro).then(function (arrDomains) {
            objEalBlacklistedDomains.third_party.iosiro.timestamp = Math.floor(Date.now() / 1000);
            objEalBlacklistedDomains.third_party.iosiro.domains = arrDomains;

            localStorage.setItem("ext-etheraddresslookup-3p_blacklist_domains_list", JSON.stringify(objEalBlacklistedDomains.third_party));
            return objEalBlacklistedDomains.eal.domains;
        });

        getBlacklistedDomainsFromSource(objEalBlacklistedDomains.third_party.segasec).then(function (arrDomains) {
            objEalBlacklistedDomains.third_party.segasec.timestamp = Math.floor(Date.now() / 1000);
            objEalBlacklistedDomains.third_party.segasec.domains = arrDomains;

            localStorage.setItem("ext-etheraddresslookup-3p_blacklist_domains_list", JSON.stringify(objEalBlacklistedDomains.third_party));
            return objEalBlacklistedDomains.eal.domains;
        });
    }
}

function getWhitelistedDomains()
{
    var objWhitelistedDomains = {"timestamp":0,"domains":[]};
    //See if we need to get the blacklisted domains - ie: do we have them cached?
    if(localStorage.getItem("ext-etheraddresslookup-whitelist_domains_list") === null) {
        getWhitelistedDomainsFromSource().then(function (arrDomains) {
            objWhitelistedDomains.timestamp = Math.floor(Date.now() / 1000);
            objWhitelistedDomains.domains = arrDomains;

            localStorage.setItem("ext-etheraddresslookup-whitelist_domains_list", JSON.stringify(objWhitelistedDomains));
            return objWhitelistedDomains.domains;
        });
    } else {
        var objWhitelistedDomains = localStorage.getItem("ext-etheraddresslookup-whitelist_domains_list");
        //Check to see if the cache is older than 5 minutes, if so re-cache it.
        objWhitelistedDomains = JSON.parse(objWhitelistedDomains);
        console.log("Whitelisted domains last fetched: " + (Math.floor(Date.now() / 1000) - objWhitelistedDomains.timestamp) + " seconds ago");
        if ((Math.floor(Date.now() / 1000) - objWhitelistedDomains.timestamp) > 300) {
            console.log("Caching whitelisted domains again.");
            getWhitelistedDomainsFromSource().then(function (arrDomains) {
                objWhitelistedDomains.timestamp = Math.floor(Date.now() / 1000);
                objWhitelistedDomains.domains = arrDomains;

                localStorage.setItem("ext-etheraddresslookup-whitelist_domains_list", JSON.stringify(objWhitelistedDomains));
                return objWhitelistedDomains.domains;
            });
        }
    }

    return objWhitelistedDomains.domains;
}

async function getBlacklistedDomainsFromSource(objBlacklist)
{
    try {
        console.log("Getting blacklist from GitHub now: "+ objBlacklist.repo);
        let objResponse = await fetch(objBlacklist.repo);
        return objResponse.json();
    }
    catch(objError) {
        console.log("Failed to get blacklist for "+ objBlacklist.repo, objError);
    }
}

async function getWhitelistedDomainsFromSource()
{
    try {
        console.log("Getting whitelist from GitHub now: https://raw.githubusercontent.com/409H/EtherAddressLookup/master/whitelists/domains.json");
        let objResponse = await fetch("https://raw.githubusercontent.com/409H/EtherAddressLookup/master/whitelists/domains.json");
        return objResponse.json();
    }
    catch(objError) {
        console.log("Failed to get whitelist for https://raw.githubusercontent.com/409H/EtherAddressLookup/master/whitelists/domains.json", objError);
    }
}<commit_msg>Blacklists are now updated every 5 mins<commit_after>let objBrowser = chrome ? chrome : browser;
(function() {
    //Toggle the highlight option and set it in LocalStorage
    var objOptionAddHighlight = document.getElementById('ext-etheraddresslookup-show_style');
    if(objOptionAddHighlight) {
        objOptionAddHighlight.addEventListener('click', toggleMatchHighlight);
    }

    //Select the blockchain explorer set it in LocalStorage
    var objOptionBlockchainExplorer = document.getElementById('ext-etheraddresslookup-choose_blockchain');
    if(objOptionBlockchainExplorer) {
        objOptionBlockchainExplorer.addEventListener('change', toggleBlockchainExplorer);
    }

    //Toggle the address lookups option and set it in LocalStorage
    var objAddressLookups = document.getElementById('ext-etheraddresslookup-perform_address_lookups');
    if(objAddressLookups) {
        objAddressLookups.addEventListener('click', togglePerformAddressLookups);
    }

    //Toggle the blacklist domains option and set it in LocalStorage
    var objBlacklistDomains = document.getElementById('ext-etheraddresslookup-blacklist_domains');
    if(objBlacklistDomains) {
        objBlacklistDomains.addEventListener('click', toggleBlacklistDomains);
    }

    //Toggle the use 3rd party blacklist domains option and set it in LocalStorage
    var objBlacklistDomains = document.getElementById('ext-etheraddresslookup-3rd_party_blacklist_domains');
    if(objBlacklistDomains) {
        objBlacklistDomains.addEventListener('click', toggle3rdPartyBlacklistDomains);
    }

    //Get the extension version
    var objManifest = objBrowser.runtime.getManifest();
    var objManifestVersion = document.getElementById('ext-manifest_version');
    if(objManifestVersion) {
        objManifestVersion.innerHTML = objManifest.version;
    }

    //init getting blacklisted domains
    getBlacklistedDomains();
    setInterval(function() {
        console.log("Re-caching blacklisted domains");
        getBlacklistedDomains();
    }, 180000);

    getWhitelistedDomains();
    setInterval(function() {
        console.log("Re-caching whitelisted domains");
        getWhitelistedDomains();
    }, 180000);
})();

objBrowser.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        var strOption = request.func;
        var strResponse = "";

        switch(strOption) {
            case 'highlight_option' :
                strResponse = localStorage.getItem("ext-etheraddresslookup-show_style");
                break;
            case 'blockchain_explorer' :
                strResponse = localStorage.getItem("ext-etheraddresslookup-blockchain_explorer");
                if(strResponse === null) {
                    strResponse = "https://etherscan.io/address";
                }
                break;
            case 'blacklist_domains' :
                //This option is enabled by default
                if(localStorage.getItem("ext-etheraddresslookup-blacklist_domains") === null) {
                    strResponse = 1;
                } else {
                    strResponse = localStorage.getItem("ext-etheraddresslookup-blacklist_domains");
                }
                break;
            case '3rd_party_blacklist_domains' :
                //This option is enabled by defailt
                if(localStorage.getItem("ext-etheraddresslookup-3rd_party_blacklist_domains") === null) {
                    strResponse = 1;
                } else {
                    strResponse = localStorage.getItem("ext-etheraddresslookup-3rd_party_blacklist_domains");
                }
                break;
            case 'blacklist_domain_list' :
                console.log("Getting blacklisted domain list");
                strResponse = getBlacklistedDomains("eal");
                break;
            case '3p_blacklist_domain_list' :
                console.log("Getting 3p blacklisted domain list");
                strResponse = getBlacklistedDomains("3p");
                break;
            case 'use_3rd_party_blacklists' :
                //This option is enabled by default
                if(localStorage.getItem("ext-etheraddresslookup-use_3rd_party_blacklist") === null) {
                    strResponse = 1;
                } else {
                    strResponse = localStorage.getItem("ext-etheraddresslookup-use_3rd_party_blacklist");
                }
                break;
            case 'whitelist_domain_list' :
                console.log("Getting whitelisted domain list");
                strResponse = getWhitelistedDomains();
                break;
            case 'rpc_provider' :
                    if(localStorage.getItem("ext-etheraddresslookup-rpc_node") === null) {
                        strResponse = "https://freely-central-lark.quiknode.io/9fe4c4a0-2ea2-4ac1-ab64-f92990cd2914/118-xxADc8hKSSB9joCb-g==/";
                    } else {
                        strResponse = localStorage.getItem("ext-etheraddresslookup-rpc_node");
                    }
                break;
            case 'rpc_default_provider' :
                strResponse = "https://freely-central-lark.quiknode.io/9fe4c4a0-2ea2-4ac1-ab64-f92990cd2914/118-xxADc8hKSSB9joCb-g==/";
                break;
            case 'perform_address_lookups' :
                //This option is enabled by default
                if(localStorage.getItem("ext-etheraddresslookup-perform_address_lookups") === null) {
                    strResponse = 1;
                } else {
                    strResponse = localStorage.getItem("ext-etheraddresslookup-perform_address_lookups");
                }
                break;
            case 'blacklist_whitelist_domain_list' :
                var objDomainLists = {"blacklist": "", "whitelist": ""};
                var objBlacklist = JSON.parse(getBlacklistedDomains("eal"));
                objDomainLists.blacklist = objBlacklist.domains;
                objDomainLists.whitelist = getWhitelistedDomains();
                strResponse = JSON.stringify(objDomainLists);
                break;
            default:
                strResponse = "unsupported";
                break;
        }

        sendResponse({resp:strResponse});
    }
);

function getBlacklistedDomains(strType)
{
    var objEalBlacklistedDomains = {
        "eal": {
            "timestamp": 0,
            "domains": [],
            "format": "plain",
            "repo": "https://raw.githubusercontent.com/409H/EtherAddressLookup/master/blacklists/domains.json",
            "identifer": "eal"
        },
        "third_party": {
            "iosiro": {
                "timestamp": 0,
                "domains": [],
                "format": "plain",
                "repo": "https://raw.githubusercontent.com/iosiro/counter_phishing_blacklist/master/blacklists/domains.json",
                "identifer": "iosiro"
            },
            "segasec": {
                "timestamp": 0,
                "domains": [],
                "format": "sha256",
                "repo": "https://segasec.github.io/PhishingFeed/phishing-domains-sha256.json",
                "identifer": "segasec"
            }
        }
    };
    //See if we need to get the blacklisted domains - ie: do we have them cached?
    if(localStorage.getItem("ext-etheraddresslookup-blacklist_domains_list") === null) {
        updateAllBlacklists(objEalBlacklistedDomains);
    } else {
        var objBlacklistedDomains = localStorage.getItem("ext-etheraddresslookup-blacklist_domains_list");
        //Check to see if the cache is older than 5 minutes, if so re-cache it.
        objBlacklistedDomains = JSON.parse(objBlacklistedDomains);
        console.log("Domains last fetched: " + (Math.floor(Date.now() / 1000) - objBlacklistedDomains.timestamp) + " seconds ago");
        if (objBlacklistedDomains.timestamp == 0 || (Math.floor(Date.now() / 1000) - objBlacklistedDomains.timestamp) > 300) {
            updateAllBlacklists(objEalBlacklistedDomains);
        }
    }

    strType = strType || "eal";
    if(strType == "eal") {
        var objEalDomains = localStorage.getItem("ext-etheraddresslookup-blacklist_domains_list");
        return objEalDomains;
    } else {
        var objEalDomains = localStorage.getItem("ext-etheraddresslookup-3p_blacklist_domains_list");
        return objEalDomains;
    }
}

function updateAllBlacklists(objEalBlacklistedDomains)
{
    getBlacklistedDomainsFromSource(objEalBlacklistedDomains.eal).then(function (arrDomains) {
        objEalBlacklistedDomains.eal.timestamp = Math.floor(Date.now() / 1000);
        objEalBlacklistedDomains.eal.domains = arrDomains;

        localStorage.setItem("ext-etheraddresslookup-blacklist_domains_list", JSON.stringify(objEalBlacklistedDomains.eal));
    });

    if( [null, 1].indexOf(localStorage.getItem("ext-etheraddresslookup-use_3rd_party_blacklist")) >= 0) {
        getBlacklistedDomainsFromSource(objEalBlacklistedDomains.third_party.iosiro).then(function (arrDomains) {
            objEalBlacklistedDomains.third_party.iosiro.timestamp = Math.floor(Date.now() / 1000);
            objEalBlacklistedDomains.third_party.iosiro.domains = arrDomains;

            localStorage.setItem("ext-etheraddresslookup-3p_blacklist_domains_list", JSON.stringify(objEalBlacklistedDomains.third_party));
            return objEalBlacklistedDomains.eal.domains;
        });

        getBlacklistedDomainsFromSource(objEalBlacklistedDomains.third_party.segasec).then(function (arrDomains) {
            objEalBlacklistedDomains.third_party.segasec.timestamp = Math.floor(Date.now() / 1000);
            objEalBlacklistedDomains.third_party.segasec.domains = arrDomains;

            localStorage.setItem("ext-etheraddresslookup-3p_blacklist_domains_list", JSON.stringify(objEalBlacklistedDomains.third_party));
            return objEalBlacklistedDomains.eal.domains;
        });
    }
}

function getWhitelistedDomains()
{
    var objWhitelistedDomains = {"timestamp":0,"domains":[]};
    //See if we need to get the blacklisted domains - ie: do we have them cached?
    if(localStorage.getItem("ext-etheraddresslookup-whitelist_domains_list") === null) {
        getWhitelistedDomainsFromSource().then(function (arrDomains) {
            objWhitelistedDomains.timestamp = Math.floor(Date.now() / 1000);
            objWhitelistedDomains.domains = arrDomains;

            localStorage.setItem("ext-etheraddresslookup-whitelist_domains_list", JSON.stringify(objWhitelistedDomains));
            return objWhitelistedDomains.domains;
        });
    } else {
        var objWhitelistedDomains = localStorage.getItem("ext-etheraddresslookup-whitelist_domains_list");
        //Check to see if the cache is older than 5 minutes, if so re-cache it.
        objWhitelistedDomains = JSON.parse(objWhitelistedDomains);
        console.log("Whitelisted domains last fetched: " + (Math.floor(Date.now() / 1000) - objWhitelistedDomains.timestamp) + " seconds ago");
        if ((Math.floor(Date.now() / 1000) - objWhitelistedDomains.timestamp) > 300) {
            console.log("Caching whitelisted domains again.");
            getWhitelistedDomainsFromSource().then(function (arrDomains) {
                objWhitelistedDomains.timestamp = Math.floor(Date.now() / 1000);
                objWhitelistedDomains.domains = arrDomains;

                localStorage.setItem("ext-etheraddresslookup-whitelist_domains_list", JSON.stringify(objWhitelistedDomains));
                return objWhitelistedDomains.domains;
            });
        }
    }

    return objWhitelistedDomains.domains;
}

async function getBlacklistedDomainsFromSource(objBlacklist)
{
    try {
        console.log("Getting blacklist from GitHub now: "+ objBlacklist.repo);
        let objResponse = await fetch(objBlacklist.repo);
        return objResponse.json();
    }
    catch(objError) {
        console.log("Failed to get blacklist for "+ objBlacklist.repo, objError);
    }
}

async function getWhitelistedDomainsFromSource()
{
    try {
        console.log("Getting whitelist from GitHub now: https://raw.githubusercontent.com/409H/EtherAddressLookup/master/whitelists/domains.json");
        let objResponse = await fetch("https://raw.githubusercontent.com/409H/EtherAddressLookup/master/whitelists/domains.json");
        return objResponse.json();
    }
    catch(objError) {
        console.log("Failed to get whitelist for https://raw.githubusercontent.com/409H/EtherAddressLookup/master/whitelists/domains.json", objError);
    }
}<|endoftext|>


<commit_before>App.addChild('Contribution', {
  el: '#new-contribution',

  events: {
    'click .radio label' : 'clickReward',
    'click .submit-form' : 'submitForm',
    'input #contribution_value' : 'restrictChars'
  },

  restrictChars: function(event){
    var $target = $(event.target);
    $target.val($target.val().replace(/[^\d,]/, ''));
  },

  submitForm: function(){
    var user_value = this.$('.selected').find('.user-reward-value').val();
    var default_value = this.$('.selected').find('label[data-minimum-value]').data('minimum-value');
    this.$value.val(user_value || default_value);
    this.$('form').submit();
    return false;
  },

  activate: function(){
    this.$('.user-reward-value').mask('000.000.000,00', {reverse: true});
    this.$value = this.$('#contribution_value');
    this.$minimum = this.$('#minimum-value');
    this.clickReward({currentTarget: this.$('input[type=radio]:checked').parent()[0]});
    this.activateFloattingHeader();
  },

  activateFloattingHeader: function(){
    var top;
    var top_title = $('#new-contribution'),
    faq_top = $("#faq-box").offset().top;
    $(window).scroll(function() {
        top = $(top_title).offset().top,
        $(window).scrollTop() > top ? $(".reward-floating").addClass("reward-floating-display") : $(".reward-floating").removeClass("reward-floating-display");
        var t = $("#faq-box");
        $(window).scrollTop() > faq_top-130 ? $(t).hasClass("faq-card-fixed") || $(t).addClass("faq-card-fixed") : $(t).hasClass("faq-card-fixed") && $(t).removeClass("faq-card-fixed")
    });
  },

  resetReward: function(event){
    if(parseInt('0' + this.$value.val()) < this.minimumValue()){
      this.selectReward(this.$('.radio label'));
    }
  },

  minimumValue: function(){
    return this.$('.selected').find('label[data-minimum-value]').data('minimum-value');
  },

  resetSelected: function(){
    this.$('.w-radio').removeClass('selected');
  },

  selectReward: function(reward){
    this.resetSelected();
    reward.find('input[type=radio]').prop('checked', true);
    this.$('.back-reward-money').hide();
    reward.find('.back-reward-money').show();
    reward.parent().addClass('selected');

  },

  clickReward: function(event){
    this.selectReward($(event.currentTarget));
    var minimum = this.minimumValue();
    this.$value.val(minimum);
    this.$minimum.html(minimum);
  }
});

App.addChild('FaqBox', {
  el: '#faq-box',

  events: {
    'click li.list-question' : 'clickQuestion'
  },

  clickQuestion: function(event){
    var $question = $(event.currentTarget);
    var $answer = $question.next();
    $question.toggleClass('open').toggleClass('alt-link');
    $answer.slideToggle('slow');
  },

  activate: function(){
    this.$('li.list-answer').hide();
  }
});
<commit_msg>center screen on selected reward<commit_after>App.addChild('Contribution', {
  el: '#new-contribution',

  events: {
    'click .radio label' : 'clickReward',
    'click .submit-form' : 'submitForm',
    'input #contribution_value' : 'restrictChars'
  },

  restrictChars: function(event){
    var $target = $(event.target);
    $target.val($target.val().replace(/[^\d,]/, ''));
  },

  submitForm: function(){
    var user_value = this.$('.selected').find('.user-reward-value').val();
    var default_value = this.$('.selected').find('label[data-minimum-value]').data('minimum-value');
    this.$value.val(user_value || default_value);
    this.$('form').submit();
    return false;
  },

  activate: function(){
    this.$('.user-reward-value').mask('000.000.000,00', {reverse: true});
    this.$value = this.$('#contribution_value');
    this.$minimum = this.$('#minimum-value');
    this.clickReward({currentTarget: this.$('input[type=radio]:checked').parent()[0]});
    this.activateFloattingHeader();
  },

  activateFloattingHeader: function(){
    var top;
    var top_title = $('#new-contribution'),
    faq_top = $("#faq-box").offset().top;
    $(window).scroll(function() {
        top = $(top_title).offset().top,
        $(window).scrollTop() > top ? $(".reward-floating").addClass("reward-floating-display") : $(".reward-floating").removeClass("reward-floating-display");
        var t = $("#faq-box");
        $(window).scrollTop() > faq_top-130 ? $(t).hasClass("faq-card-fixed") || $(t).addClass("faq-card-fixed") : $(t).hasClass("faq-card-fixed") && $(t).removeClass("faq-card-fixed")
    });
  },

  resetReward: function(event){
    if(parseInt('0' + this.$value.val()) < this.minimumValue()){
      this.selectReward(this.$('.radio label'));
    }
  },

  minimumValue: function(){
    return this.$('.selected').find('label[data-minimum-value]').data('minimum-value');
  },

  resetSelected: function(){
    this.$('.w-radio').removeClass('selected');
  },

  selectReward: function(reward){
    this.resetSelected();
    reward.find('input[type=radio]').prop('checked', true);
    this.$('.back-reward-money').hide();
    reward.find('.back-reward-money').show();
    reward.parent().addClass('selected');

  },

  clickReward: function(event){
    this.selectReward($(event.currentTarget));
    var $this = $(event.currentTarget);
    var posY = $this.offset().top;
    var $thisHeight = $this.outerHeight();
    var windowHeight = $(window).height();
    var scrollPos = posY - windowHeight/2 + $thisHeight/2;
    $('html, body').animate({scrollTop: scrollPos}, 200);
    var minimum = this.minimumValue();
    this.$value.val(minimum);
    this.$minimum.html(minimum);
  }
});

App.addChild('FaqBox', {
  el: '#faq-box',

  events: {
    'click li.list-question' : 'clickQuestion'
  },

  clickQuestion: function(event){
    var $question = $(event.currentTarget);
    var $answer = $question.next();
    $question.toggleClass('open').toggleClass('alt-link');
    $answer.slideToggle('slow');
  },

  activate: function(){
    this.$('li.list-answer').hide();
  }
});
<|endoftext|>


<commit_before>angular.module('app')
.controller('DashboardController', function($scope, $mdSidenav, $mdDialog, Publisher, Projects) {
    $scope.project = null;
    $scope.editMode = false;
    $scope.projects = Projects.all();
    $scope.deploying = false;
    $scope.deployProgress = 0;
    $scope.deployStatus = '';

    $scope.isProcessing = function(){
        return $scope.deploying && $scope.project;
    }
    $scope.selectProject = function(p){
        $scope.project = p;
        $scope.editMode = false;
        $mdSidenav('projects').close();
    };
    $scope.toggleProjects = function() {
        $mdSidenav('projects').toggle();
    };
    $scope.toggleEditMode = function(){
        if($scope.editMode){
            if($scope.projects.indexOf($scope.project)<0){
                $scope.projects.push($scope.project);
            }
        }
        $scope.editMode = !$scope.editMode;
    };

    $scope.newProject = function(){
        $scope.project = {};
        $scope.editMode = true;
    }

    $scope.deploy = function(){
        if(!$scope.project && !$scope.isProcessing()) return;
        var confirm = $mdDialog.confirm()
            .title('Confirm')
            .textContent('Are you sure you want to deploy ' + $scope.project.name + "?")
            .ok('Deploy')
            .cancel('Cancel')
        ;
        $mdDialog.show(confirm)
        .then(function(){
            $scope.deploying = true;

            Publisher.publish($scope.project,function(){
                $scope.$apply(function(){
                    $scope.deploying = false;
                });
            },function(percent, status){
                $scope.deployProgress = percent;
                if(1==percent){
                    $scope.deployStatus = '';
                }else{
                    $scope.deployStatus = status;
                }
                if(!$scope.$$phase) $scope.$apply();
            });

        });
    }

    $scope.save = function(){
        $scope.toggleEditMode();
        Projects.save();
    }
})
;
<commit_msg>upload to ftp<commit_after>angular.module('app')
.controller('DashboardController', function($scope, $mdSidenav, $mdDialog, Publisher, Projects) {
    $scope.project = null;
    $scope.editMode = false;
    $scope.projects = Projects.all();
    $scope.deploying = false;
    $scope.deployProgress = 0;
    $scope.deployStatus = '';

    $scope.isProcessing = function(){
        return $scope.deploying && $scope.project;
    }
    $scope.selectProject = function(p){
        $scope.project = p;
        $scope.editMode = false;
        $mdSidenav('projects').close();
    };
    $scope.toggleProjects = function() {
        $mdSidenav('projects').toggle();
    };
    $scope.toggleEditMode = function(){
        if($scope.editMode){
            if($scope.projects.indexOf($scope.project)<0){
                $scope.projects.push($scope.project);
            }
        }
        $scope.editMode = !$scope.editMode;
    };

    $scope.newProject = function(){
        $scope.project = {};
        $scope.editMode = true;
    }

    $scope.deploy = function(){
        if(!$scope.project && !$scope.isProcessing()) return;
        var confirm = $mdDialog.confirm()
            .title('Confirm')
            .textContent('Are you sure you want to deploy ' + $scope.project.name + "?")
            .ok('Deploy')
            .cancel('Cancel')
        ;
        $mdDialog.show(confirm)
        .then(function(){
            $scope.deploying = true;

            Publisher.publish($scope.project,function(){
                $scope.$apply(function(){
                    $scope.deploying = false;
                });
            },function(percent, status){
                $scope.deployProgress = percent * 100;
                if(1==percent){
                    $scope.deployStatus = '';
                }else{
                    $scope.deployStatus = status;
                }
                if(!$scope.$$phase) $scope.$apply();
            });

        });
    }

    $scope.save = function(){
        $scope.toggleEditMode();
        Projects.save();
    }
})
;
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var _ = require('@sailshq/lodash');

/**
 * Transformation
 *
 * Allows for a Waterline Collection to have different
 * attributes than what actually exist in an adater's representation.
 *
 * @param {Object} attributes
 * @param {Object} tables
 */

var Transformation = module.exports = function(attributes) {

  // Hold an internal mapping of keys to transform
  this._transformations = {};

  // Initialize
  this.initialize(attributes);

  return this;
};

/**
 * Initial mapping of transformations.
 *
 * @param {Object} attributes
 * @param {Object} tables
 */

Transformation.prototype.initialize = function(attributes) {
  var self = this;

  _.each(attributes, function(attrValue, attrName) {
    // Make sure the attribute has a columnName set
    if (!_.has(attrValue, 'columnName')) {
      return;
    }

    // Ensure the columnName is a string
    if (!_.isString(attrValue.columnName)) {
      throw new Error('Column Name must be a string on ' + attrName);
    }

    // Set the column name transformation
    self._transformations[attrName] = attrValue.columnName;
  });
};

/**
 * Transforms a set of attributes into a representation used
 * in an adapter.
 *
 * @param {Object} attributes to transform
 * @return {Object}
 */

Transformation.prototype.serialize = function(values, behavior) {
  var self = this;

  behavior = behavior || 'default';

  function recursiveParse(obj) {
    // Return if no object
    if (!obj) {
      return;
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // TODO: remove this:
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Handle array of types for findOrCreateEach
    if (_.isString(obj)) {
      if (_.has(self._transformations, obj)) {
        values = self._transformations[obj];
        return;
      }

      return;
    }
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    _.each(obj, function(propertyValue, propertyName) {
      // Schema must be serialized in first level only
      if (behavior === 'schema') {
        if (_.has(self._transformations, propertyName)) {
          obj[self._transformations[propertyName]] = propertyValue;
          delete obj[propertyName];
        }
        return;
      }

      // Recursively parse `OR` criteria objects to transform keys
      if (_.isArray(propertyValue) && propertyName === 'or') {
        return recursiveParse(propertyValue);
      }

      // If Nested Object call function again passing the property as obj
      if ((toString.call(propertyValue) !== '[object Date]') && (_.isPlainObject(propertyValue))) {

        // check if object key is in the transformations
        if (_.has(self._transformations, propertyName)) {
          obj[self._transformations[propertyName]] = propertyValue;
          delete obj[propertyName];

          return recursiveParse(obj[self._transformations[propertyName]]);
        }

        return recursiveParse(propertyValue);
      }

      // If the property === SELECT check for any transformation keys
      if (propertyName === 'select' && _.isArray(propertyValue)) {
        // var arr = _.clone(obj[property]);
        _.each(propertyValue, function(prop) {
          if(_.has(self._transformations, prop)) {
            var idx = _.indexOf(propertyValue, prop);
            if(idx > -1) {
              obj[propertyName][idx] = self._transformations[prop];
            }
          }
        });
      }

      // Check if property is a transformation key
      if (_.has(self._transformations, propertyName)) {
        obj[self._transformations[propertyName]] = propertyValue;
        if (self._transformations[propertyName] !== propertyName) {
          delete obj[propertyName];
        }
      }
    });
  }

  // Recursivly parse attributes to handle nested criteria
  recursiveParse(values);

  return values;
};

/**
 * Transforms a set of attributes received from an adapter
 * into a representation used in a collection.
 *
 * @param {Object} attributes to transform
 * @return {Object}
 */

Transformation.prototype.unserialize = function(values) {
  // Loop through the attributes and change them
  _.each(this._transformations, function(transformName, transformKey) {
    if (!_.has(values, transformName)) {
      return;
    }

    values[transformKey] = values[transformName];
    if (transformName !== transformKey) {
      delete values[transformName];
    }
  });

  return values;
};
<commit_msg>don’t remove properties that have the same name<commit_after>/**
 * Module dependencies
 */

var _ = require('@sailshq/lodash');

/**
 * Transformation
 *
 * Allows for a Waterline Collection to have different
 * attributes than what actually exist in an adater's representation.
 *
 * @param {Object} attributes
 * @param {Object} tables
 */

var Transformation = module.exports = function(attributes) {

  // Hold an internal mapping of keys to transform
  this._transformations = {};

  // Initialize
  this.initialize(attributes);

  return this;
};

/**
 * Initial mapping of transformations.
 *
 * @param {Object} attributes
 * @param {Object} tables
 */

Transformation.prototype.initialize = function(attributes) {
  var self = this;

  _.each(attributes, function(attrValue, attrName) {
    // Make sure the attribute has a columnName set
    if (!_.has(attrValue, 'columnName')) {
      return;
    }

    // Ensure the columnName is a string
    if (!_.isString(attrValue.columnName)) {
      throw new Error('Column Name must be a string on ' + attrName);
    }

    // Set the column name transformation
    self._transformations[attrName] = attrValue.columnName;
  });
};

/**
 * Transforms a set of attributes into a representation used
 * in an adapter.
 *
 * @param {Object} attributes to transform
 * @return {Object}
 */

Transformation.prototype.serialize = function(values, behavior) {
  var self = this;

  behavior = behavior || 'default';

  function recursiveParse(obj) {

    // Return if no object
    if (!obj) {
      return;
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // TODO: remove this:
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Handle array of types for findOrCreateEach
    if (_.isString(obj)) {
      if (_.has(self._transformations, obj)) {
        values = self._transformations[obj];
        return;
      }

      return;
    }
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    _.each(obj, function(propertyValue, propertyName) {
      // Schema must be serialized in first level only
      if (behavior === 'schema') {
        if (_.has(self._transformations, propertyName)) {
          obj[self._transformations[propertyName]] = propertyValue;
          delete obj[propertyName];
        }
        return;
      }

      // Recursively parse `OR` criteria objects to transform keys
      if (_.isArray(propertyValue) && propertyName === 'or') {
        return recursiveParse(propertyValue);
      }

      // If Nested Object call function again passing the property as obj
      if ((toString.call(propertyValue) !== '[object Date]') && (_.isPlainObject(propertyValue))) {

        // check if object key is in the transformations
        if (_.has(self._transformations, propertyName)) {
          obj[self._transformations[propertyName]] = propertyValue;

          // Only delete if the names are different
          if (self._transformations[propertyName] !== propertyName) {
            delete obj[propertyName];
          }

          return recursiveParse(obj[self._transformations[propertyName]]);
        }

        return recursiveParse(propertyValue);
      }

      // If the property === SELECT check for any transformation keys
      if (propertyName === 'select' && _.isArray(propertyValue)) {
        // var arr = _.clone(obj[property]);
        _.each(propertyValue, function(prop) {
          if(_.has(self._transformations, prop)) {
            var idx = _.indexOf(propertyValue, prop);
            if(idx > -1) {
              obj[propertyName][idx] = self._transformations[prop];
            }
          }
        });
      }

      // Check if property is a transformation key
      if (_.has(self._transformations, propertyName)) {
        obj[self._transformations[propertyName]] = propertyValue;
        if (self._transformations[propertyName] !== propertyName) {
          delete obj[propertyName];
        }
      }
    });
  }

  // Recursivly parse attributes to handle nested criteria
  recursiveParse(values);

  return values;
};

/**
 * Transforms a set of attributes received from an adapter
 * into a representation used in a collection.
 *
 * @param {Object} attributes to transform
 * @return {Object}
 */

Transformation.prototype.unserialize = function(values) {
  // Loop through the attributes and change them
  _.each(this._transformations, function(transformName, transformKey) {
    if (!_.has(values, transformName)) {
      return;
    }

    values[transformKey] = values[transformName];
    if (transformName !== transformKey) {
      delete values[transformName];
    }
  });

  return values;
};
<|endoftext|>