<commit_before>var assert = require('assert'),
    Stool = require('../lib/stool/cradle').Stool,
    vows = require('vows');

vows.describe('Stool').addBatch({
    'driver when constructor arg has url': {
        topic: function () {
            return new Stool({ url: 'http://localhost:5984/blah' });
        },
        'should return Craddle db': function (topic) {
            var driver = topic.driver();
            assert.equal(driver.name, 'blah');
            assert.isFunction(driver.all);
            assert.isFunction(driver.save);
            assert.isFunction(driver.remove);
        }
    },
    'iterate when database exists': {
        'should throw error when callback error is provided': function (topic) {
            var _result,
                _options,
                _finishCallCount = 0,
                _successCbCallCount = 0,
                _errorCbCallCount = 0,
                db = {
                    all: function (options, cb) {
                        _options = options;
                        cb({error: 'Danger!', reason: 'Sharks'}, undefined);
                    }
                },
                process = function (result) {
                    _result = result;
                },
                finish = function () {
                    _finishCallCount = 1;
                },
                successCb = function (docs, err) {
                    _successCbCallCount = 1;
                },
                errorCb = function (docs, res) {
                    _errorCbCallCount = 1;
                },
                stool = new Stool({ db: db, batchSize: 1 });
            try {
                stool.iterate({
                    startKeyDocId: undefined,
                    endKeyDocId: undefined,
                    pageSize: 2,
                    numPages: -1 },
                    process);
                assert.fail('An error should have been thrown.');
            } catch (e) {
                assert.equal(e.message, 'Danger! - Sharks');
            }
            assert.isTrue(_options.include_docs);
            assert.equal(_options.limit, 3);
            assert.isUndefined(_options.startkey_docid);
            assert.isUndefined(_result);
            assert.equal(_finishCallCount, 0);
            assert.equal(_successCbCallCount, 0);
            assert.equal(_errorCbCallCount, 0);
        },
        'should call all once when result is empty': function (topic) {
            var _result,
                _options,
                _finishCallCount = 0,
                _successCbCallCount = 0,
                _errorCbCallCount = 0,
                db = {
                    all: function (options, cb) {
                        _options = options;
                        cb(undefined, []);
                    }
                },
                process = function (result) {
                    _result = result;
                },
                finish = function () {
                    _finishCallCount = 1;
                },
                successCb = function (docs, err) {
                    _successCbCallCount = 1;
                },
                errorCb = function (docs, res) {
                    _errorCbCallCount = 1;
                },
                stool = new Stool({ db: db, batchSize: 1 });
            stool.iterate({
                    startKeyDocId: undefined,
                    endKeyDocId: undefined,
                    pageSize: 2,
                    numPages: -1 },
                    process, finish);
            assert.isTrue(_options.include_docs);
            assert.equal(_options.limit, 3);
            assert.isUndefined(_options.startkey_docid);
            assert.equal(_result.length, 0);
            assert.equal(_finishCallCount, 1);
            assert.equal(_successCbCallCount, 0);
            assert.equal(_errorCbCallCount, 0);
        },
        'should call all once when result is less than page size': function (topic) {
            var _result,
                _options,
                _finishCallCount = 0,
                _successCbCallCount = 0,
                _errorCbCallCount = 0,
                db = {
                    all: function (options, cb) {
                        _options = options;
                        cb(undefined, [ { doc: { _id: 'a' } } ]);
                    }
                },
                process = function (result) {
                    _result = result;
                },
                finish = function () {
                    _finishCallCount = 1;
                },
                successCb = function (docs, err) {
                    _successCbCallCount = 1;
                },
                errorCb = function (docs, res) {
                    _errorCbCallCount = 1;
                },
                stool = new Stool({ db: db, batchSize: 1 });
            stool.iterate({
                    startKeyDocId: undefined,
                    endKeyDocId: undefined,
                    pageSize: 2,
                    numPages: -1 },
                    process, finish);
            assert.isTrue(_options.include_docs);
            assert.equal(_options.limit, 3);
            assert.isUndefined(_options.startkey_docid);
            assert.isUndefined(_options.endkey_docid);
            assert.equal(_result.length, 1);
            assert.equal(_result[0].doc._id, 'a');
            assert.equal(_finishCallCount, 1);
            assert.equal(_successCbCallCount, 0);
            assert.equal(_errorCbCallCount, 0);
        },
        'should call all once when result is exactly the page size': function (topic) {
            var _result,
                _options,
                _finishCallCount = 0,
                _successCbCallCount = 0,
                _errorCbCallCount = 0,
                db = {
                    all: function (options, cb) {
                        _options = options;
                        cb(undefined, [ { doc: { _id: 'a' } }, { doc: { _id: 'b' } } ]);
                    }
                },
                process = function (result) {
                    _result = result;
                },
                finish = function () {
                    _finishCallCount = 1;
                },
                successCb = function (docs, err) {
                    _successCbCallCount = 1;
                },
                errorCb = function (docs, res) {
                    _errorCbCallCount = 1;
                },
                stool = new Stool({ db: db, batchSize: 1 });
            stool.iterate({
                    startKeyDocId: undefined,
                    endKeyDocId: undefined,
                    pageSize: 2,
                    numPages: -1 },
                    process, finish);
            assert.isTrue(_options.include_docs);
            assert.equal(_options.limit, 3);
            assert.isUndefined(_options.startkey_docid);
            assert.isUndefined(_options.endkey_docid);
            assert.equal(_result.length, 2);
            assert.equal(_result[0].doc._id, 'a');
            assert.equal(_result[1].doc._id, 'b');
            assert.equal(_finishCallCount, 1);
            assert.equal(_successCbCallCount, 0);
            assert.equal(_errorCbCallCount, 0);
        },
        'should call all twice when result is more than page size': function (topic) {
            var _result,
                _options,
                dbCallCount = 0,
                _finishCallCount = 0,
                _successCbCallCount = 0,
                _errorCbCallCount = 0,
                db = {
                    all: function (options, cb) {
                        _options = options;
                        dbCallCount += 1;
                        if (dbCallCount === 1) {
                            cb(undefined, [
                                { doc: { _id: 'a' } },
                                { doc: { _id: 'b' } },
                                { doc: { _id: 'c' } } ]);
                        } else if (dbCallCount === 2) {
                            cb(undefined, [ { doc: { _id: 'c' } } ]);
                        } else {
                            assert.fail('Should not call all twice.');
                        }
                    }
                },
                process = function (result) {
                    _result = result;
                },
                finish = function () {
                    _finishCallCount = 1;
                },
                successCb = function (docs, err) {
                    _successCbCallCount = 1;
                },
                errorCb = function (docs, res) {
                    _errorCbCallCount = 1;
                },
                stool = new Stool({ db: db, batchSize: 1 });
            stool.iterate({
                startKeyDocId: undefined,
                endKeyDocId: 'z',
                pageSize: 2,
                numPages: -1 }, process, finish);
            // options and result from the last call
            assert.isTrue(_options.include_docs);
            assert.equal(_options.limit, 3);
            assert.equal(_options.startkey_docid, 'c');
            assert.equal(_options.endkey_docid, 'z');
            assert.equal(_result.length, 1);
            assert.equal(_result[0].doc._id, 'c');
            assert.equal(dbCallCount, 2);
            assert.equal(_finishCallCount, 1);
            assert.equal(_successCbCallCount, 0);
            assert.equal(_errorCbCallCount, 0);
        },
        'should call all once when num pages is 1 even though result is more than page size':
        function (topic) {
            var _result,
                _options,
                dbCallCount = 0,
                _finishCallCount = 0,
                _successCbCallCount = 0,
                _errorCbCallCount = 0,
                db = {
                    all: function (options, cb) {
                        _options = options;
                        dbCallCount += 1;
                        if (dbCallCount === 1) {
                            cb(undefined, [
                                { doc: { _id: 'a' } },
                                { doc: { _id: 'b' } },
                                { doc: { _id: 'c' } } ]);
                        } else {
                            assert.fail('Should not call all once.');
                        }
                    }
                },
                process = function (result) {
                    _result = result;
                },
                finish = function () {
                    _finishCallCount = 1;
                },
                successCb = function (docs, err) {
                    _successCbCallCount = 1;
                },
                errorCb = function (docs, res) {
                    _errorCbCallCount = 1;
                },
                stool = new Stool({ db: db, batchSize: 1 });
            stool.iterate({
                    startKeyDocId: undefined,
                    endKeyDocId: undefined,
                    pageSize: 2,
                    numPages: 1 },
                    process, finish);
            // options and result from the last call
            assert.isTrue(_options.include_docs);
            assert.equal(_options.limit, 3);
            assert.isUndefined(_options.startkey_docid);
            assert.isUndefined(_options.endkey_docid);
            assert.equal(_result.length, 3);
            assert.equal(_result[0].doc._id, 'a');
            assert.equal(dbCallCount, 1);
            assert.equal(_finishCallCount, 1);
            assert.equal(_successCbCallCount, 0);
            assert.equal(_errorCbCallCount, 0);
        }
    },
    'save': {
        'should call error callback when an error occured': function (topic) {
            var _docs, _err, callCount,
                db = {
                    'save': function (docs, cb) {
                        _docs = docs;
                        cb({ 'message': 'some error' }, undefined);
                    }
                },
                stool = new Stool({ db: db, batchSize: 1 });
            callCount = stool.save({ _id: 'abc', _rev: '123', blah: 'foobar' },
                undefined,
                function (docs, err) {
                    _err = err;
                });
            assert.equal(callCount, 1);
            assert.equal(_docs.length, 1);
            assert.equal(_docs[0]._id, 'abc');
            assert.equal(_docs[0]._rev, '123');
            assert.isUndefined(_docs[0]._deleted);
            assert.equal(_docs[0].blah, 'foobar');
            assert.equal(_err.message, 'some error');
        },
        'should call success callback when no error occured': function (topic) {
            var _docs, _res, callCount,
                db = {
                    'save': function (docs, cb) {
                        _docs = docs;
                        cb(undefined, { 'message': 'success' });
                    }
                },
                stool = new Stool({ db: db, batchSize: 1 });
            callCount = stool.save({ _id: 'abc', _rev: '123', blah: 'foobar' },
                function (docs, res) {
                    _res = res;
                },
                undefined);
            assert.equal(callCount, 1);
            assert.equal(_docs.length, 1);
            assert.equal(_docs[0]._id, 'abc');
            assert.equal(_docs[0]._rev, '123');
            assert.isUndefined(_docs[0]._deleted);
            assert.equal(_docs[0].blah, 'foobar');
            assert.equal(_res.message, 'success');
        }
    },
    'remove': {
        'should call error callback when an error occured': function (topic) {
            var _docs, _err, callCount,
                db = {
                    'save': function (docs, cb) {
                        _docs = docs;
                        cb({ 'message': 'some error' }, undefined);
                    }
                },
                stool = new Stool({ db: db, batchSize: 1 });
            callCount = stool.remove({ _id: 'abc', _rev: '123', blah: 'foobar' },
                undefined,
                function (docs, err) {
                    _err = err;
                });
            assert.equal(callCount, 1);
            assert.equal(_docs.length, 1);
            assert.equal(_docs[0]._id, 'abc');
            assert.equal(_docs[0]._rev, '123');
            assert.isTrue(_docs[0]._deleted);
            assert.equal(_docs[0].blah, 'foobar');
            assert.equal(_err.message, 'some error');
        },
        'should call success callback when no error occured': function (topic) {
            var _docs, _res, callCount,
                db = {
                    'save': function (docs, cb) {
                        _docs = docs;
                        cb(undefined, { 'message': 'success' });
                    }
                },
                stool = new Stool({ db: db, batchSize: 1 });
            callCount = stool.remove({ _id: 'abc', _rev: '123', blah: 'foobar' },
                function (docs, res) {
                    _res = res;
                },
                undefined);
            assert.equal(callCount, 1);
            assert.equal(_docs.length, 1);
            assert.equal(_docs[0]._id, 'abc');
            assert.equal(_docs[0]._rev, '123');
            assert.isTrue(_docs[0]._deleted);
            assert.equal(_docs[0].blah, 'foobar');
            assert.equal(_res.message, 'success');
        }
    }
}).exportTo(module);
<commit_msg>Move test stool cradle to a subdir now that bob test handles subdir.<commit_after><|endoftext|>


<commit_before>var termops = require('../lib/util/termops');
var test = require('tape');

test('termops', function(t) {
    t.test('tokenize', function(q) {
        q.test('tokenizes basic strings', function(r) {
            r.deepEqual(termops.tokenize('foo'), ['foo']);
            r.deepEqual(termops.tokenize('foo bar'), ['foo', 'bar']);
            r.deepEqual(termops.tokenize('foo-bar'), ['foo', 'bar']);
            r.deepEqual(termops.tokenize('San José'), ['san', 'jose']);
            r.deepEqual(termops.tokenize('San José'), ['san', 'jose']);
            r.deepEqual(termops.tokenize('Chamonix-Mont-Blanc'), ['chamonix','mont','blanc']);
            r.deepEqual(termops.tokenize('Москва'), ['moskva']);
            r.deepEqual(termops.tokenize('京都市'), ['jing','du','shi']);
            r.end();
        });
        q.test('tokenizes lonlat', function(r) {
            r.deepEqual(termops.tokenize('40,0', true), [40,0]);
            r.deepEqual(termops.tokenize('40.00000,-40.31200', true), [40,-40.312]);
            r.deepEqual(termops.tokenize('-120.9129102983109, 45.312312', true), [-120.9129102983109,45.312312]);
            r.deepEqual(termops.tokenize('14th 15th', true), ['14th','15th']);
            r.end();
        });
        q.test('edge cases - empty string', function(r) {
            r.deepEqual(termops.tokenize(''), []);
            r.end()
        });
        q.end();
    });
    t.test('isIdent - tests if searching by id', function(q) {
        var index = {
            country: "",
            province: "",
            place: "",
            postcode: ""
        };
        q.strictEqual(termops.isIdent(index, 'country.5432'), true);
        q.strictEqual(termops.isIdent(index, 'province.123'), true);
        q.strictEqual(termops.isIdent(index, 'postcode.546'), true);
        q.strictEqual(termops.isIdent(index, 'place.455233'), true);
        q.strictEqual(termops.isIdent(index, 'gotham.43213'), false);
        q.strictEqual(termops.isIdent(index, 'country.a445'), false);
        q.strictEqual(termops.isIdent(index, 'place.32f424'), false);
        q.strictEqual(termops.isIdent(index, 'country.424k'), false);
        q.end();
    });
    t.test('tokenMap - maps query tokens', function(q) {
        q.deepEqual([
            'nw',
            'broad',
            'st'
        ], termops.tokenMap({
            'street': 'st',
            'northwest': 'nw'
        }, [
            'northwest',
            'broad',
            'street'
        ]));
        q.end();
    });
    t.test('tokenizeMapping', function(q) {
        q.deepEqual({}, termops.tokenizeMapping({}));
        q.deepEqual({
            'street': 'st'
        }, termops.tokenizeMapping({
            'Street': 'St'
        }));
        q.throws(function() {
            q.deepEqual({
                'north west': 'nw'
            }, termops.tokenizeMapping({
                'North West': 'NW'
            }));
        }, /Invalid mapping token North West/);
        q.end();
    });
    t.test('terms - tokenizes and hashes values', function(q) {
        q.deepEqual(termops.terms(['foo','bar']), [2851307216,1991736592]);
        q.end();
    });
    t.test('termsMap - tokenizes and hashes values', function(q) {
        q.deepEqual(termops.termsMap(['foo','bar']), {
            2851307216: 'foo',
            1991736592: 'bar'
        });
        q.end();
    });
    t.test('degens', function(q) {
        var degens = termops.degens('foobarbaz');
        q.deepEqual(degens, [
            1617781328, 1617781328,
            4112850176, 1617781329,
            2921073328, 1617781330,
            3214735712, 1617781331,
            967483776, 1617781332,
            1062237920, 1617781333,
            2851307216, 1617781334
        ]);
        for (var i = 0; i < degens.length/2; i = i + 2) {
            // Encodes ID for 'foobarbaz'.
            q.equal(degens[i+1] >>> 4 << 4 >>> 0, termops.terms(['foobarbaz'])[0]);
            // Encodes degen distance (max: 15) from foobarbaz.
            q.ok(degens[i+1] % 16 <= 15);
        }
        q.end();
    });
    t.test('phrase - generates a name id', function(q) {
        q.deepEqual(termops.phrase(['foo'], 'foo'), 2851307223);
        q.deepEqual(termops.phrase(['foo','street'], 'foo'), 2851505742);
        q.deepEqual(termops.phrase(['foo','lane'], 'foo'), 2851502143);
        // Clusters phrase IDs based on initial term.
        q.deepEqual(termops.phrase(['foo'], 'foo') >>> 24, 169);
        q.deepEqual(termops.phrase(['foo','street'], 'foo') >>> 24, 169);
        q.deepEqual(termops.phrase(['foo','lane'], 'foo') >>> 24, 169);
        q.end();
    });
    t.end();
});
<commit_msg>added tests for alphanumeric adds<commit_after>var termops = require('../lib/util/termops');
var test = require('tape');

test('termops', function(t) {
    t.test('tokenize', function(q) {
        q.test('tokenizes basic strings', function(r) {
            r.deepEqual(termops.tokenize('foo'), ['foo']);
            r.deepEqual(termops.tokenize('foo bar'), ['foo', 'bar']);
            r.deepEqual(termops.tokenize('foo-bar'), ['foo', 'bar']);
            r.deepEqual(termops.tokenize('San José'), ['san', 'jose']);
            r.deepEqual(termops.tokenize('San José'), ['san', 'jose']);
            r.deepEqual(termops.tokenize('Chamonix-Mont-Blanc'), ['chamonix','mont','blanc']);
            r.deepEqual(termops.tokenize('Москва'), ['moskva']);
            r.deepEqual(termops.tokenize('京都市'), ['jing','du','shi']);
            r.end();
        });
        q.test('tokenizes lonlat', function(r) {
            r.deepEqual(termops.tokenize('40,0', true), [40,0]);
            r.deepEqual(termops.tokenize('40.00000,-40.31200', true), [40,-40.312]);
            r.deepEqual(termops.tokenize('-120.9129102983109, 45.312312', true), [-120.9129102983109,45.312312]);
            r.deepEqual(termops.tokenize('14th 15th', true), ['14th','15th']);
            r.end();
        });
        q.test('edge cases - empty string', function(r) {
            r.deepEqual(termops.tokenize(''), []);
            r.end()
        });
        q.end();
    });
    t.test('isIdent - tests if searching by id', function(q) {
        var index = {
            country: "",
            province: "",
            place: "",
            postcode: ""
        };
        q.strictEqual(termops.isIdent(index, 'country.5432'), true);
        q.strictEqual(termops.isIdent(index, 'province.123'), true);
        q.strictEqual(termops.isIdent(index, 'postcode.546'), true);
        q.strictEqual(termops.isIdent(index, 'place.455233'), true);
        q.strictEqual(termops.isIdent(index, 'gotham.43213'), false);
        q.strictEqual(termops.isIdent(index, 'country.a445'), false);
        q.strictEqual(termops.isIdent(index, 'place.32f424'), false);
        q.strictEqual(termops.isIdent(index, 'country.424k'), false);
        q.end();
    });
    t.test('tokenMap - maps query tokens', function(q) {
        q.deepEqual([
            'nw',
            'broad',
            'st'
        ], termops.tokenMap({
            'street': 'st',
            'northwest': 'nw'
        }, [
            'northwest',
            'broad',
            'street'
        ]));
        q.end();
    });
    t.test('tokenizeMapping', function(q) {
        q.deepEqual({}, termops.tokenizeMapping({}));
        q.deepEqual({
            'street': 'st'
        }, termops.tokenizeMapping({
            'Street': 'St'
        }));
        q.throws(function() {
            q.deepEqual({
                'north west': 'nw'
            }, termops.tokenizeMapping({
                'North West': 'NW'
            }));
        }, /Invalid mapping token North West/);
        q.end();
    });
    t.test('terms - tokenizes and hashes values', function(q) {
        q.deepEqual(termops.terms(['foo','bar']), [2851307216,1991736592]);
        q.end();
    });
    t.test('termsMap - tokenizes and hashes values', function(q) {
        q.deepEqual(termops.termsMap(['foo','bar']), {
            2851307216: 'foo',
            1991736592: 'bar'
        });
        q.end();
    });
    t.test('degens', function(q) {
        var degens = termops.degens('foobarbaz');
        q.deepEqual(degens, [
            1617781328, 1617781328,
            4112850176, 1617781329,
            2921073328, 1617781330,
            3214735712, 1617781331,
            967483776, 1617781332,
            1062237920, 1617781333,
            2851307216, 1617781334
        ]);
        for (var i = 0; i < degens.length/2; i = i + 2) {
            // Encodes ID for 'foobarbaz'.
            q.equal(degens[i+1] >>> 4 << 4 >>> 0, termops.terms(['foobarbaz'])[0]);
            // Encodes degen distance (max: 15) from foobarbaz.
            q.ok(degens[i+1] % 16 <= 15);
        }
        q.end();
    });
    t.test('phrase - generates a name id', function(q) {
        q.deepEqual(termops.phrase(['foo'], 'foo'), 2851307223);
        q.deepEqual(termops.phrase(['foo','street'], 'foo'), 2851505742);
        q.deepEqual(termops.phrase(['foo','lane'], 'foo'), 2851502143);
        // Clusters phrase IDs based on initial term.
        q.deepEqual(termops.phrase(['foo'], 'foo') >>> 24, 169);
        q.deepEqual(termops.phrase(['foo','street'], 'foo') >>> 24, 169);
        q.deepEqual(termops.phrase(['foo','lane'], 'foo') >>> 24, 169);
        q.end();
    });

    t.test('address', function(q) {
        q.deepEqual(termops.address('500 baker st'), '500', 'full address');
        q.deepEqual(termops.address('baker st'), null, 'no housenum');
        q.deepEqual(termops.address('500'), null, 'only number');
        q.deepEqual(termops.address('500b baker st'), '500b', 'alphanumeric');
        q.deepEqual(termops.address('15th st'), null, 'numbered st');
        q.deepEqual(termops.address('15 st francis drive'), '15', 'ambiguous abbr');
        q.end();
    });

    t.end();
});
<|endoftext|>


<commit_before>var fs             = require('fs'),
    Tw             = require('twit'),
		_              = require('underscore'),
		__             = require('./libs/underscore.ratelimit.js'),
		verbose        = true;

var T,
		regex,
		last_time_file_name = 'last_successful_time_searched.txt',
		last_time           = fs.existsSync('./' + last_time_file_name) ? fs.readFileSync('./'+ last_time_file_name).toString() : "Sat Jan 01 2000 00:00:00 GMT-0500 (EDT)",
		status = {};

function reportStatus(msg){
	if (verbose){
		console.log(msg)
	}
}

function retweetID(tweet_id, cb){
	T.post('statuses/retweet/:id', {id: tweet_id, trim_user: true}, function(err, replies) {
  	var this_moment = new Date();
	  if(err){
	    console.log('Retweet status:',this_moment, err);
	    cb(err, status)
	  }else{
	  	console.log('Successful retweet', this_moment, tweet_id)
	  	cb(null, status)
	  };
	});
}

function retweetIDs(arr, cb){
	var retweetID_rateLimited = _.rateLimit(retweetID, 500); // Limit the speed of retweets to one every 500ms
	if (arr.length){
		status.status = true
		_.each(arr, function(tweet_id){
			retweetID_rateLimited(tweet_id, cb);
		});
	}else{
		status.status = false;
		cb(null, status)
	}
};

function extractValuesFromJSON(arr, key){
	var key_list = [];
	_.each(arr, function(row){
		key_list.push(row[key]);
	});
	return key_list
};

function recordDate(file_name){
	var now = new Date();
	fs.writeFile(file_name, now, function(err) {
	    if(err) {
	        console.log(err);
	        cb(err)
	    } else {
	        console.log("Date saved!");
	    };
	});
};

function filterListByRegex(arr, regx){
	var filtered_list = [];
	_.each(arr, function(row){
		var tweet_text = row.text.toLowerCase()
		var matches_regex = regx.test(tweet_text);
		if(matches_regex){
			filtered_list.push(row)
		};
	});
	return filtered_list
};

function filterListByDate(arr, date){
	var filtered_list = [];
	var last_time_unix = new Date(last_time).getTime();
	_.each(arr, function(row){
		tweet_time_unix = new Date(row.created_at).getTime();
		// If the tweet is more recent than the last time the tweet bot ran
		if (tweet_time_unix > last_time_unix){
			filtered_list.push(row)
		}
	});
	return filtered_list
};

function filterByDateAndRegex(arr){
	var tweets_since_last_time = filterListByDate(arr, last_time);
	var tweets_matching_regex_and_time  = filterListByRegex(arr, regex);

	status.new_since      = tweets_since_last_time.length;
	status.matching_since = tweets_matching_regex_and_time.length;

	reportStatus('Matching time: '         + status.new_since)
	reportStatus('Matching time + regex: ' + status.matching_since);
	return tweets_matching_regex_and_time
};

function matchAndRetweet(arr, cb){
	var tweets_matching_regex_and_time = filterByDateAndRegex(arr);
	var tweet_ids_to_retweet = extractValuesFromJSON(tweets_matching_regex_and_time, 'id_str');
	retweetIDs(tweet_ids_to_retweet, cb);
}

function retrieveListStatuses(list_name, list_owner, count, cb){
	T.get('lists/statuses', { slug: list_name, owner_screen_name: list_owner, count: count }, function(err, replies) {
	  if(err){
	    console.log(err);
	    cb(err)
	  }else{
	    matchAndRetweet(replies, cb);
			recordDate(last_time_file_name);
	  };
	});
};

function retrieveListAndRetweet(opts, cb){
	var credentials = opts.credentials;
	T     = new Tw( credentials );
	regex = new RegExp(opts.regex);

	retrieveListStatuses(opts.list_name, opts.list_owner, opts.count, cb);
}

module.exports = {
	retweet: retrieveListAndRetweet
}<commit_msg>save date<commit_after>var fs             = require('fs'),
    Tw             = require('twit'),
		_              = require('underscore'),
		__             = require('./libs/underscore.ratelimit.js'),
		verbose        = true;

var T,
		regex,
		last_time_file_name = './last_successful_time_searched.txt',
		last_time           = fs.existsSync(last_time_file_name) ? fs.readFileSync(last_time_file_name).toString() : "Sat Jan 01 2000 00:00:00 GMT-0500 (EDT)",
		status = {};

function reportStatus(msg){
	if (verbose){
		console.log(msg)
	}
}

function retweetID(tweet_id, cb){
	T.post('statuses/retweet/:id', {id: tweet_id, trim_user: true}, function(err, replies) {
  	var this_moment = new Date();
	  if(err){
	    console.log('Retweet status:',this_moment, err);
	    cb(err, status)
	  }else{
	  	console.log('Successful retweet', this_moment, tweet_id)
	  	cb(null, status)
	  };
	});
}

function retweetIDs(arr, cb){
	var retweetID_rateLimited = _.rateLimit(retweetID, 500); // Limit the speed of retweets to one every 500ms
	if (arr.length){
		status.status = true
		_.each(arr, function(tweet_id){
			retweetID_rateLimited(tweet_id, cb);
		});
	}else{
		status.status = false;
		cb(null, status)
	}
};

function extractValuesFromJSON(arr, key){
	var key_list = [];
	_.each(arr, function(row){
		key_list.push(row[key]);
	});
	return key_list
};

function recordDate(file_name){
	var now = new Date();
	fs.writeFile(file_name, now, function(err) {
	    if(err) {
	        console.log(err);
	        cb(err)
	    } else {
	        console.log("Date saved!");
	    };
	});
};

function filterListByRegex(arr, regx){
	var filtered_list = [];
	_.each(arr, function(row){
		var tweet_text = row.text.toLowerCase()
		var matches_regex = regx.test(tweet_text);
		if(matches_regex){
			filtered_list.push(row)
		};
	});
	return filtered_list
};

function filterListByDate(arr, date){
	var filtered_list = [];
	var last_time_unix = new Date(last_time).getTime();
	_.each(arr, function(row){
		tweet_time_unix = new Date(row.created_at).getTime();
		// If the tweet is more recent than the last time the tweet bot ran
		if (tweet_time_unix > last_time_unix){
			filtered_list.push(row)
		}
	});
	return filtered_list
};

function filterByDateAndRegex(arr){
	var tweets_since_last_time = filterListByDate(arr, last_time);
	var tweets_matching_regex_and_time  = filterListByRegex(arr, regex);

	status.new_since      = tweets_since_last_time.length;
	status.matching_since = tweets_matching_regex_and_time.length;

	reportStatus('Matching time: '         + status.new_since)
	reportStatus('Matching time + regex: ' + status.matching_since);
	return tweets_matching_regex_and_time
};

function matchAndRetweet(arr, cb){
	var tweets_matching_regex_and_time = filterByDateAndRegex(arr);
	var tweet_ids_to_retweet = extractValuesFromJSON(tweets_matching_regex_and_time, 'id_str');
	retweetIDs(tweet_ids_to_retweet, cb);
}

function retrieveListStatuses(list_name, list_owner, count, cb){
	T.get('lists/statuses', { slug: list_name, owner_screen_name: list_owner, count: count }, function(err, replies) {
	  if(err){
	    console.log(err);
	    cb(err)
	  }else{
	    matchAndRetweet(replies, cb);
			recordDate(last_time_file_name);
	  };
	});
};

function retrieveListAndRetweet(opts, cb){
	var credentials = opts.credentials;
	T     = new Tw( credentials );
	regex = new RegExp(opts.regex);

	retrieveListStatuses(opts.list_name, opts.list_owner, opts.count, cb);
}

module.exports = {
	retweet: retrieveListAndRetweet
}<|endoftext|>


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

/**
 * This class handles feature info requests and preparing response for gui.
 *
 * @author Christin Henzen, Hannes Tressel. Professorship of Geoinformation Systems
 */
var markers;
var service_url, service_version, service_srs;

/**
 * This method is used to register an event listener that sets the marker on the map, when the user has clicked into the map.
 * Further, the feature info response is initialized and embedded.
 *
 * @param time_info - string param that is set to "time", if the service is time enabled and empty if not.
 */
var infoControls;

function bindFeatureControls(time_info) {
    //getting general information of web service
    var service_JSON;
    wmsDescription_Store.fetchItemByIdentity({
        identity: "serviceDescriptionParam",
        onItem: function(item, request) {
            service_JSON = item;
        }
    });
    service_url = wmsDescription_Store.getValue(service_JSON, "url");
    service_version = wmsDescription_Store.getValue(service_JSON, "version");
    service_srs = wmsDescription_Store.getValue(service_JSON, "srs");

    map.on("singleclick", function(evt) {
        map.getLayers().forEach(function(layer) {
            if (layer.getProperties().title === layer_Array[vis_layer_number].getProperties().title) {
                var resolution = map.getView().getResolution();
                var projection = map.getView().getProjection();
                var source = layer.getSource().getGetFeatureInfoUrl(evt.coordinate, resolution, projection, {
                    "INFO_FORMAT": "text/html",
                });
                if (typeof source != null) {
                    require(["dojo/dom-attr", "dojo/io-query"], function(domAttr, ioQuery) {
                        var sourceObject = ioQuery.queryToObject(source);
                        if (time_info === "time") {
                            var url = "featureInfo_compare.jsp?url=" + service_url + "&request=GetFeatureInfo&service=WMS" + "&version=" + sourceObject.VERSION + "&query_layers=" + sourceObject.QUERY_LAYERS + "&crs=" + sourceObject.SRS + "&bbox=" + sourceObject.BBOX + "&width=" + sourceObject.WIDTH + "&height=" + sourceObject.HEIGHT + "&I=" + sourceObject.X + "&J=" + sourceObject.Y + "&time=" + sourceObject.time;
                            domAttr.set("featureInfo_frame", "src", url);
                        } else {
                            var url = "featureInfo_compare.jsp?url=" + service_url + "&request=GetFeatureInfo&service=WMS" + "&version=" + sourceObject.VERSION + "&query_layers=" + sourceObject.QUERY_LAYERS + "&crs=" + (typeof sourceObject.CRS != "undefined" ? sourceObject.CRS : sourceObject.SRS) + "&bbox=" + sourceObject.BBOX + "&width=" + sourceObject.WIDTH + "&height=" + sourceObject.HEIGHT + "&I=" + (typeof sourceObject.X != "undefined" ? sourceObject.X : sourceObject.I) + "&J=" + (typeof sourceObject.Y != "undefined" ? sourceObject.Y : sourceObject.J) + "&time=x";
                            domAttr.set("featureInfo_frame", "src", url);
                        }
                    });
                }

                /* remove existant Overlays */
                map.getOverlays().forEach(function(overlay) {
                    map.removeOverlay(overlay);
                });

                /*create overlay image*/
                var overlayElement = null;
                require(["dojo/dom-construct", "dojo/query"], function(domConstruct, domStyle) {
                    overlayElement = domConstruct.create("img", {
                        src: 'js/ol3/resources/marker-blue.png',
                        style: {
                            position: "absolute",
                            top: "-25px",
                            left: "-10.5px",
                            color: "darkslateblue"
                        }
                    });
                });

                /* create overlay */
                var overlay = new ol.Overlay({
                    position: evt.coordinate,
                    element: overlayElement
                });

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

/**
 * This class handles feature info requests and preparing response for gui.
 *
 * @author Christin Henzen, Hannes Tressel. Professorship of Geoinformation Systems
 */
var markers;
var service_url, service_version, service_srs;
var featureInfoUrl;

/**
 * This method is used to register an event listener that sets the marker on the map, when the user has clicked into the map.
 * Further, the feature info response is initialized and embedded.
 *
 * @param time_info - string param that is set to "time", if the service is time enabled and empty if not.
 */
var infoControls;

function bindFeatureControls(time_info) {
    //getting general information of web service
    var service_JSON;
    wmsDescription_Store.fetchItemByIdentity({
        identity: "serviceDescriptionParam",
        onItem: function(item, request) {
            service_JSON = item;
        }
    });
    service_url = wmsDescription_Store.getValue(service_JSON, "url");
    service_version = wmsDescription_Store.getValue(service_JSON, "version");
    service_srs = wmsDescription_Store.getValue(service_JSON, "srs");

    map.on("singleclick", function(evt) {
        last_event = evt.coordinate;
        map.getLayers().forEach(function(layer) {
            if (layer.getProperties().title === layer_Array[vis_layer_number].getProperties().title) {
                var resolution = map.getView().getResolution();
                var projection = map.getView().getProjection();
                console.log(evt.coordinate);
                console.log(resolution);
                console.log(projection);
                var source = layer.getSource().getGetFeatureInfoUrl(evt.coordinate, resolution, projection, {
                    "INFO_FORMAT": "text/html",
                });
                featureInfoUrl = source;
                if (typeof source != null) {
                    require(["dojo/dom-attr", "dojo/io-query"], function(domAttr, ioQuery) {
                        var sourceObject = ioQuery.queryToObject(source);
                        if (time_info === "time") {
                            var url = "featureInfo_compare.jsp?url=" + service_url + "&request=GetFeatureInfo&service=WMS" + "&version=" + sourceObject.VERSION + "&query_layers=" + sourceObject.QUERY_LAYERS + "&crs=" + sourceObject.SRS + "&bbox=" + sourceObject.BBOX + "&width=" + sourceObject.WIDTH + "&height=" + sourceObject.HEIGHT + "&I=" + sourceObject.X + "&J=" + sourceObject.Y + "&time=" + sourceObject.time;
                            domAttr.set("featureInfo_frame", "src", url);
                        } else {
                            var url = "featureInfo_compare.jsp?url=" + service_url + "&request=GetFeatureInfo&service=WMS" + "&version=" + sourceObject.VERSION + "&query_layers=" + sourceObject.QUERY_LAYERS + "&crs=" + (typeof sourceObject.CRS != "undefined" ? sourceObject.CRS : sourceObject.SRS) + "&bbox=" + sourceObject.BBOX + "&width=" + sourceObject.WIDTH + "&height=" + sourceObject.HEIGHT + "&I=" + (typeof sourceObject.X != "undefined" ? sourceObject.X : sourceObject.I) + "&J=" + (typeof sourceObject.Y != "undefined" ? sourceObject.Y : sourceObject.J) + "&time=x";
                            domAttr.set("featureInfo_frame", "src", url);
                        }
                    });
                }

                /* remove existant Overlays */
                map.getOverlays().forEach(function(overlay) {
                    map.removeOverlay(overlay);
                });

                /*create overlay image*/
                var overlayElement = null;
                require(["dojo/dom-construct", "dojo/query"], function(domConstruct, domStyle) {
                    overlayElement = domConstruct.create("img", {
                        src: 'js/ol3/resources/marker-blue.png',
                        style: {
                            position: "absolute",
                            top: "-25px",
                            left: "-10.5px",
                            color: "darkslateblue"
                        }
                    });
                });

                /* create overlay */
                var overlay = new ol.Overlay({
                    position: evt.coordinate,
                    element: overlayElement
                });

                map.addOverlay(overlay);
            }
        });
    });
}
<|endoftext|>


<commit_before>/**
 * General utility library for Node.JS
 *
 * Copyright (c) 2019 Julian Knight (Totally Information)
 * https://it.knightnet.org.uk
 *
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/
// @ts-check
'use strict'

const path = require('path')
const fs = require('fs-extra')

module.exports = {
    /** Remove leading/trailing slashes from a string
     * @param {string} str
     * @returns {string}
     */
    trimSlashes: function(str) {
        return str.replace(/(^\/*)|(\/*$)/g, '')
    }, // ---- End of trimSlashes ---- //

    /** Joins all arguments as a URL string
     * @see http://stackoverflow.com/a/28592528/3016654
     * @since v1.0.10, fixed potential double // issue
     * @arguments {string} URL fragments
     * @returns {string}
     */
    urlJoin: function() {
        const paths = Array.prototype.slice.call(arguments)
        const url =
            '/'+paths.map(function(e){
                return e !== undefined ? e.replace(/^\/|\/$/g,'') : ''
            }).filter(function(e){
                return e
            }).join('/')
        return  url.replace('//','/')
    }, // ---- End of urlJoin ---- //

    /** Escape a user input string to use in a regular expression
     * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
     * @param {string} string
     * @returns {string} Input string escaped to use in a re
     */
    escapeRegExp: function(string) {
        return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string
    }, // ---- End of escapeRegExp ---- //

    /**  Get a list of all of the npm run scripts in <folder>/package.json OR
     * Check if a specific script exists in <folder>/package.json
     * Used to check that restart and build scripts are available.
     * @param {string} chkPath - The path that should contain a package.json
     * @param {string} chkScript - OPTIONAL. If present return the script text if present
     * @returns {Object|string|undefined|null} undefined if file not found or list of script names/commands. If chkScript, null if not found or script text.
     */
    getNpmRunScripts: function(chkPath, chkScript='') {
        let pj = undefined
        try {
            pj = require( path.join( chkPath, 'package.json' ) ).scripts
        } catch (e) {
            pj = undefined
        }
        if ( (pj !== undefined) && (chkScript !== '') ) {
            if (pj[chkScript] === undefined) pj = null
            else pj = pj[chkScript]
        }
        return pj
    }, // ---- End of getRedUserRunScripts ---- //

    /** Merge and deduplicate multiple arrays
     * @see https://stackoverflow.com/a/27664971/1309986
     * @param {any[]} arr One or more arrays
     * @returns {any[]} Deduplicated, merged single array
     */
    mergeDedupe: function(...arr) {
        return [...new Set([].concat(...arr))]
    }, // ----  ---- //

    /** Utility function to html pretty-print JSON */
    syntaxHighlight: function(json) {
        /*
            pre .string { color: orange; }
            .number { color: white; }
            .boolean { color: rgb(20, 99, 163); }
            .null { color: magenta; }
            .key { color: #069fb3;}
        */
        json = JSON.stringify(json, undefined, 4)
        json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
        return '
' + json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
            var cls = 'number', style = 'style="color:white"'
            if (/^"/.test(match)) {
                if (/:$/.test(match)) {
                    cls = 'key'
                    style = 'style="color:#069fb3"'
                } else {
                    cls = 'string'
                    style = 'style="color:orange"'
                }
            } else if (/true|false/.test(match)) {
                cls = 'boolean'
                style = 'style="color:rgb(20,99,163)"'
            } else if (/null/.test(match)) {
                cls = 'null'
                style = 'style="color:magenta"'
            }
            return `<span class="${cls}" ${style}>${match}</span>`
        }) + '
'
    }, // ----  ---- //

    /** Find package install folder
     * Searches in: userDir, nrc-uibuilder/node_modules, require.resolve(packageName) in that order.
     * NOTE: require.resolve can be a little ODD!
     *       When run from a linked package, it uses the link root not the linked location,
     *       this throws out the tree search. That's why we have to try several different locations here.
     *       Also, it finds the "main" script name which might not be in the package root.
     * @param {string} packageName - Name of the package who's root folder we are looking for.
     * @param {string} userDir - Home folder for Node-RED modules - needed to allow search for installation
     * @return {null|string} Actual filing system path to the installed package
     */
    findPackage: function(packageName, userDir) {

        let found = false, packagePath = ''
        try {
            packagePath = path.dirname( require.resolve(packageName, {paths: [userDir]}) )
            //console.log(`${packageName} found from userDir`, packagePath)
            found = true
        } catch (e) {
            //console.log (`${packageName} not found from userDir`)
        }
        if (found === false) try {
            packagePath = path.dirname( require.resolve(packageName) )
            //console.log(`${packageName} found`, packagePath)
            found = true
        } catch (e) {
            //console.log (`${packageName} not found`)
        }
        if (found === false) try {
            packagePath = path.dirname( require.resolve(packageName, {paths: [path.join(__dirname,'..')]}) )
            //console.log(`${packageName} found from uibuilder`, packagePath)
            found = true
        } catch (e) {
            //console.log (`${packageName} not found from uibuilder`)
        }

        if ( found === false ) return null

        /** require.resolve returns the "main" script, this may not be in the root folder for the package
         *  so we change that here. We check whether the last element of the path matches the package
         *  name. If not, we walk back up the tree until it is or we run out of tree.
         *  If we don't do this, when it is used with serveStatic, we may not get everything we need served.
         * NB: Only assuming 3 levels here.
         */
        let pathSplit = packagePath.split(path.sep)
        if ( (pathSplit.length > 1) && (pathSplit[pathSplit.length - 1] !== packageName) ) pathSplit.pop()
        if ( (pathSplit.length > 1) && (pathSplit[pathSplit.length - 1] !== packageName) ) pathSplit.pop()
        if ( (pathSplit.length > 1) && (pathSplit[pathSplit.length - 1] !== packageName) ) pathSplit.pop()
        packagePath = pathSplit.join(path.sep)

        return packagePath
    }, // ----  ---- //

    /** Return an updated list of installed front-end library packages
     * TODO DEPRECATE and change references to uiblib.updVendorPaths()
     * @param {string[]} masterPackageList Array of installed package names
     * @param {string} userDir Home folder for Node-RED modules - needed to allow search for installation
     * @return {string[]} Updated array of installed packages
     */
    updatePackageList: function(masterPackageList, userDir) {
        console.warn('uibuilder warning: tilib.updatePackageList is DEPRECATED, please remove from code')
        // Clone the current package list
        const packageList = [...masterPackageList]
        // Walk the cloned list and find any that are no longer actally there - changes the original list
        packageList.forEach(function(packageName,index){
            // call check function
            const qPackage = this.findPackage(packageName, userDir)
            // If not found, remove from global list
            if ( qPackage === null ) {
                masterPackageList = masterPackageList.filter(function(pName, index){
                    return pName != packageName
                })
            }
            // TODO ?Remove served references? Is this necessary?
        })
        // Find common FE packages and add them to the list if not already there - changes the original list

        return masterPackageList
    }, // ---- End of updatePackageList ---- //

    /** Read the contents of a package.json file
     * @param {string} folder The folder containing a package.json file
     * @returns {Object|null} Object representation of JSON if found otherwise null
    */
    readPackageJson: function(folder) {
        var file = null
        try {
            file = JSON.parse( fs.readFileSync( path.join(folder, 'package.json'), 'utf8' ) )
        } catch (err) {
            //console.error('[uibuilder] tilib.readPackageJson - failed to read ', folder, 'package.json', err)
        }
        return file
    }, // ----  ---- //

    /** Compare 2 simple arrays, return array of arrays - additions and deletions
     * @param {array} a1 First array
     * @param {array} a2 Second array
     * @returns {[string[],string[]]} Array of 2 arrays. Inner array 1: Additions, 2: Deletions
     */
    compareArrays: function(a1, a2) {
        let temp = [ [], [] ]

        // for each a1 entry, if not in a2 then push to temp[0]
        for (let i = 0, len = a1.length; i < len; ++i) {
            if(a2.indexOf(a1[i]) === -1) temp[0].push(a1[i])
        }

        // for each a2 entry, if not in a1 then push to temp[1]
        for (let i = 0, len = a2.length; i < len; ++i) {
            if(a1.indexOf(a2[i]) === -1) temp[1].push(a2[i])
        }

        // @ts-ignore
        return temp
    }, // ----  ---- //

} // ---- End of module.exports ---- //<commit_msg>Add class to pre in syntaxHighlight<commit_after>/**
 * General utility library for Node.JS
 *
 * Copyright (c) 2019 Julian Knight (Totally Information)
 * https://it.knightnet.org.uk
 *
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/
// @ts-check
'use strict'

const path = require('path')
const fs = require('fs-extra')

module.exports = {
    /** Remove leading/trailing slashes from a string
     * @param {string} str
     * @returns {string}
     */
    trimSlashes: function(str) {
        return str.replace(/(^\/*)|(\/*$)/g, '')
    }, // ---- End of trimSlashes ---- //

    /** Joins all arguments as a URL string
     * @see http://stackoverflow.com/a/28592528/3016654
     * @since v1.0.10, fixed potential double // issue
     * @arguments {string} URL fragments
     * @returns {string}
     */
    urlJoin: function() {
        const paths = Array.prototype.slice.call(arguments)
        const url =
            '/'+paths.map(function(e){
                return e !== undefined ? e.replace(/^\/|\/$/g,'') : ''
            }).filter(function(e){
                return e
            }).join('/')
        return  url.replace('//','/')
    }, // ---- End of urlJoin ---- //

    /** Escape a user input string to use in a regular expression
     * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
     * @param {string} string
     * @returns {string} Input string escaped to use in a re
     */
    escapeRegExp: function(string) {
        return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string
    }, // ---- End of escapeRegExp ---- //

    /**  Get a list of all of the npm run scripts in <folder>/package.json OR
     * Check if a specific script exists in <folder>/package.json
     * Used to check that restart and build scripts are available.
     * @param {string} chkPath - The path that should contain a package.json
     * @param {string} chkScript - OPTIONAL. If present return the script text if present
     * @returns {Object|string|undefined|null} undefined if file not found or list of script names/commands. If chkScript, null if not found or script text.
     */
    getNpmRunScripts: function(chkPath, chkScript='') {
        let pj = undefined
        try {
            pj = require( path.join( chkPath, 'package.json' ) ).scripts
        } catch (e) {
            pj = undefined
        }
        if ( (pj !== undefined) && (chkScript !== '') ) {
            if (pj[chkScript] === undefined) pj = null
            else pj = pj[chkScript]
        }
        return pj
    }, // ---- End of getRedUserRunScripts ---- //

    /** Merge and deduplicate multiple arrays
     * @see https://stackoverflow.com/a/27664971/1309986
     * @param {any[]} arr One or more arrays
     * @returns {any[]} Deduplicated, merged single array
     */
    mergeDedupe: function(...arr) {
        return [...new Set([].concat(...arr))]
    }, // ----  ---- //

    /** Utility function to html pretty-print JSON */
    syntaxHighlight: function(json) {
        /*
            pre .string { color: orange; }
            .number { color: white; }
            .boolean { color: rgb(20, 99, 163); }
            .null { color: magenta; }
            .key { color: #069fb3;}
        */
        json = JSON.stringify(json, undefined, 4)
        json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
        json = '
' + json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
            var cls = 'number', style = 'style="color:white"'
            if (/^"/.test(match)) {
                if (/:$/.test(match)) {
                    cls = 'key'
                    style = 'style="color:#069fb3"'
                } else {
                    cls = 'string'
                    style = 'style="color:orange"'
                }
            } else if (/true|false/.test(match)) {
                cls = 'boolean'
                style = 'style="color:rgb(20,99,163)"'
            } else if (/null/.test(match)) {
                cls = 'null'
                style = 'style="color:magenta"'
            }
            return `<span class="${cls}" ${style}>${match}</span>`
        }) + '
'
        return json
    }, // ----  ---- //

    /** Find package install folder
     * Searches in: userDir, nrc-uibuilder/node_modules, require.resolve(packageName) in that order.
     * NOTE: require.resolve can be a little ODD!
     *       When run from a linked package, it uses the link root not the linked location,
     *       this throws out the tree search. That's why we have to try several different locations here.
     *       Also, it finds the "main" script name which might not be in the package root.
     * @param {string} packageName - Name of the package who's root folder we are looking for.
     * @param {string} userDir - Home folder for Node-RED modules - needed to allow search for installation
     * @return {null|string} Actual filing system path to the installed package
     */
    findPackage: function(packageName, userDir) {

        let found = false, packagePath = ''
        try {
            packagePath = path.dirname( require.resolve(packageName, {paths: [userDir]}) )
            //console.log(`${packageName} found from userDir`, packagePath)
            found = true
        } catch (e) {
            //console.log (`${packageName} not found from userDir`)
        }
        if (found === false) try {
            packagePath = path.dirname( require.resolve(packageName) )
            //console.log(`${packageName} found`, packagePath)
            found = true
        } catch (e) {
            //console.log (`${packageName} not found`)
        }
        if (found === false) try {
            packagePath = path.dirname( require.resolve(packageName, {paths: [path.join(__dirname,'..')]}) )
            //console.log(`${packageName} found from uibuilder`, packagePath)
            found = true
        } catch (e) {
            //console.log (`${packageName} not found from uibuilder`)
        }

        if ( found === false ) return null

        /** require.resolve returns the "main" script, this may not be in the root folder for the package
         *  so we change that here. We check whether the last element of the path matches the package
         *  name. If not, we walk back up the tree until it is or we run out of tree.
         *  If we don't do this, when it is used with serveStatic, we may not get everything we need served.
         * NB: Only assuming 3 levels here.
         */
        let pathSplit = packagePath.split(path.sep)
        if ( (pathSplit.length > 1) && (pathSplit[pathSplit.length - 1] !== packageName) ) pathSplit.pop()
        if ( (pathSplit.length > 1) && (pathSplit[pathSplit.length - 1] !== packageName) ) pathSplit.pop()
        if ( (pathSplit.length > 1) && (pathSplit[pathSplit.length - 1] !== packageName) ) pathSplit.pop()
        packagePath = pathSplit.join(path.sep)

        return packagePath
    }, // ----  ---- //

    /** Return an updated list of installed front-end library packages
     * TODO DEPRECATE and change references to uiblib.updVendorPaths()
     * @param {string[]} masterPackageList Array of installed package names
     * @param {string} userDir Home folder for Node-RED modules - needed to allow search for installation
     * @return {string[]} Updated array of installed packages
     */
    updatePackageList: function(masterPackageList, userDir) {
        console.warn('uibuilder warning: tilib.updatePackageList is DEPRECATED, please remove from code')
        // Clone the current package list
        const packageList = [...masterPackageList]
        // Walk the cloned list and find any that are no longer actally there - changes the original list
        packageList.forEach(function(packageName,index){
            // call check function
            const qPackage = this.findPackage(packageName, userDir)
            // If not found, remove from global list
            if ( qPackage === null ) {
                masterPackageList = masterPackageList.filter(function(pName, index){
                    return pName != packageName
                })
            }
            // TODO ?Remove served references? Is this necessary?
        })
        // Find common FE packages and add them to the list if not already there - changes the original list

        return masterPackageList
    }, // ---- End of updatePackageList ---- //

    /** Read the contents of a package.json file
     * @param {string} folder The folder containing a package.json file
     * @returns {Object|null} Object representation of JSON if found otherwise null
    */
    readPackageJson: function(folder) {
        var file = null
        try {
            file = JSON.parse( fs.readFileSync( path.join(folder, 'package.json'), 'utf8' ) )
        } catch (err) {
            //console.error('[uibuilder] tilib.readPackageJson - failed to read ', folder, 'package.json', err)
        }
        return file
    }, // ----  ---- //

    /** Compare 2 simple arrays, return array of arrays - additions and deletions
     * @param {array} a1 First array
     * @param {array} a2 Second array
     * @returns {[string[],string[]]} Array of 2 arrays. Inner array 1: Additions, 2: Deletions
     */
    compareArrays: function(a1, a2) {
        let temp = [ [], [] ]

        // for each a1 entry, if not in a2 then push to temp[0]
        for (let i = 0, len = a1.length; i < len; ++i) {
            if(a2.indexOf(a1[i]) === -1) temp[0].push(a1[i])
        }

        // for each a2 entry, if not in a1 then push to temp[1]
        for (let i = 0, len = a2.length; i < len; ++i) {
            if(a1.indexOf(a2[i]) === -1) temp[1].push(a2[i])
        }

        // @ts-ignore
        return temp
    }, // ----  ---- //

} // ---- End of module.exports ---- //<|endoftext|>


<commit_before>// @flow
import * as React from 'react'
import * as Kb from '../../../../common-adapters'
import * as Styles from '../../../../styles'
import * as ChatTypes from '../../../../constants/types/chat2'
import {Avatars, TeamAvatar} from '../../../avatars'

export type ConvProps = {
  fullname: string,
  teamType: ChatTypes.TeamType,
  ignored: boolean,
  muted: boolean,
  participants: Array<string>,
}

export type Props = {
  attachTo: () => ?React.Component<any>,
  badgeSubscribe: boolean,
  canAddPeople: boolean,
  convProps: ?ConvProps, // empty when this conv is for a team but no particular conv
  isSmallTeam: boolean,
  manageChannelsSubtitle: string,
  manageChannelsTitle: string,
  memberCount: number,
  teamname: string,
  visible: boolean,
  hasCanPerform: boolean,
  loadOperations: () => void,
  onAddPeople: () => void,
  onHidden: () => void,
  onInvite: () => void,
  onLeaveTeam: () => void,
  onHideConv: () => void,
  onMuteConv: (muted: boolean) => void,
  onUnhideConv: () => void,
  onManageChannels: () => void,
  onViewTeam: () => void,
}

type AdhocHeaderProps = {
  fullname: string,
  isMuted: boolean,
  participants: Array<string>,
}
const AdhocHeader = (props: AdhocHeaderProps) => (
  <Kb.Box2 direction="vertical" gap="tiny" gapStart={false} gapEnd={true} style={styles.headerContainer}>
    <Avatars
      backgroundColor={Styles.globalColors.white}
      isHovered={false}
      isLocked={false}
      isMuted={props.isMuted}
      isSelected={false}
      participants={props.participants}
    />
    <Kb.Box2 direction="vertical" centerChildren={true}>
      <Kb.ConnectedUsernames
        colorFollowing={true}
        commaColor={Styles.globalColors.black_50}
        inline={false}
        skipSelf={props.participants.length > 1}
        type="BodyBig"
        underline={false}
        usernames={props.participants}
      />
      {!!props.fullname && <Kb.Text type="BodySmall">{props.fullname}</Kb.Text>}
    </Kb.Box2>
  </Kb.Box2>
)

type TeamHeaderProps = {
  isMuted: boolean,
  memberCount: number,
  teamname: string,
}
const TeamHeader = (props: TeamHeaderProps) => (
  <Kb.Box2 direction="vertical" gap="tiny" gapStart={false} gapEnd={true} style={styles.headerContainer}>
    <TeamAvatar teamname={props.teamname} isMuted={props.isMuted} isSelected={false} isHovered={false} />
    <Kb.Box2 direction="vertical" centerChildren={true}>
      <Kb.Text type="BodySemibold">{props.teamname}</Kb.Text>
      <Kb.Text type="BodySmall">{`${props.memberCount} member${props.memberCount !== 1 ? 's' : ''}`}</Kb.Text>
    </Kb.Box2>
  </Kb.Box2>
)

class InfoPanelMenu extends React.Component<Props> {
  componentDidUpdate(prevProps: Props) {
    if (this.props.hasCanPerform && this.props.visible !== prevProps.visible) {
      this.props.loadOperations()
    }
  }

  render() {
    const props = this.props
    const addPeopleItems = [
      {
        onClick: props.onAddPeople,
        style: {borderTopWidth: 0},
        subTitle: 'Keybase, Twitter, etc.',
        title: 'Add someone by username',
      },
      {
        onClick: props.onInvite,
        title: Styles.isMobile ? 'Add someone from address book' : 'Add someone by email',
      },
    ]
    const channelItem = props.isSmallTeam
      ? {
          onClick: props.onManageChannels,
          subTitle: props.manageChannelsSubtitle,
          title: props.manageChannelsTitle,
        }
      : {
          onClick: props.onManageChannels,
          title: props.manageChannelsTitle,
          view: (
            <Kb.Box style={Styles.globalStyles.flexBoxRow}>
              <Kb.Text style={styles.text} type={Styles.isMobile ? 'BodyBig' : 'Body'}>
                {props.manageChannelsTitle}
              </Kb.Text>
              {props.badgeSubscribe && <Kb.Box style={styles.badge} />}
            </Kb.Box>
          ),
        }

    const isAdhoc = !!(props.convProps && props.convProps.teamType === 'adhoc')
    const adhocItems = [this.hideItem(), this.muteItem()]
    const teamItems = [
      ...(props.canAddPeople ? addPeopleItems : []),
      {onClick: props.onViewTeam, style: {borderTopWidth: 0}, title: 'View team'},
      this.hideItem(),
      this.muteItem(),
      channelItem,
      {danger: true, onClick: props.onLeaveTeam, title: 'Leave team'},
    ].filter(item => item !== null)

    const header = {
      title: 'header',
      view:
        isAdhoc && props.convProps ? (
          <AdhocHeader
            isMuted={props.convProps.muted}
            fullname={props.convProps.fullname}
            participants={props.convProps.participants}
          />
        ) : (
          <TeamHeader
            isMuted={!!props.convProps?.muted}
            teamname={props.teamname}
            memberCount={props.memberCount}
          />
        ),
    }

    return (
      <Kb.FloatingMenu
        attachTo={props.attachTo}
        visible={props.visible}
        items={isAdhoc ? adhocItems : teamItems}
        header={header}
        onHidden={props.onHidden}
        position="bottom left"
        closeOnSelect={true}
      />
    )
  }

  hideItem() {
    if (this.props.convProps == null) {
      return null
    }
    const convProps = this.props.convProps
    if (convProps.teamType === 'adhoc' || convProps.teamType === 'small') {
      if (convProps.ignored) {
        return {onClick: this.props.onUnhideConv, style: {borderTopWidth: 0}, title: 'Unhide conversation'}
      } else {
        return {
          onClick: this.props.onHideConv,
          style: {borderTopWidth: 0},
          subTitle: 'Until next message',
          title: 'Hide conversation',
        }
      }
    } else {
      return null
    }
  }

  muteItem() {
    if (this.props.convProps == null) {
      return null
    }
    const convProps = this.props.convProps
    const title = `${convProps.muted ? 'Unmute' : 'Mute all'} notifications`
    return {
      onClick: () => this.props.onMuteConv(!convProps.muted),
      title,
      view: (
        <Kb.Box style={styles.muteAction}>
          <Kb.Text style={styles.text} type={Styles.isMobile ? 'BodyBig' : 'Body'}>
            {title}
          </Kb.Text>
          {!convProps.muted && (
            <Kb.Icon color={Styles.globalColors.black_20} style={styles.icon} type="iconfont-shh" />
          )}
        </Kb.Box>
      ),
    }
  }
}

const styles = Styles.styleSheetCreate({
  badge: Styles.platformStyles({
    common: {
      backgroundColor: Styles.globalColors.blue,
      borderRadius: 6,
      height: 8,
      margin: 6,
      width: 8,
    },
    isElectron: {
      margin: 4,
      marginTop: 5,
      position: 'absolute',
      right: Styles.globalMargins.tiny,
    },
  }),
  headerAvatar: Styles.platformStyles({
    isElectron: {
      marginBottom: 2,
    },
    isMobile: {
      marginBottom: 4,
    },
  }),
  headerContainer: Styles.platformStyles({
    common: {
      ...Styles.globalStyles.flexBoxColumn,
      alignItems: 'center',
    },
    isElectron: {
      paddingTop: 16,
    },
    isMobile: {paddingBottom: 24, paddingTop: 40},
  }),
  icon: {
    marginLeft: Styles.globalMargins.tiny,
  },
  muteAction: {
    ...Styles.globalStyles.flexBoxRow,
    alignItems: 'center',
  },
  noTopborder: {
    borderTopWidth: 0,
  },
  text: Styles.platformStyles({
    isMobile: {
      color: Styles.globalColors.blue,
    },
  }),
})

export {InfoPanelMenu}
<commit_msg>wrap long usernames/teamnames in convo menu header (#17533)<commit_after>// @flow
import * as React from 'react'
import * as Kb from '../../../../common-adapters'
import * as Styles from '../../../../styles'
import * as ChatTypes from '../../../../constants/types/chat2'
import {Avatars, TeamAvatar} from '../../../avatars'

export type ConvProps = {
  fullname: string,
  teamType: ChatTypes.TeamType,
  ignored: boolean,
  muted: boolean,
  participants: Array<string>,
}

export type Props = {
  attachTo: () => ?React.Component<any>,
  badgeSubscribe: boolean,
  canAddPeople: boolean,
  convProps: ?ConvProps, // empty when this conv is for a team but no particular conv
  isSmallTeam: boolean,
  manageChannelsSubtitle: string,
  manageChannelsTitle: string,
  memberCount: number,
  teamname: string,
  visible: boolean,
  hasCanPerform: boolean,
  loadOperations: () => void,
  onAddPeople: () => void,
  onHidden: () => void,
  onInvite: () => void,
  onLeaveTeam: () => void,
  onHideConv: () => void,
  onMuteConv: (muted: boolean) => void,
  onUnhideConv: () => void,
  onManageChannels: () => void,
  onViewTeam: () => void,
}

type AdhocHeaderProps = {
  fullname: string,
  isMuted: boolean,
  participants: Array<string>,
}
const AdhocHeader = (props: AdhocHeaderProps) => (
  <Kb.Box2 direction="vertical" gap="tiny" gapStart={false} gapEnd={true} style={styles.headerContainer}>
    <Avatars
      backgroundColor={Styles.globalColors.white}
      isHovered={false}
      isLocked={false}
      isMuted={props.isMuted}
      isSelected={false}
      participants={props.participants}
    />
    <Kb.Box2 direction="vertical" centerChildren={true}>
      <Kb.ConnectedUsernames
        colorFollowing={true}
        commaColor={Styles.globalColors.black_50}
        inline={false}
        skipSelf={props.participants.length > 1}
        containerStyle={styles.maybeLongText}
        type="BodyBig"
        underline={false}
        usernames={props.participants}
      />
      {!!props.fullname && <Kb.Text type="BodySmall">{props.fullname}</Kb.Text>}
    </Kb.Box2>
  </Kb.Box2>
)

type TeamHeaderProps = {
  isMuted: boolean,
  memberCount: number,
  teamname: string,
}
const TeamHeader = (props: TeamHeaderProps) => (
  <Kb.Box2 direction="vertical" gap="tiny" gapStart={false} gapEnd={true} style={styles.headerContainer}>
    <TeamAvatar teamname={props.teamname} isMuted={props.isMuted} isSelected={false} isHovered={false} />
    <Kb.Box2 direction="vertical" centerChildren={true}>
      <Kb.Text type="BodySemibold" style={styles.maybeLongText}>
        {props.teamname}
      </Kb.Text>
      <Kb.Text type="BodySmall">{`${props.memberCount} member${props.memberCount !== 1 ? 's' : ''}`}</Kb.Text>
    </Kb.Box2>
  </Kb.Box2>
)

class InfoPanelMenu extends React.Component<Props> {
  componentDidUpdate(prevProps: Props) {
    if (this.props.hasCanPerform && this.props.visible !== prevProps.visible) {
      this.props.loadOperations()
    }
  }

  render() {
    const props = this.props
    const addPeopleItems = [
      {
        onClick: props.onAddPeople,
        style: {borderTopWidth: 0},
        subTitle: 'Keybase, Twitter, etc.',
        title: 'Add someone by username',
      },
      {
        onClick: props.onInvite,
        title: Styles.isMobile ? 'Add someone from address book' : 'Add someone by email',
      },
    ]
    const channelItem = props.isSmallTeam
      ? {
          onClick: props.onManageChannels,
          subTitle: props.manageChannelsSubtitle,
          title: props.manageChannelsTitle,
        }
      : {
          onClick: props.onManageChannels,
          title: props.manageChannelsTitle,
          view: (
            <Kb.Box style={Styles.globalStyles.flexBoxRow}>
              <Kb.Text style={styles.text} type={Styles.isMobile ? 'BodyBig' : 'Body'}>
                {props.manageChannelsTitle}
              </Kb.Text>
              {props.badgeSubscribe && <Kb.Box style={styles.badge} />}
            </Kb.Box>
          ),
        }

    const isAdhoc = !!(props.convProps && props.convProps.teamType === 'adhoc')
    const adhocItems = [this.hideItem(), this.muteItem()]
    const teamItems = [
      ...(props.canAddPeople ? addPeopleItems : []),
      {onClick: props.onViewTeam, style: {borderTopWidth: 0}, title: 'View team'},
      this.hideItem(),
      this.muteItem(),
      channelItem,
      {danger: true, onClick: props.onLeaveTeam, title: 'Leave team'},
    ].filter(item => item !== null)

    const header = {
      title: 'header',
      view:
        isAdhoc && props.convProps ? (
          <AdhocHeader
            isMuted={props.convProps.muted}
            fullname={props.convProps.fullname}
            participants={props.convProps.participants}
          />
        ) : (
          <TeamHeader
            isMuted={!!props.convProps?.muted}
            teamname={props.teamname}
            memberCount={props.memberCount}
          />
        ),
    }

    return (
      <Kb.FloatingMenu
        attachTo={props.attachTo}
        visible={props.visible}
        items={isAdhoc ? adhocItems : teamItems}
        header={header}
        onHidden={props.onHidden}
        position="bottom left"
        closeOnSelect={true}
      />
    )
  }

  hideItem() {
    if (this.props.convProps == null) {
      return null
    }
    const convProps = this.props.convProps
    if (convProps.teamType === 'adhoc' || convProps.teamType === 'small') {
      if (convProps.ignored) {
        return {onClick: this.props.onUnhideConv, style: {borderTopWidth: 0}, title: 'Unhide conversation'}
      } else {
        return {
          onClick: this.props.onHideConv,
          style: {borderTopWidth: 0},
          subTitle: 'Until next message',
          title: 'Hide conversation',
        }
      }
    } else {
      return null
    }
  }

  muteItem() {
    if (this.props.convProps == null) {
      return null
    }
    const convProps = this.props.convProps
    const title = `${convProps.muted ? 'Unmute' : 'Mute all'} notifications`
    return {
      onClick: () => this.props.onMuteConv(!convProps.muted),
      title,
      view: (
        <Kb.Box style={styles.muteAction}>
          <Kb.Text style={styles.text} type={Styles.isMobile ? 'BodyBig' : 'Body'}>
            {title}
          </Kb.Text>
          {!convProps.muted && (
            <Kb.Icon color={Styles.globalColors.black_20} style={styles.icon} type="iconfont-shh" />
          )}
        </Kb.Box>
      ),
    }
  }
}

const styles = Styles.styleSheetCreate({
  badge: Styles.platformStyles({
    common: {
      backgroundColor: Styles.globalColors.blue,
      borderRadius: 6,
      height: 8,
      margin: 6,
      width: 8,
    },
    isElectron: {
      margin: 4,
      marginTop: 5,
      position: 'absolute',
      right: Styles.globalMargins.tiny,
    },
  }),
  headerAvatar: Styles.platformStyles({
    isElectron: {
      marginBottom: 2,
    },
    isMobile: {
      marginBottom: 4,
    },
  }),
  headerContainer: Styles.platformStyles({
    common: {
      ...Styles.globalStyles.flexBoxColumn,
      alignItems: 'center',
    },
    isElectron: {
      paddingTop: 16,
      width: 200, // don't expand if text is long
    },
    isMobile: {paddingBottom: 24, paddingTop: 40},
  }),
  icon: {
    marginLeft: Styles.globalMargins.tiny,
  },
  maybeLongText: Styles.platformStyles({
    common: {
      ...Styles.padding(0, Styles.globalMargins.tiny),
      textAlign: 'center',
    },
    isElectron: {
      wordBreak: 'break-word',
    },
  }),
  muteAction: {
    ...Styles.globalStyles.flexBoxRow,
    alignItems: 'center',
  },
  noTopborder: {
    borderTopWidth: 0,
  },
  text: Styles.platformStyles({
    isMobile: {
      color: Styles.globalColors.blue,
    },
  }),
})

export {InfoPanelMenu}
<|endoftext|>


<commit_before>
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
class Normalizer {
  constructor (datasets) {
    this.datasets = datasets;
  }

  static consistentSOPClass(datasets) {
    // return sopClass if all exist and match, otherwise undefined
    let sopClass;
    datasets.forEach(function(dataset) {
      console.log(dataset);
      if (!dataset.SOPClass) {
        return(undefined);
      }
      if (!sopClass) {
       sopClass = dataset.SOPClass;
      }
      if (dataset.SOPClass != sopClass) {
        return(undefined);
      }
    });
    return(sopClass);
  }

  static sopClassMap() {
    return ({
      "CTImage" : CTImageNormalizer,
      "MRImage" : MRImageNormalizer,
      "EnhancedMRImage" : EnhancedMRImageNormalizer,
      "PETImage" : PETImageNormalizer,
    });
  }

  normalize() {
    return("No normalization defined");
  }

  static normalizeToDataset(datasets) {
    let sopClass = Normalizer.consistentSOPClass(datasets);
    let normalizerClass = Normalizer.sopClassMap()[sopClass];
    if (!normalizerClass) {
      return(undefined);
    }
    let normalizer = new normalizerClass(datasets);
    return(normalizer.normalize());
  }
}

class ImageNormalizer extends Normalizer {
  normalize() {
    let dataset = this.datasets[0];
    if (!dataset.PixelRepresentation) {
      // Required tag: guess signed
      dataset.PixelRepresentation = 1;
    }
    if (!dataset.NumberOfFrames) {
      dataset.NumberOfFrames = 1;
    }
    if (!Array.isArray(dataset.WindowCenter)) {
      if (dataset.WindowCenter) {
        // assume both are specified as single string value
        dataset.WindowCenter = [dataset.WindowCenter];
        dataset.WindowWidth = [dataset.WindowWidth];
      } else {
        // pick a probably bad default
        dataset.WindowCenter = ["200"];
        dataset.WindowWidth = ["500"];
      }
    }
    return(dataset);
  }
}

class MRImageNormalizer extends ImageNormalizer {
  normalize() {
    let dataset = super.normalize();
    return(dataset);
  }
}

class EnhancedMRImageNormalizer extends ImageNormalizer {
  normalize() {
    if (this.datasets.length != 1) {
      return(undefined);
    }
    dataset = this.datasets[0];

    // provide a volume-level window/level estimate
    let wcww = {center: 0, width: 0};
    dataset.PerFrameFunctionalGroups.forEach(function(functionalGroup) {
      wcww.center += Number(functionalGroup.FrameVOILUT.WindowCenter);
      wcww.width += Number(functionalGroup.FrameVOILUT.WindowWidth);
    });
    dataset.WindowCenter = [String(wcww.center / Number(dataset.NumberOfFrames))];
    dataset.WindowWidth = [String(wcww.width / Number(dataset.NumberOfFrames))];

    return(dataset);
  }
}

class CTImageNormalizer extends ImageNormalizer {
  normalize() {
    let dataset = super.normalize();
    return(dataset);
  }
}

class PETImageNormalizer extends ImageNormalizer {
  normalize() {
    return("PETImageNormalizer");
  }
}
<commit_msg>Minor changes setting up for series display<commit_after>
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
class Normalizer {
  constructor (datasets) {
    this.datasets = datasets;
  }

  static consistentSOPClass(datasets) {
    // return sopClass if all exist and match, otherwise undefined
    let sopClass;
    datasets.forEach(function(dataset) {
      if (!dataset.SOPClass) {
        return(undefined);
      }
      if (!sopClass) {
       sopClass = dataset.SOPClass;
      }
      if (dataset.SOPClass != sopClass) {
        return(undefined);
      }
    });
    return(sopClass);
  }

  static sopClassMap() {
    return ({
      "CTImage" : CTImageNormalizer,
      "MRImage" : MRImageNormalizer,
      "EnhancedMRImage" : EnhancedMRImageNormalizer,
      "PETImage" : PETImageNormalizer,
    });
  }

  normalize() {
    return("No normalization defined");
  }

  static normalizeToDataset(datasets) {
    let sopClass = Normalizer.consistentSOPClass(datasets);
    let normalizerClass = Normalizer.sopClassMap()[sopClass];
    if (!normalizerClass) {
      return(undefined);
    }
    let normalizer = new normalizerClass(datasets);
    return(normalizer.normalize());
  }
}

class ImageNormalizer extends Normalizer {
  normalize() {
    let dataset = this.datasets[0];
    if (!dataset.PixelRepresentation) {
      // Required tag: guess signed
      dataset.PixelRepresentation = 1;
    }
    if (!dataset.NumberOfFrames) {
      dataset.NumberOfFrames = 1;
    }
    if (!Array.isArray(dataset.WindowCenter)) {
      if (dataset.WindowCenter) {
        // assume both are specified as single string value
        dataset.WindowCenter = [dataset.WindowCenter];
        dataset.WindowWidth = [dataset.WindowWidth];
      } else {
        // pick a probably bad default
        dataset.WindowCenter = ["200"];
        dataset.WindowWidth = ["500"];
      }
    }
    return(dataset);
  }
}

class MRImageNormalizer extends ImageNormalizer {
  normalize() {
    let dataset = super.normalize();
    return(dataset);
  }
}

class EnhancedMRImageNormalizer extends ImageNormalizer {
  normalize() {
    if (this.datasets.length != 1) {
      return(undefined);
    }
    let dataset = this.datasets[0];

    // provide a volume-level window/level estimate
    let wcww = {center: 0, width: 0};
    dataset.PerFrameFunctionalGroups.forEach(function(functionalGroup) {
      wcww.center += Number(functionalGroup.FrameVOILUT.WindowCenter);
      wcww.width += Number(functionalGroup.FrameVOILUT.WindowWidth);
    });
    dataset.WindowCenter = [String(wcww.center / Number(dataset.NumberOfFrames))];
    dataset.WindowWidth = [String(wcww.width / Number(dataset.NumberOfFrames))];

    return(dataset);
  }
}

class CTImageNormalizer extends ImageNormalizer {
  normalize() {
    let dataset = super.normalize();
    return(dataset);
  }
}

class PETImageNormalizer extends ImageNormalizer {
  normalize() {
    return("PETImageNormalizer");
  }
}
<|endoftext|>


<commit_before>(function(cobalt){
    var plugin={
        name:"webservices",

        settings:{
            base:{
                url :"",
                params : {}
            },
            defaultParameters:{
                type : "GET",
                saveToStorage : true,
                filterData : undefined,
                sendCacheResult : true
            }
        },
        calls:{},

        init:function(options){
            //create shortcuts
            cobalt.ws={
                config : this.config.bind(this),
                call : this.call.bind(this),
                pause : this.pause.bind(this),
                resume : this.resume.bind(this),
                clearPausedCalls : this.clearPausedCalls.bind(this),
                clearStorage : this.clearStorage.bind(this)
            }
            if (options){
                this.config(options);
            }

        },
        config:function(settings){
            cobalt.log('config webservices plugin with settings', settings)
            if (settings){
                if (settings.base){
                    this.settings.base = cobalt.utils.extend(this.settings.base, settings.base);
                }
                if (settings.defaultParameters){
                    this.settings.defaultParameters = cobalt.utils.extend(this.settings.defaultParameters, settings.defaultParameters);
                }
            }
        },
        call:function(options){
            var self=this;
            var newCall = {
                processData :    options.processData || this.settings.defaultParameters.processData,
                storageKey :    ( typeof options.storageKey =="string" && options.storageKey.length ) ? options.storageKey : undefined
            }

            if (options.url){
                newCall.url = ((/^https?:/).test(options.url)) ? options.url : self.settings.base.url + options.url;
                newCall.successCallback = (typeof options.successCallback =="function") ?  options.successCallback : self.settings.defaultParameters.successCallback || undefined;
                newCall.errorCallback = (typeof options.errorCallback =="function") ?  options.errorCallback : self.settings.defaultParameters.errorCallback || undefine;

                var params = cobalt.utils.extend( this.settings.base.params, options.params );
                if (params){
                    newCall.params = cobalt.utils.param(params);
                }
                newCall.type = options.type || this.settings.defaultParameters.type;

                newCall.headers = cobalt.utils.extend( this.settings.defaultParameters.headers, options.headers );
                if (! newCall.headers['User-Agent']){
                    newCall.headers['User-Agent'] = navigator.userAgent;
                }
            }

            if (newCall.storageKey){
                newCall.cacheCallback = (typeof options.cacheCallback =="function") ?  options.cacheCallback : self.settings.defaultParameters.cacheCallback || undefined;
                newCall.cacheError = (typeof options.cacheError =="function") ?  options.cacheError : self.settings.defaultParameters.cacheError || undefined;

                if (newCall.url){
                    newCall.saveToStorage = options.saveToStorage || this.settings.defaultParameters.saveToStorage;
                }

                if (newCall.cacheCallback){
                    newCall.sendCacheResult = options.saveToStorage || this.settings.defaultParameters.saveToStorage;
                }
            }

            self.send("call", newCall, function( data ){
                cobalt.log('WS call started with id = '+data.callId, newCall)
                newCall.callId = data.callId;
                self.calls[data.callId] = newCall;
            })

        },
        /* abort pending calls and stack all following calls
         *   call_ids = array of call ids.
         *   if none, all calls are paused
         */
        pause:function( call_ids ){
            self.send("pause", { call_ids : call_ids || [] })
        },
        /* resend aborted calls and send all stacked calls
         *   call_ids = array of call ids.
         *   if none, all stacked calls are resumed
         */
        resume:function( call_ids ){
            self.send("resume", { call_ids : call_ids || [] })
        },
        clearPausedCalls:function(){
            self.send("clearPausedCalls")
        },
        clearStorage:function(){
            self.send("clearStorage")
        },
        handleEvent:function(json){
            cobalt.log('received webservices plugin event', json)
            var data = ( json && json.data ) ? json.data : undefined;
            if (data && data.callId && this.calls[data.callId]){
                var concernedCall = this.calls[data.callId];
                switch (json.action){
                    case "onWSError":
                        if (concernedCall.errorCallback){
                            concernedCall.errorCallback( data.data || data.text, data.statusCode, concernedCall )
                        }else{
                            cobalt.log('WS error : No JS error callback for call ' + data.callId)
                        }
                        break;
                    case "onWSResult":
                        if (concernedCall.successCallback){
                            concernedCall.successCallback( data.data || data.text, data.statusCode, concernedCall )
                        }else{
                            cobalt.log('WS success but no JS callback for call ' + data.callId)
                        }
                        break;
                    case "onStorageResult":
                        if (concernedCall.cacheCallback){
                            concernedCall.cacheCallback( data.data || data.text, concernedCall )
                        }else{
                            cobalt.log('Some data in storage but no JS callback for call '+ data.callId)
                        }
                        break;
                    case "onStorageError":
                        if (concernedCall.cacheError){
                            concernedCall.cacheError( data.data || data.text, concernedCall )
                        }else{
                            cobalt.log('Some data in storage but no JS callback for call '+ data.callId)
                        }
                        break;
                    default :
                        cobalt.log('WS unknown action received from native side for call '+ data.callId);

                }
            }else{
                cobalt.log('WS unknown call event for call ', json)
            }

        },
        send:function(action, data, callback){
            cobalt.send({ type : "plugin", name : "webservices", action : action, data : data }, callback);
        }
    };
    cobalt.plugins.register(plugin);

})(cobalt || {});
<commit_msg>Update cobalt.webservices.js<commit_after>(function(cobalt){
    var plugin={
        name:"webservices",

        settings:{
            base:{
                url :"",
                params : {}
            },
            defaultParameters:{
                type : "GET",
                saveToStorage : true,
                filterData : undefined,
                sendCacheResult : true
            }
        },
        calls:{},

        init:function(options){
            //create shortcuts
            cobalt.ws={
                config : this.config.bind(this),
                call : this.call.bind(this),
                pause : this.pause.bind(this),
                resume : this.resume.bind(this),
                clearPausedCalls : this.clearPausedCalls.bind(this),
                clearStorage : this.clearStorage.bind(this)
            }
            if (options){
                this.config(options);
            }

        },
        config:function(settings){
            cobalt.log('config webservices plugin with settings', settings)
            if (settings){
                if (settings.base){
                    this.settings.base = cobalt.utils.extend(this.settings.base, settings.base);
                }
                if (settings.defaultParameters){
                    this.settings.defaultParameters = cobalt.utils.extend(this.settings.defaultParameters, settings.defaultParameters);
                }
            }
        },
        call:function(options){
            var self=this;
            var newCall = {
                processData :    options.processData || this.settings.defaultParameters.processData,
                storageKey :    ( typeof options.storageKey =="string" && options.storageKey.length ) ? options.storageKey : undefined
            }

            if (options.url){
                newCall.url = ((/^https?:/).test(options.url)) ? options.url : self.settings.base.url + options.url;
                newCall.successCallback = (typeof options.successCallback =="function") ?  options.successCallback : self.settings.defaultParameters.successCallback || undefined;
                newCall.errorCallback = (typeof options.errorCallback =="function") ?  options.errorCallback : self.settings.defaultParameters.errorCallback || undefine;

                var params = cobalt.utils.extend( this.settings.base.params, options.params );
                if (params){
                    newCall.params = cobalt.utils.param(params);
                }
                newCall.type = options.type || this.settings.defaultParameters.type;

                newCall.headers = cobalt.utils.extend( this.settings.defaultParameters.headers, options.headers );
                if (! newCall.headers['User-Agent']){
                    newCall.headers['User-Agent'] = navigator.userAgent;
                }
            }

            if (newCall.storageKey){
                newCall.cacheCallback = (typeof options.cacheCallback =="function") ?  options.cacheCallback : self.settings.defaultParameters.cacheCallback || undefined;
                newCall.cacheError = (typeof options.cacheError =="function") ?  options.cacheError : self.settings.defaultParameters.cacheError || undefined;

                if (newCall.url){
                    newCall.saveToStorage = options.saveToStorage || this.settings.defaultParameters.saveToStorage;
                }

                if (newCall.cacheCallback){
                    newCall.sendCacheResult = options.saveToStorage || this.settings.defaultParameters.saveToStorage;
                }
            }

            self.send("call", newCall, function( data ){
                cobalt.log('WS call started with id = '+data.callId, newCall)
                newCall.callId = data.callId;
                self.calls[data.callId] = newCall;
            })

        },
        /* abort pending calls and stack all following calls
         *   call_ids = array of call ids.
         *   if none, all calls are paused
         */
        pause:function( call_ids ){
            self.send("pause", { call_ids : call_ids || [] })
        },
        /* resend aborted calls and send all stacked calls
         *   call_ids = array of call ids.
         *   if none, all stacked calls are resumed
         */
        resume:function( call_ids , options ){
            self.send("resume", { call_ids : call_ids || [], options : options || undefined })
        },
        clearPausedCalls:function(){
            self.send("clearPausedCalls")
        },
        clearStorage:function(){
            self.send("clearStorage")
        },
        handleEvent:function(json){
            cobalt.log('received webservices plugin event', json)
            var data = ( json && json.data ) ? json.data : undefined;
            if (data && data.callId && this.calls[data.callId]){
                var concernedCall = this.calls[data.callId];
                switch (json.action){
                    case "onWSError":
                        if (concernedCall.errorCallback){
                            concernedCall.errorCallback( data.data || data.text, data.statusCode, concernedCall )
                        }else{
                            cobalt.log('WS error : No JS error callback for call ' + data.callId)
                        }
                        break;
                    case "onWSResult":
                        if (concernedCall.successCallback){
                            concernedCall.successCallback( data.data || data.text, data.statusCode, concernedCall )
                        }else{
                            cobalt.log('WS success but no JS callback for call ' + data.callId)
                        }
                        break;
                    case "onStorageResult":
                        if (concernedCall.cacheCallback){
                            concernedCall.cacheCallback( data.data || data.text, concernedCall )
                        }else{
                            cobalt.log('Some data in storage but no JS callback for call '+ data.callId)
                        }
                        break;
                    case "onStorageError":
                        if (concernedCall.cacheError){
                            concernedCall.cacheError( data.data || data.text, concernedCall )
                        }else{
                            cobalt.log('Some data in storage but no JS callback for call '+ data.callId)
                        }
                        break;
                    default :
                        cobalt.log('WS unknown action received from native side for call '+ data.callId);

                }
            }else{
                cobalt.log('WS unknown call event for call ', json)
            }

        },
        send:function(action, data, callback){
            cobalt.send({ type : "plugin", name : "webservices", action : action, data : data }, callback);
        }
    };
    cobalt.plugins.register(plugin);

})(cobalt || {});
<|endoftext|>