<commit_before>const path = require('path')
if(process.env.NODE_ENV === "development") {
    const path_to_envs = path.resolve(path.join(__dirname, '..'), '.env')
    require('dotenv').config({path: path_to_envs})
}
const amqp = require('amqplib');
const bunyan = require('bunyan');
const assert = require('assert');
const uuidv1 = require('uuid/v1');
const logger = bunyan.createLogger({ name: 'tracker' });
const mq = process.env.RABBIT_URL;
const q = 'analyses_queue';
let ch;
let db;
const npm_registry = require('nano')('https://skimdb.npmjs.com/registry');
const Octokit = require('@octokit/rest')
const octokit = new Octokit({
    auth: `token ${process.env.GITHUB_TOKEN}`
});
const request = require('request-promise');
const Promise = require('bluebird');
Promise.config({
    // Enable cancellation
    cancellation: true,
});
const mkdirp = require('mkdirp');
// const pid = uuidv1();
const pid = process.env.PID || process.argv[2];
const dest = `./downloads-${pid}`;
const fs = require('fs');
const targz = require('targz');
const jssa = Promise.promisifyAll(require('jssa'));
const afs = Promise.promisifyAll(require('fs'));
const glob = require('globby');
const _ = require('lodash');
const shell = require('shelljs');
const MongoClient = require('mongodb').MongoClient;
// Connection URL
const url = process.env.MONGODB_URL;
console.log(url)
const dbName = 'npmminer';
const rimraf = require('rimraf');
const timeout = 50000;

MongoClient.connect(url).then((client) => {
    db = client.db(dbName);
    logger.info("Connected successfully to server");
    const collection = db.collection('packages');
    return collection.createIndex({ name : "hashed" });
}).then((result) => {
    logger.info(result);
    return amqp.connect(mq);
}).catch(err => {
    console.error(err)
    logger.error(`1: ${err}`);
}).then(conn => {
    return conn.createChannel();
}).catch(err => {
    console.error(err)
    logger.error(`1: ${err}`);
}).then(channel => {
    ch = channel;
    return ch.assertQueue(q, {durable: true, arguments: {
        "x-message-ttl" : 540000
    }});
}).catch(err => {
    console.error(err)
    logger.error(`1: ${err}`);
}).then(() => {
    ch.prefetch(1);
    return ch.consume(q, msg => {
        const job = JSON.parse(msg.content.toString());
        return work(job, ch, msg, db);
    });
}).catch(err => {
    console.error(err)
    logger.error(`1: ${err}`);
}).finally(() => {
    // db.close();
})

function createGlobbyPattern(localPath, ignores) {
    const ignoreArray = _.map(ignores, ignore => `!${localPath}/${ignore}`);
    return [`${localPath}/**/*.js`].concat(ignoreArray);
}

function work(job, channel, msg, db) {
    logger.info(`[1] Got job for package: ${job.package_name}`);
    return new Promise((resolve, reject) => {
        const package = {};
        npm_registry.get(job.package_name).then(doc => {
            package.id = doc._id;
            package.name = doc.name;
            package.processing_date = Date.now();
            // package.latest_package_json = doc.versions[doc['dist-tags'].latest];
            package.dependencies = doc.versions[doc['dist-tags'].latest].dependencies;
            package.devDependencies = doc.versions[doc['dist-tags'].latest].devDependencies;
            let analysis;
            let localPath;
            let paths;
            logger.info(process.argv);
            logger.info(`[2] Retrieved from npm: ${doc._id}`);
            if(doc.name &&
                doc.name === job.package_name &&
                doc.repository &&
                doc.repository.url &&
                new RegExp(
                    /[\/][\/]github[\.]com[\/][a-zA-Z0-9\-]+[\/][a-zA-Z0-9\-]+/g
                ).test(doc.repository.url)) {
                const github_repository = `https:${doc.repository.url.match(
                    /[\/][\/]github[\.]com[\/][a-zA-Z0-9\-]+[\/][a-zA-Z0-9\-]+/g
                )[0]}`;
                package.github_repository = github_repository;
                // @TODO check here if it exists in the DB
                let split = package.github_repository.split('/');
                let user = split[3];
                let repo = split[4];
                const remote_tasks = [];
                remote_tasks.push(
                    request({
                        url: `https://api.npms.io/v2/package/${package.name}`,
                        json: true
                    })
                );
                remote_tasks.push(
                    octokit.repos.get({
                        owner: user,
                        repo: repo
                    })
                );
                Promise.all(remote_tasks).then(res => {
                    const npmsio = res[0];
                    const github = res[1];
                    logger.info(`[3] The score is  ${npmsio.score.final}`);
                    package.npmsio = npmsio;
                    logger.info(`[4] Stars ${user}/${repo}: ${github.data.stargazers_count}`);
                    if (
                        github.data.html_url.includes(user) &&
                        github.data.html_url.includes(repo)
                    ) {
                        package.stars = github.data.stargazers_count;
                        logger.info(`[5] Store package ${package.name} with a repo of ${github.data.stargazers_count} GitHub stars!`);
                    } else {
                        package.issue = 'github-redirect'
                    }
                    rimraf.sync(dest);
                    mkdirp.sync(dest);
                    const url = package.latest_package_json.dist.tarball;
                    logger.info(`[6] Downloading tarball from: ${url}`);
                    let filename = url.substr(url.lastIndexOf('/'));
                    const tarzball = path.join(dest, filename);
                    const targetDir = path.join(dest, filename.slice(0, -4));
                    localPath = targetDir;
                    return new Promise((resolve, reject) => {
                        request(url)
                        .pipe(fs.createWriteStream(tarzball))
                        .on('error', function(err) {
                            console.log('error 1');
                            console.log(err);
                            reject(callback());
                        })
                        .on('end', () => {
                            console.log('the end');
                        })
                        .on('finish', function() {
                            targz.decompress(
                            {
                                src: tarzball,
                                dest: targetDir
                            },
                            function(err) {
                                if (err) {
                                    console.log(err);
                                    return reject('error 2');
                                } else {
                                    console.log('Done!');
                                    return resolve('Job done!');
                                }
                            });
                        });
                    });
                }).then(() => {
                    return afs.readFileAsync(path.join(__dirname, 'ignores.json'));
                })
                .then((ignoresFile) => {
                  const json = JSON.parse(ignoresFile);
                  ignores = json.ignore;
                  return glob(createGlobbyPattern(localPath, ignores), { nodir: true });
                }).then(filepaths => {
                    paths = filepaths;
                    logger.info(`[7] Files identified: ${paths.length}`);
                    package.numOfFiles = paths.length;
                    if (path.length > 1000) {
                        return reject('More than 1000 files');
                    } else {
                        package.paths = paths;
                        const directories = _.map(paths, path => {
                            return path.split('/').length - 4;
                        });
                        package.minDirDepth = _.min(directories);
                        package.maxDirDepth = _.max(directories);
                        package.sumDirDepth = _.sum(directories);
                        return _.chain(paths)
                            .map(file => {
                                const lines = shell
                                .exec(`wc -l ${file}`, { silent: true })
                                .stdout.trim()
                                .split(' ')[0];
                                // const name = file.substring(file.indexOf('/code/') + '/code/'.length);
                                const name = file;
                                logger.info(file);
                                return {
                                name,
                                lines: parseInt(lines, 10)
                                };
                            })
                            .sumBy('lines')
                            .value();
                    }
                }).then(lines => {
                    package.numOfLines = lines;
                    if (lines > 1000000) {
                        return reject('More than 1000 files');
                    } else {
                        logger.info(`Number of lines: ${lines}`);
                        logger.info('[8] eslint analysis');
                        package.eslint = {};
                        // Wrapping it as a bluebird Promise to have the cancel() function
                        analysis = Promise.resolve(jssa.analyze_eslint(paths));
                        return Promise.race([
                            analysis,
                            new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
                        ]);
                    }
                }).then(report => {
                    package.eslint.message = 'completed';
                    package.eslint.errorCount = report.eslint.errorCount;
                    package.eslint.warningCount = report.eslint.warningCount;
                    const typesAndCounts = _.chain(report.eslint.results)
                    .map((result) => {
                        const errorTypes = _.values(_.reduce(result.messages, (result, obj) => {
                        const type = obj.ruleId;
                        result[type] = {
                          type,
                          count: 1 + (result[type] ? result[type].count : 0),
                        };
                        return result;
                      }, {}));
                      return errorTypes;
                    })
                    .flattenDeep()
                    .groupBy('type')
                    .map((objs, key) => ({
                    'type': key,
                    'count': _.sumBy(objs, 'count') }))
                    .keyBy('type')
                    .mapValues('count')
                    .value();
                    if(_.isEmpty(typesAndCounts)) {
                        package.eslint.typesAndCounts = null;
                    } else {
                        package.eslint.typesAndCounts = typesAndCounts;
                    }
                    logger.info(typesAndCounts);
                    logger.info(report.eslint.errorCount);
                    logger.info(report.eslint.warningCount);
                    return resolve('OK');
                }).catch(err => {
                    logger.error(`2: ${err}`);
                    package.error2 = err;
                    logger.error('eslint issue');
                    analysis.cancel();
                    package.eslint.message = 'eslint-not-completed';
                    return resolve('OK');
                }).then(() => {
                    logger.info('[9] escomplex analysis');
                    package.escomplex = {};
                    analysis = Promise.resolve(jssa.analyze_escomplex(paths));
                    return Promise.race([
                        analysis,
                        new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
                    ]);
                }).then(report => {
                    package.escomplex.message = 'completed';
                    package.escomplex.tlocp = _.sumBy(
                        report.escomplex.reports,
                        o => o.aggregate.sloc.physical
                      );
                    package.escomplex.tlocl = _.sumBy(report.escomplex.reports, o => o.aggregate.sloc.logical);
                    package.escomplex.firstOrderDensity=report.escomplex.firstOrderDensity,
                    package.escomplex.changeCost=report.escomplex.changeCost,
                    package.escomplex.coreSize=report.escomplex.coreSize,
                    package.escomplex.loc=report.escomplex.loc,
                    package.escomplex.cyclomatic=report.escomplex.cyclomatic,
                    package.escomplex.effort=report.escomplex.effort,
                    package.escomplex.params=report.escomplex.params,
                    package.escomplex.maintainability=report.escomplex.maintainability,
                    logger.info(package.escomplex.tlocl);
                    return resolve('OK');
                }).catch(err => {
                    logger.error(`3: ${err}`);
                    logger.error('escomplex issue');
                    package.error3 = err;
                    analysis.cancel();
                    package.escomplex.message = 'escomplex-not-completed';
                    return resolve('OK');
                }).then(() => {
                    logger.info('[10] npm audit analysis');
                    package.npmaudit = {};
                    let pathToPackage = path.join(__dirname, localPath,'package')
                    logger.info(pathToPackage);
                    shell.exec(`npm --prefix ${pathToPackage} --package-lock-only install`, { silent: true })
                    analysis = Promise.resolve(jssa.analyze_npmaudit(pathToPackage));
                    return Promise.race([
                        analysis,
                        new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
                    ]);
                }).then(report => {
                    package.npmaudit.message = 'completed';
                    package.npmaudit.results = report.npmaudit;
                    logger.info(package.npmaudit.results.actions.length);
                    return resolve('OK');
                }).catch(err => {
                    logger.error(`4: ${err}`);
                    logger.error('npmaudit issue');
                    package.error4 = err;
                    analysis.cancel();
                    package.npmaudit.message = 'npmaudit-not-completed';
                    return resolve('OK');
                }).then(() => {
                    logger.info('[11] jsinspect analysis');
                    package.jsinspect = {};
                    analysis = Promise.resolve(jssa.analyze_jsinspect(paths));
                    return Promise.race([
                        analysis,
                        new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
                    ]);
                }).then(report => {
                    package.jsinspect.message = 'completed';
                    package.jsinspect.duplicates = report.jsinspect.length;
                    logger.info(package.jsinspect.duplicates);
                    return resolve('OK');
                }).catch(err => {
                    logger.error(`5: ${err}`);
                    logger.error('jsinspect issue');
                    package.error5 = err;
                    analysis.cancel();
                    package.jsinspect.message = 'jsinspect-not-completed';
                    return resolve('OK');
                // }).then(() => {
                //     logger.info('[12] sonarjs analysis');
                //     package.sonarjs = {};
                //     analysis = Promise.resolve(jssa.analyze_sonarjs(path.join(localPath,'package')));
                //     return Promise.race([
                //         analysis,
                //         new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
                //     ]);
                // }).then(report => {
                //     package.sonarjs.message = 'completed';
                //     package.sonarjs.issues = report.sonarjs.length;
                //     package.sonarjs.blockerCount = _.sumBy(report.sonarjs, i => (i.severity === 'BLOCKER' ? 1 : 0));
                //     package.sonarjs.criticalCount = _.sumBy(report.sonarjs, i => (i.severity === 'CRITICAL' ? 1 : 0));
                //     package.sonarjs.majorCount = _.sumBy(report.sonarjs, i => (i.severity === 'MAJOR' ? 1 : 0));
                //     package.sonarjs.minorCount = _.sumBy(report.sonarjs, i => (i.severity === 'MINOR' ? 1 : 0));
                //     package.sonarjs.infoCount = _.sumBy(report.sonarjs, i => (i.severity === 'INFO' ? 1 : 0));

                //     logger.info(package.sonarjs.issues);
                //     return resolve('OK');
                // }).catch(err => {
                //     logger.error(`6: ${err}`);
                //     logger.error('sonarjs issue');
                //     package.error6 = err;
                //     analysis.cancel();
                //     package.sonarjs.message = 'sonarjs-not-completed';
                //     return resolve('OK');
                }).then(() => {
                    logger.info('[13] analyses completed');
                    rimraf.sync(dest);
                    return resolve('OK');
                }).catch(err => {
                    logger.error(`7: ${err}`);
                    package.error7 = err;
                }).finally(() => {
                    channel.ack(msg);
                    const col = db.collection('packages');
                    logger.info('[14] Document upserted');
                    return col.findOneAndReplace({name: package.name}, package, { upsert: true });
                })
            } else {
                logger.info(`No github repo identified`);
                package.error1 = 'no-github-repo-identified';
                channel.ack(msg);
                const col = db.collection('packages');
                logger.info('[14] Document upserted');
                return col.findOneAndReplace({name: package.name}, package, { upsert: true });
            }
        }).catch(err => {
            logger.error(`8: ${err}`);
            const col = db.collection('packages');
            package.error8 = err;
            logger.info('[14] Document upserted');
            return col.findOneAndReplace({name: job.package_name}, package, { upsert: true });
        });
    });
}<commit_msg>Fix tarball<commit_after>const path = require('path')
if(process.env.NODE_ENV === "development") {
    const path_to_envs = path.resolve(path.join(__dirname, '..'), '.env')
    require('dotenv').config({path: path_to_envs})
}
const amqp = require('amqplib');
const bunyan = require('bunyan');
const assert = require('assert');
const uuidv1 = require('uuid/v1');
const logger = bunyan.createLogger({ name: 'tracker' });
const mq = process.env.RABBIT_URL;
const q = 'analyses_queue';
let ch;
let db;
const npm_registry = require('nano')('https://skimdb.npmjs.com/registry');
const Octokit = require('@octokit/rest')
const octokit = new Octokit({
    auth: `token ${process.env.GITHUB_TOKEN}`
});
const request = require('request-promise');
const Promise = require('bluebird');
Promise.config({
    // Enable cancellation
    cancellation: true,
});
const mkdirp = require('mkdirp');
// const pid = uuidv1();
const pid = process.env.PID || process.argv[2];
const dest = `./downloads-${pid}`;
const fs = require('fs');
const targz = require('targz');
const jssa = Promise.promisifyAll(require('jssa'));
const afs = Promise.promisifyAll(require('fs'));
const glob = require('globby');
const _ = require('lodash');
const shell = require('shelljs');
const MongoClient = require('mongodb').MongoClient;
// Connection URL
const url = process.env.MONGODB_URL;
console.log(url)
const dbName = 'npmminer';
const rimraf = require('rimraf');
const timeout = 50000;

MongoClient.connect(url).then((client) => {
    db = client.db(dbName);
    logger.info("Connected successfully to server");
    const collection = db.collection('packages');
    return collection.createIndex({ name : "hashed" });
}).then((result) => {
    logger.info(result);
    return amqp.connect(mq);
}).catch(err => {
    console.error(err)
    logger.error(`1: ${err}`);
}).then(conn => {
    return conn.createChannel();
}).catch(err => {
    console.error(err)
    logger.error(`1: ${err}`);
}).then(channel => {
    ch = channel;
    return ch.assertQueue(q, {durable: true, arguments: {
        "x-message-ttl" : 540000
    }});
}).catch(err => {
    console.error(err)
    logger.error(`1: ${err}`);
}).then(() => {
    ch.prefetch(1);
    return ch.consume(q, msg => {
        const job = JSON.parse(msg.content.toString());
        return work(job, ch, msg, db);
    });
}).catch(err => {
    console.error(err)
    logger.error(`1: ${err}`);
}).finally(() => {
    // db.close();
})

function createGlobbyPattern(localPath, ignores) {
    const ignoreArray = _.map(ignores, ignore => `!${localPath}/${ignore}`);
    return [`${localPath}/**/*.js`].concat(ignoreArray);
}

function work(job, channel, msg, db) {
    logger.info(`[1] Got job for package: ${job.package_name}`);
    return new Promise((resolve, reject) => {
        const package = {};
        npm_registry.get(job.package_name).then(doc => {
            package.id = doc._id;
            package.name = doc.name;
            package.processing_date = Date.now();
            package.tarball = doc.versions[doc['dist-tags'].latest].dist.tarball;
            package.dependencies = doc.versions[doc['dist-tags'].latest].dependencies;
            package.devDependencies = doc.versions[doc['dist-tags'].latest].devDependencies;
            let analysis;
            let localPath;
            let paths;
            logger.info(process.argv);
            logger.info(`[2] Retrieved from npm: ${doc._id}`);
            if(doc.name &&
                doc.name === job.package_name &&
                doc.repository &&
                doc.repository.url &&
                new RegExp(
                    /[\/][\/]github[\.]com[\/][a-zA-Z0-9\-]+[\/][a-zA-Z0-9\-]+/g
                ).test(doc.repository.url)) {
                const github_repository = `https:${doc.repository.url.match(
                    /[\/][\/]github[\.]com[\/][a-zA-Z0-9\-]+[\/][a-zA-Z0-9\-]+/g
                )[0]}`;
                package.github_repository = github_repository;
                // @TODO check here if it exists in the DB
                let split = package.github_repository.split('/');
                let user = split[3];
                let repo = split[4];
                const remote_tasks = [];
                remote_tasks.push(
                    request({
                        url: `https://api.npms.io/v2/package/${package.name}`,
                        json: true
                    })
                );
                remote_tasks.push(
                    octokit.repos.get({
                        owner: user,
                        repo: repo
                    })
                );
                Promise.all(remote_tasks).then(res => {
                    const npmsio = res[0];
                    const github = res[1];
                    logger.info(`[3] The score is  ${npmsio.score.final}`);
                    package.npmsio = npmsio;
                    logger.info(`[4] Stars ${user}/${repo}: ${github.data.stargazers_count}`);
                    if (
                        github.data.html_url.includes(user) &&
                        github.data.html_url.includes(repo)
                    ) {
                        package.stars = github.data.stargazers_count;
                        logger.info(`[5] Store package ${package.name} with a repo of ${github.data.stargazers_count} GitHub stars!`);
                    } else {
                        package.issue = 'github-redirect'
                    }
                    rimraf.sync(dest);
                    mkdirp.sync(dest);
                    const url = package.tarball;
                    logger.info(`[6] Downloading tarball from: ${url}`);
                    let filename = url.substr(url.lastIndexOf('/'));
                    const tarzball = path.join(dest, filename);
                    const targetDir = path.join(dest, filename.slice(0, -4));
                    localPath = targetDir;
                    return new Promise((resolve, reject) => {
                        request(url)
                        .pipe(fs.createWriteStream(tarzball))
                        .on('error', function(err) {
                            console.log('error 1');
                            console.log(err);
                            reject(callback());
                        })
                        .on('end', () => {
                            console.log('the end');
                        })
                        .on('finish', function() {
                            targz.decompress(
                            {
                                src: tarzball,
                                dest: targetDir
                            },
                            function(err) {
                                if (err) {
                                    console.log(err);
                                    return reject('error 2');
                                } else {
                                    console.log('Done!');
                                    return resolve('Job done!');
                                }
                            });
                        });
                    });
                }).then(() => {
                    return afs.readFileAsync(path.join(__dirname, 'ignores.json'));
                })
                .then((ignoresFile) => {
                  const json = JSON.parse(ignoresFile);
                  ignores = json.ignore;
                  return glob(createGlobbyPattern(localPath, ignores), { nodir: true });
                }).then(filepaths => {
                    paths = filepaths;
                    logger.info(`[7] Files identified: ${paths.length}`);
                    package.numOfFiles = paths.length;
                    if (path.length > 1000) {
                        return reject('More than 1000 files');
                    } else {
                        package.paths = paths;
                        const directories = _.map(paths, path => {
                            return path.split('/').length - 4;
                        });
                        package.minDirDepth = _.min(directories);
                        package.maxDirDepth = _.max(directories);
                        package.sumDirDepth = _.sum(directories);
                        return _.chain(paths)
                            .map(file => {
                                const lines = shell
                                .exec(`wc -l ${file}`, { silent: true })
                                .stdout.trim()
                                .split(' ')[0];
                                // const name = file.substring(file.indexOf('/code/') + '/code/'.length);
                                const name = file;
                                logger.info(file);
                                return {
                                name,
                                lines: parseInt(lines, 10)
                                };
                            })
                            .sumBy('lines')
                            .value();
                    }
                }).then(lines => {
                    package.numOfLines = lines;
                    if (lines > 1000000) {
                        return reject('More than 1000 files');
                    } else {
                        logger.info(`Number of lines: ${lines}`);
                        logger.info('[8] eslint analysis');
                        package.eslint = {};
                        // Wrapping it as a bluebird Promise to have the cancel() function
                        analysis = Promise.resolve(jssa.analyze_eslint(paths));
                        return Promise.race([
                            analysis,
                            new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
                        ]);
                    }
                }).then(report => {
                    package.eslint.message = 'completed';
                    package.eslint.errorCount = report.eslint.errorCount;
                    package.eslint.warningCount = report.eslint.warningCount;
                    const typesAndCounts = _.chain(report.eslint.results)
                    .map((result) => {
                        const errorTypes = _.values(_.reduce(result.messages, (result, obj) => {
                        const type = obj.ruleId;
                        result[type] = {
                          type,
                          count: 1 + (result[type] ? result[type].count : 0),
                        };
                        return result;
                      }, {}));
                      return errorTypes;
                    })
                    .flattenDeep()
                    .groupBy('type')
                    .map((objs, key) => ({
                    'type': key,
                    'count': _.sumBy(objs, 'count') }))
                    .keyBy('type')
                    .mapValues('count')
                    .value();
                    if(_.isEmpty(typesAndCounts)) {
                        package.eslint.typesAndCounts = null;
                    } else {
                        package.eslint.typesAndCounts = typesAndCounts;
                    }
                    logger.info(typesAndCounts);
                    logger.info(report.eslint.errorCount);
                    logger.info(report.eslint.warningCount);
                    return resolve('OK');
                }).catch(err => {
                    logger.error(`2: ${err}`);
                    package.error2 = err;
                    logger.error('eslint issue');
                    analysis.cancel();
                    package.eslint.message = 'eslint-not-completed';
                    return resolve('OK');
                }).then(() => {
                    logger.info('[9] escomplex analysis');
                    package.escomplex = {};
                    analysis = Promise.resolve(jssa.analyze_escomplex(paths));
                    return Promise.race([
                        analysis,
                        new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
                    ]);
                }).then(report => {
                    package.escomplex.message = 'completed';
                    package.escomplex.tlocp = _.sumBy(
                        report.escomplex.reports,
                        o => o.aggregate.sloc.physical
                      );
                    package.escomplex.tlocl = _.sumBy(report.escomplex.reports, o => o.aggregate.sloc.logical);
                    package.escomplex.firstOrderDensity=report.escomplex.firstOrderDensity,
                    package.escomplex.changeCost=report.escomplex.changeCost,
                    package.escomplex.coreSize=report.escomplex.coreSize,
                    package.escomplex.loc=report.escomplex.loc,
                    package.escomplex.cyclomatic=report.escomplex.cyclomatic,
                    package.escomplex.effort=report.escomplex.effort,
                    package.escomplex.params=report.escomplex.params,
                    package.escomplex.maintainability=report.escomplex.maintainability,
                    logger.info(package.escomplex.tlocl);
                    return resolve('OK');
                }).catch(err => {
                    logger.error(`3: ${err}`);
                    logger.error('escomplex issue');
                    package.error3 = err;
                    analysis.cancel();
                    package.escomplex.message = 'escomplex-not-completed';
                    return resolve('OK');
                }).then(() => {
                    logger.info('[10] npm audit analysis');
                    package.npmaudit = {};
                    let pathToPackage = path.join(__dirname, localPath,'package')
                    logger.info(pathToPackage);
                    shell.exec(`npm --prefix ${pathToPackage} --package-lock-only install`, { silent: true })
                    analysis = Promise.resolve(jssa.analyze_npmaudit(pathToPackage));
                    return Promise.race([
                        analysis,
                        new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
                    ]);
                }).then(report => {
                    package.npmaudit.message = 'completed';
                    package.npmaudit.results = report.npmaudit;
                    logger.info(package.npmaudit.results.actions.length);
                    return resolve('OK');
                }).catch(err => {
                    logger.error(`4: ${err}`);
                    logger.error('npmaudit issue');
                    package.error4 = err;
                    analysis.cancel();
                    package.npmaudit.message = 'npmaudit-not-completed';
                    return resolve('OK');
                }).then(() => {
                    logger.info('[11] jsinspect analysis');
                    package.jsinspect = {};
                    analysis = Promise.resolve(jssa.analyze_jsinspect(paths));
                    return Promise.race([
                        analysis,
                        new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
                    ]);
                }).then(report => {
                    package.jsinspect.message = 'completed';
                    package.jsinspect.duplicates = report.jsinspect.length;
                    logger.info(package.jsinspect.duplicates);
                    return resolve('OK');
                }).catch(err => {
                    logger.error(`5: ${err}`);
                    logger.error('jsinspect issue');
                    package.error5 = err;
                    analysis.cancel();
                    package.jsinspect.message = 'jsinspect-not-completed';
                    return resolve('OK');
                // }).then(() => {
                //     logger.info('[12] sonarjs analysis');
                //     package.sonarjs = {};
                //     analysis = Promise.resolve(jssa.analyze_sonarjs(path.join(localPath,'package')));
                //     return Promise.race([
                //         analysis,
                //         new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
                //     ]);
                // }).then(report => {
                //     package.sonarjs.message = 'completed';
                //     package.sonarjs.issues = report.sonarjs.length;
                //     package.sonarjs.blockerCount = _.sumBy(report.sonarjs, i => (i.severity === 'BLOCKER' ? 1 : 0));
                //     package.sonarjs.criticalCount = _.sumBy(report.sonarjs, i => (i.severity === 'CRITICAL' ? 1 : 0));
                //     package.sonarjs.majorCount = _.sumBy(report.sonarjs, i => (i.severity === 'MAJOR' ? 1 : 0));
                //     package.sonarjs.minorCount = _.sumBy(report.sonarjs, i => (i.severity === 'MINOR' ? 1 : 0));
                //     package.sonarjs.infoCount = _.sumBy(report.sonarjs, i => (i.severity === 'INFO' ? 1 : 0));

                //     logger.info(package.sonarjs.issues);
                //     return resolve('OK');
                // }).catch(err => {
                //     logger.error(`6: ${err}`);
                //     logger.error('sonarjs issue');
                //     package.error6 = err;
                //     analysis.cancel();
                //     package.sonarjs.message = 'sonarjs-not-completed';
                //     return resolve('OK');
                }).then(() => {
                    logger.info('[13] analyses completed');
                    rimraf.sync(dest);
                    return resolve('OK');
                }).catch(err => {
                    logger.error(`7: ${err}`);
                    package.error7 = err;
                }).finally(() => {
                    channel.ack(msg);
                    const col = db.collection('packages');
                    logger.info('[14] Document upserted');
                    return col.findOneAndReplace({name: package.name}, package, { upsert: true });
                })
            } else {
                logger.info(`No github repo identified`);
                package.error1 = 'no-github-repo-identified';
                channel.ack(msg);
                const col = db.collection('packages');
                logger.info('[14] Document upserted');
                return col.findOneAndReplace({name: package.name}, package, { upsert: true });
            }
        }).catch(err => {
            logger.error(`8: ${err}`);
            const col = db.collection('packages');
            package.error8 = err;
            logger.info('[14] Document upserted');
            return col.findOneAndReplace({name: job.package_name}, package, { upsert: true });
        });
    });
}<|endoftext|>


<commit_before>//Inspiration from http://gaarf.info/2013/06/25/securing-stripe-webhooks-with-node-js/

module.exports = function (config) {

  var stripe = require('stripe')(config.secret),
    models = require('../../models'),
    stripeTransactions = {
      'unhandled':          require('./unhandled.js'),
      'charge.succeeded':   require('./charge.succeeded.js')
    };

  return {

    authEvent: function(req, res, next) {

      if (req.body.object !== 'event') {
        return res.send(400); // invalid data
      }

      stripe.events.retrieve(req.body.id, function(err, event) {

        // err = invalid event, !event = error from stripe
        if (err || !event) {
          return res.send(401);
        }

        req.stripeEvent = event;
        next();

      });

    },

    handleTransaction: function(req, res) {

      var event = req.stripeEvent,
          data = event.data.object;

      // takes care of unexpected event types
      var transactionMethod = stripeTransactions[event.type] || stripeTransactions.unhandled;

      transactionMethod(data, function(err){
        if ( !err ) {
          res.send(200);
        }
      });

    },

    handleSubscription: function(req, res) {
      var user = req.session.user,
          stripeToken = req.body.stripeToken;
      if (!user) {
        // please login before subscribing to jsbin
        // TODO
      }

      stripe.customers.create({
        card: stripeToken,
        plan: 'test_pro'
      }).then(function (err, customer) {
        if (!err) {
          models.user.setProAccount(user.name, true, function(err) {
            if (!err) {
              req.session.user.pro = true;
              res.redirect('/');
            }
          });
          models.customer.setCustomer({
            user: user.name,
            stripeId: customer.id
          });
        }
      });

    }

  };
};
<commit_msg>updating customer creation fulfilment<commit_after>//Inspiration from http://gaarf.info/2013/06/25/securing-stripe-webhooks-with-node-js/

module.exports = function (config) {

  var stripe = require('stripe')(config.secret),
    models = require('../../models'),
    stripeTransactions = {
      'unhandled':                  require('./unhandled.js'),
      'charge.succeeded':           require('./charge.succeeded.js'),
      'invoice.payment_succeeded':  require('./invoice.payment_succeeded.js')
    };

  return {

    authEvent: function(req, res, next) {

      if (req.body.object !== 'event') {
        return res.send(400); // invalid data
      }

      stripe.events.retrieve(req.body.id, function(err, event) {

        // err = invalid event, !event = error from stripe
        if (err || !event) {
          return res.send(401);
        }

        req.stripeEvent = event;
        next();

      });

    },

    handleTransaction: function(req, res) {

      var event = req.stripeEvent,
          data = event.data.object;

      // takes care of unexpected event types
      var transactionMethod = stripeTransactions[event.type] || stripeTransactions.unhandled;

      transactionMethod(data, function(err){
        if ( !err ) {
          res.send(200);
        }
      });

    },

    handleSubscription: function(req, res) {
      var user = req.session.user,
          stripeToken = req.body.stripeToken;
      if (!user) {
        // please login before subscribing to jsbin
        // TODO
      }

      stripe.customers.create({
        card: stripeToken,
        plan: 'test_pro'
      }).then(function (customer) {

        models.user.setProAccount(user.name, true, function(err) {
          if (!err) {
            req.session.user.pro = true;
            req.flash('notification', 'Welcome to the pro user lounge. Your seat is waiting');
          } else {
            req.flash('error', 'Something went wrong, please try signing in and out again');
          }
          res.redirect('/');
        });

        models.customer.setCustomer({
          user: user.name,
          stripeId: customer.id
        });

      }, function(err) {
        // error with customer creation
        err;
      });

    }

  };
};
<|endoftext|>


<commit_before>'use babel';

import core from 'core-js/library';
const { find } = core.Array.prototype;

const disposables = [];

const Lang = (rLangScope, openCommentToken, closeCommentToken) => ({
  test: (scope) => rLangScope.test(scope),
  commentTokens: { open: openCommentToken, close: closeCommentToken },
});
const langs = [
  Lang(/^source\.js\.?/ , '/*'  , '*/' ),
  Lang(/^source\.css\.?/, '/*'  , '*/' ),
  Lang(/^text\.html\.php?/ , '/*'  , '*/'),
  Lang(/^text\.html\.?/ , '<!--', '-->'),
];

export function activate() {
  disposables.push(atom.commands.add('atom-text-editor:not([mini])', { 'sublime-block-comment:toggle': toggle }));
}

export function deactivate() {
  for (const disposable of disposables) disposable.dispose();
  disposables.length = 0;
}

function toggle() {
  const editor = atom.workspace.getActiveTextEditor();
  if (!editor) return;

  const buffer = editor.getBuffer();

  buffer.transact(() => {
    for (const selection of editor.getSelectionsOrderedByBufferPosition().reverse()) {
      const range = selection.getBufferRange();
      const textInRange = buffer.getTextInRange(range);
      const scopes = getPositionScopes(range.start).reverse();

      let lang;
      if (!scopes.some((scope) => lang = langs::find((lang) => lang.test(scope)))) lang = langs[0];
      const commentTokens = lang.commentTokens;

      // If we are inside a block comment or have one fully or partially selected, uncomment it.
      if (
        (isInsideBlockComment(range.start) || isAtCloseCommentToken(range.start, commentTokens.close))
        && (isInsideBlockComment(range.end) || isAtCloseCommentToken(range.end, commentTokens.close))
        && ~[-1, textInRange.length - commentTokens.close.length].indexOf(textInRange.indexOf(commentTokens.close))
      ) {
        let blockCommentCloseRange;
        const lastRow = buffer.getLastRow();
        for (let row = range.end.row; !blockCommentCloseRange && row <= lastRow; row++) {
          const line = buffer.lineForRow(row);
          for (
            let column = row === range.end.row ? Math.max(range.end.column - commentTokens.close.length, 0) : 0;
            (column = line.indexOf(commentTokens.close, column)) !== -1;
            column++
          ) {
            if (isCommentDefinitionPunctuation([row, column])) {
              blockCommentCloseRange = [[row, column], [row, column + commentTokens.close.length]];
              break;
            }
          }
        }

        let blockCommentOpenRange;
        for (let row = range.start.row; !blockCommentOpenRange && row >= 0; row--) {
          const line = buffer.lineForRow(row);
          for (
            let column = row === range.start.row
              ? (
                blockCommentCloseRange && row === blockCommentCloseRange[0][0]
                  ? blockCommentCloseRange[0][1]
                  : Math.min(range.start.column + commentTokens.open.length, line.length)
              )
              : line.length;
            (column = line.lastIndexOf(commentTokens.open, column)) !== -1;
            column--
          ) {
            if (isCommentDefinitionPunctuation([row, column])) {
              blockCommentOpenRange = [[row, column], [row, column + commentTokens.open.length]];
              break;
            }
          }
        }

        if (blockCommentCloseRange) buffer.delete(blockCommentCloseRange);
        if (blockCommentOpenRange) buffer.delete(blockCommentOpenRange);

        continue;
      }

      // Else, wrap selection with block comment.
      buffer.insert(range.end, commentTokens.close);
      buffer.insert(range.start, commentTokens.open);

      // Unselect the opening and closing comment tokens.
      const startRowColumnOffset = commentTokens.open.length;
      selection.setBufferRange([
        [range.start.row, range.start.column + startRowColumnOffset],
        [range.end.row, range.end.column + (range.start.row === range.end.row ? startRowColumnOffset : 0)]
      ]);
    }
  });

  function isInsideBlockComment(position) {
    return getPositionScopes(position).some((scope) => scope.startsWith('comment.block.'));
  }

  function isCommentDefinitionPunctuation(position) {
    return getPositionScopes(position).some((scope) => scope.startsWith('punctuation.definition.comment.'));
  }

  function getPositionScopes(position) {
    return editor.scopeDescriptorForBufferPosition(position).getScopesArray();
  }

  function isAtCloseCommentToken(position, closeCommentToken) {
    return position.column >= closeCommentToken.length
      && buffer.getTextInRange([[position.row, position.column - closeCommentToken.length], position]) === closeCommentToken
      && isCommentDefinitionPunctuation([position.row, position.column - 1]);
  }
}
<commit_msg>code style<commit_after>'use babel';

import core from 'core-js/library';
const { find } = core.Array.prototype;

const disposables = [];

const Lang = (rLangScope, openCommentToken, closeCommentToken) => ({
  test: (scope) => rLangScope.test(scope),
  commentTokens: { open: openCommentToken, close: closeCommentToken },
});
const langs = [
  Lang(/^source\.js\.?/   , '/*'  , '*/' ),
  Lang(/^source\.css\.?/  , '/*'  , '*/' ),
  Lang(/^text\.html\.php?/, '/*'  , '*/' ),
  Lang(/^text\.html\.?/   , '<!--', '-->'),
];

export function activate() {
  disposables.push(atom.commands.add('atom-text-editor:not([mini])', { 'sublime-block-comment:toggle': toggle }));
}

export function deactivate() {
  for (const disposable of disposables) disposable.dispose();
  disposables.length = 0;
}

function toggle() {
  const editor = atom.workspace.getActiveTextEditor();
  if (!editor) return;

  const buffer = editor.getBuffer();

  buffer.transact(() => {
    for (const selection of editor.getSelectionsOrderedByBufferPosition().reverse()) {
      const range = selection.getBufferRange();
      const textInRange = buffer.getTextInRange(range);
      const scopes = getPositionScopes(range.start).reverse();

      let lang;
      if (!scopes.some((scope) => lang = langs::find((lang) => lang.test(scope)))) lang = langs[0];
      const commentTokens = lang.commentTokens;

      // If we are inside a block comment or have one fully or partially selected, uncomment it.
      if (
        (isInsideBlockComment(range.start) || isAtCloseCommentToken(range.start, commentTokens.close))
        && (isInsideBlockComment(range.end) || isAtCloseCommentToken(range.end, commentTokens.close))
        && ~[-1, textInRange.length - commentTokens.close.length].indexOf(textInRange.indexOf(commentTokens.close))
      ) {
        let blockCommentCloseRange;
        const lastRow = buffer.getLastRow();
        for (let row = range.end.row; !blockCommentCloseRange && row <= lastRow; row++) {
          const line = buffer.lineForRow(row);
          for (
            let column = row === range.end.row ? Math.max(range.end.column - commentTokens.close.length, 0) : 0;
            (column = line.indexOf(commentTokens.close, column)) !== -1;
            column++
          ) {
            if (isCommentDefinitionPunctuation([row, column])) {
              blockCommentCloseRange = [[row, column], [row, column + commentTokens.close.length]];
              break;
            }
          }
        }

        let blockCommentOpenRange;
        for (let row = range.start.row; !blockCommentOpenRange && row >= 0; row--) {
          const line = buffer.lineForRow(row);
          for (
            let column = row === range.start.row
              ? (
                blockCommentCloseRange && row === blockCommentCloseRange[0][0]
                  ? blockCommentCloseRange[0][1]
                  : Math.min(range.start.column + commentTokens.open.length, line.length)
              )
              : line.length;
            (column = line.lastIndexOf(commentTokens.open, column)) !== -1;
            column--
          ) {
            if (isCommentDefinitionPunctuation([row, column])) {
              blockCommentOpenRange = [[row, column], [row, column + commentTokens.open.length]];
              break;
            }
          }
        }

        if (blockCommentCloseRange) buffer.delete(blockCommentCloseRange);
        if (blockCommentOpenRange) buffer.delete(blockCommentOpenRange);

        continue;
      }

      // Else, wrap selection with block comment.
      buffer.insert(range.end, commentTokens.close);
      buffer.insert(range.start, commentTokens.open);

      // Unselect the opening and closing comment tokens.
      const startRowColumnOffset = commentTokens.open.length;
      selection.setBufferRange([
        [range.start.row, range.start.column + startRowColumnOffset],
        [range.end.row, range.end.column + (range.start.row === range.end.row ? startRowColumnOffset : 0)]
      ]);
    }
  });

  function isInsideBlockComment(position) {
    return getPositionScopes(position).some((scope) => scope.startsWith('comment.block.'));
  }

  function isCommentDefinitionPunctuation(position) {
    return getPositionScopes(position).some((scope) => scope.startsWith('punctuation.definition.comment.'));
  }

  function getPositionScopes(position) {
    return editor.scopeDescriptorForBufferPosition(position).getScopesArray();
  }

  function isAtCloseCommentToken(position, closeCommentToken) {
    return position.column >= closeCommentToken.length
      && buffer.getTextInRange([[position.row, position.column - closeCommentToken.length], position]) === closeCommentToken
      && isCommentDefinitionPunctuation([position.row, position.column - 1]);
  }
}
<|endoftext|>


<commit_before>/*
 * Converts ember model attributes to sails model attributes and vice versa
 * Sails supports: string, text, integer, float, date, datetime, boolean, binary, array, json
 * Ember Data supports: string, number, boolean, and date
 */

module.exports = {
  toEmber: function(attributes){
    //create a deep copy so the original element does not get overwritten
    var attributesCopy = attributes.slice(0);
    for(i in attributesCopy) {
      var attrArray = attributesCopy[i].split(':');

      //if the given attribute does not have a colon, ignore
      if (attrArray.length > 1) {
        var attrType = attrArray.pop();
        switch (attrType) {
          case 'text':
            attrArray.push('string');
            break;
          case 'integer':
            attrArray.push('number');
            break;
          case 'float':
            attrArray.push('number');
            break;
          case 'datetime':
            attrArray.push('date');
            break;
          case 'binary':
            // TODO(markus): Need testing if boolean is a possibility
            // attrArray.push('boolean');
            break;
          case 'array':
            //no proper equivalent on the ember side
            break;
          case 'json':
            //no proper equivalent on the ember side
            break;
          default:
            //add popped element back
            attrArray.push(attrType);
            break;
        }

        attributesCopy[i] = attrArray.join(':');
      }
    }
    return attributesCopy;
  },
  toSails: function(attributes){
    //create a deep copy so the original element does not get overwritten
    var attributesCopy = attributes.slice(0);
    for(i in attributesCopy) {
      var attrArray = attributesCopy[i].split(':');
      //if the given attribute does not have a colon, ignore
      if (attrArray.length > 1) {
        var attrType = attrArray.pop();

        if (attrType === 'number') {
          attrArray.push('float');
        } else {
          //add popped element back
          attrArray.push(attrType);
        }

        attributesCopy[i] = attrArray.join(':');
      }
    }

    return attributesCopy;
  }
};<commit_msg>boolean is a possibility: (see link to source)<commit_after>/*
 * Converts ember model attributes to sails model attributes and vice versa
 * Sails supports: string, text, integer, float, date, datetime, boolean, binary, array, json
 * Ember Data supports: string, number, boolean, and date
 */

module.exports = {
  toEmber: function(attributes){
    //create a deep copy so the original element does not get overwritten
    var attributesCopy = attributes.slice(0);
    for(i in attributesCopy) {
      var attrArray = attributesCopy[i].split(':');

      //if the given attribute does not have a colon, ignore
      if (attrArray.length > 1) {
        var attrType = attrArray.pop();
        switch (attrType) {
          case 'text':
            attrArray.push('string');
            break;
          case 'integer':
            attrArray.push('number');
            break;
          case 'float':
            attrArray.push('number');
            break;
          case 'datetime':
            attrArray.push('date');
            break;
          case 'binary':
            attrArray.push('boolean');
            break;
          case 'array':
            //no proper equivalent on the ember side
            break;
          case 'json':
            //no proper equivalent on the ember side
            break;
          default:
            //add popped element back
            attrArray.push(attrType);
            break;
        }

        attributesCopy[i] = attrArray.join(':');
      }
    }
    return attributesCopy;
  },
  toSails: function(attributes){
    //create a deep copy so the original element does not get overwritten
    var attributesCopy = attributes.slice(0);
    for(i in attributesCopy) {
      var attrArray = attributesCopy[i].split(':');
      //if the given attribute does not have a colon, ignore
      if (attrArray.length > 1) {
        var attrType = attrArray.pop();

        if (attrType === 'number') {
          attrArray.push('float');
        } else {
          //add popped element back
          attrArray.push(attrType);
        }

        attributesCopy[i] = attrArray.join(':');
      }
    }

    return attributesCopy;
  }
};
<|endoftext|>


<commit_before>function removeNode(node){
  node.parentElement.removeChild(node);
}

function markUnread(name){
  const buttom = document.getElementsByClassName("channel_buttom");
  for(var i=0;i<buttom.length;i++){
    if(buttom[i].getElementsByClassName("name")[0].innerHTML == name){
      if(buttom[i].className.split(" ").indexOf("unread") == -1){
         buttom[i].className += " unread";
      }
      return;
    }
  }
}

var StarGui = {
  initUserList : function(){
    var element = document.createElement("div");
    element.className = "user-list";
    document.getElementById("ulist-container").appendChild(element);
    return element;
  },

  initContextContainer : function(){
    const context = document.createElement("div");
    context.className = "context-container";
    document.getElementById("pageContainer").appendChild(context);
    return context;
  },

  appendMessage : function(page, time, avatar, nick, message){
    if(page.system.isFocus(page.name)){
      markUnread(page.name);//the main system do not support this!! so wee do it
    }

    const container = document.createElement("div");
    container.className = "line";

    if(time){
      const t = document.createElement("span");
      t.className = "time";
      t.innerHTML = "["+time+"]";
      container.appendChild(t);
    }

    if(avatar){
      const img = document.createElement("span");
      img.className = "message-avatar";
      img.style.backgroundImage = "url('"+avatar+"')";
      container.appendChild(img);
    }

    if(nick){
     const n = document.createElement("span");
     n.className = "nick";
     n.innerHTML = nick+": ";
     if(nick == "Bot"){
       n.className += " bot-nick";
     }else if(this.name != "console"){
       const u = page.user.get(nick);
       if(u === null){
         page.system.getPage("console").line(time, "", "Bot", "Unknown user: "+nick);
       }else{
         if(u.isOp){
           n.className += " op";
           n.innerHTML = "@"+n.innerHTML;
         }else if(u.isVoice){
           n.className += " voice";
           n.innerHTML = "+"+n.innerHTML;
         }
       }
     }
     container.appendChild(n);
    }

    const m = document.createElement("span");
    m.className = "message";
    m.innerHTML = message;
    container.appendChild(m);

    page.context.appendChild(container);
  };

  removeUserlist : function(dom){
    removeNode(dom);
  },

  removeContextContainer : function(dom){
    removeNode(dom);
  },

  showContextContainer : function(dom){
    dom.style.display = "block";
  },

  hideContextContainer : function(dom){
    dom.style.display = "none";
  }
};
<commit_msg>Update gui.js<commit_after>function removeNode(node){
  node.parentElement.removeChild(node);
}

function markUnread(name){
  const buttom = document.getElementsByClassName("channel_buttom");
  for(var i=0;i<buttom.length;i++){
    if(buttom[i].getElementsByClassName("name")[0].innerHTML == name){
      if(buttom[i].className.split(" ").indexOf("unread") == -1){
         buttom[i].className += " unread";
      }
      return;
    }
  }
}

var StarGui = {
  initUserList : function(){
    var element = document.createElement("div");
    element.className = "user-list";
    document.getElementById("ulist-container").appendChild(element);
    return element;
  },

  initContextContainer : function(){
    const context = document.createElement("div");
    context.className = "context-container";
    document.getElementById("pageContainer").appendChild(context);
    return context;
  },

  appendMessage : function(page, time, avatar, nick, message){
    if(page.system.isFocus(page.name)){
      markUnread(page.name);//the main system do not support this!! so wee do it
    }

    const container = document.createElement("div");
    container.className = "line";

    if(time){
      const t = document.createElement("span");
      t.className = "time";
      t.innerHTML = "["+time+"]";
      container.appendChild(t);
    }

    if(avatar){
      const img = document.createElement("span");
      img.className = "message-avatar";
      img.style.backgroundImage = "url('"+avatar+"')";
      container.appendChild(img);
    }

    if(nick){
     const n = document.createElement("span");
     n.className = "nick";
     n.innerHTML = nick+": ";
     if(nick == "Bot"){
       n.className += " bot-nick";
     }else if(this.name != "console"){
       const u = page.user.get(nick);
       if(u === null){
         page.system.getPage("console").line(time, "", "Bot", "Unknown user: "+nick);
       }else{
         if(u.isOp){
           n.className += " op";
           n.innerHTML = "@"+n.innerHTML;
         }else if(u.isVoice){
           n.className += " voice";
           n.innerHTML = "+"+n.innerHTML;
         }
       }
     }
     container.appendChild(n);
    }

    const m = document.createElement("span");
    m.className = "message";
    m.innerHTML = message;
    container.appendChild(m);

    page.context.appendChild(container);
  },

  appendUser : function(dom, avatar, nick){
    const container = document.createElement("div");
    container.className = "user-item";

    if(avatar){
      const a = document.createElement("span");
      a.style.backgroundImage = "url('"+avatar+"')";
      a.className = "user-list-avatar";
      container.appendChild(a);
    }

    const name = document.createElement("span");
    name.className = "nick";
    name.innerHTML = nick;
    container.appendChild(name);
    const self = this;
    name.onclick = function(){
      const my = self.users[myNick];
      var m = [];
      if(nick == myNick){
        m.push([
          function(){
            var newNick = prompt(language["writeNick"]);
            if(newNick){
              send("Bot", "/nick "+newNick);
            }
          },
          language["changeNick"]
        ]);
      }else if(my.isOp){
        m.push([
          function(){
            alert(typeof sys.currentPage());
            send(sys.currentPage().name, "/kick "+nick);
          },
          language["kick"]
        ]);
        m.push([
          function(){
            send(sys.currentPage().name, "/ban "+nick);
          },
          language["ban"]
        ]);
      }

      for(var i=0;i<m.length;i++){
         const item = document.createElement("div");
         item.onclick = m[i][0];
         item.innerHTML = m[i][1];
         menu.appendChild(item);
      }
      if(menu.offsetParent == null){
        menu.style.display = "block";
      }else{
        menu.style.display = "none";
        menu.innerHTML = "";
      }
    };

    const menu = document.createElement("div");
    menu.className = "menu";
    menu.style.display = "none";
    container.appendChild(menu);

    dom.appendChild(container);
    return container;
  },

  removeUserlist : function(dom){
    removeNode(dom);
  },

  removeContextContainer : function(dom){
    removeNode(dom);
  },

  showContextContainer : function(dom){
    dom.style.display = "block";
  },

  hideContextContainer : function(dom){
    dom.style.display = "none";
  }
};
<|endoftext|>


<commit_before>(function(exports) {
  exports.torque = exports.torque || {};
  exports.torque.renderer = exports.torque.renderer || {};

  var TAU = Math.PI * 2;
  var DEFAULT_CARTOCSS = [
    '#layer {',
    '  marker-fill: #662506;',
    '  marker-width: 4;',
    '  [value > 1] { marker-fill: #FEE391; }',
    '  [value > 2] { marker-fill: #FEC44F; }',
    '  [value > 3] { marker-fill: #FE9929; }',
    '  [value > 4] { marker-fill: #EC7014; }',
    '  [value > 5] { marker-fill: #CC4C02; }',
    '  [value > 6] { marker-fill: #993404; }',
    '  [value > 7] { marker-fill: #662506; }',
    '}'
  ].join('\n');

  //
  // this renderer just render points depending of the value
  //
  function PointRenderer(canvas, options) {
    if (!canvas) {
      throw new Error("canvas can't be undefined");
    }
    this.options = options;
    this._canvas = canvas;
    this._ctx = canvas.getContext('2d');
    this._sprites = []; // sprites per layer
    this._shader = null;
    this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
  }

  PointRenderer.prototype = {

    setCanvas: function(canvas) {
      this._canvas = canvas;
      this._ctx = canvas.getContext('2d');
    },

    //
    // sets the cartocss style to render stuff
    //
    setCartoCSS: function(cartocss) {
      // clean sprites
      this.setShader(new carto.RendererJS().render(cartocss));
    },

    setShader: function(shader) {
      // clean sprites
      this._sprites = [];
      this._shader = shader;
    },

    clearSpriteCache: function() {
      this._sprites = [];
    },

    //
    // generate sprite based on cartocss style
    //
    generateSprite: function(shader, value, shaderVars) {
      var prof = Profiler.metric('torque.renderer.point.generateSprite').start();
      var st = shader.getStyle('canvas-2d', {
        value: value
      }, shaderVars);

      var pointSize = st['point-radius'];
      if (!pointSize) {
        throw new Error("marker-width property should be set");
      }

      var canvas = document.createElement('canvas');

      // take into account the exterior ring to calculate the size
      var canvasSize = (st.lineWidth || 0) + pointSize*2;
      var ctx = canvas.getContext('2d');
      var w = ctx.width = canvas.width = ctx.height = canvas.height = Math.ceil(canvasSize);
      ctx.translate(w/2, w/2);

      if(st['point-file'] || st['marker-file']) {
        torque.cartocss.renderSprite(ctx, st);
      } else {
        var mt = st['marker-type'];
        if (mt && mt === 'rectangle') {
          torque.cartocss.renderRectangle(ctx, st);
        } else {
          torque.cartocss.renderPoint(ctx, st);
        }
      }
      prof.end(true);
      return canvas;
    },

    //
    // renders all the layers (and frames for each layer) from cartocss
    //
    renderTile: function(tile, key) {
      var prof = Profiler.metric('torque.renderer.point.renderLayers').start();
      var layers = this._shader.getLayers();
      for(var i = 0, n = layers.length; i < n; ++i ) {
        var layer = layers[i];
        if (layer.name() !== "Map") {
          var sprites = this._sprites[i] || (this._sprites[i] = {});
          // frames for each layer
          for(var fr = 0; fr < layer.frames().length; ++fr) {
            var frame = layer.frames()[fr];
            var fr_sprites = sprites[frame] || (sprites[frame] = []);
            this._renderTile(tile, key - frame, frame, fr_sprites, layer);
          }
        }
      }
      prof.end(true);
    },

    //
    // renders a tile in the canvas for key defined in
    // the torque tile
    //
    _renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
      if(!this._canvas) return;

      var prof = Profiler.metric('torque.renderer.point.renderTile').start();
      var ctx = this._ctx;
      var blendMode = shader.eval('comp-op') || this.options.blendmode;
      if(blendMode) {
        ctx.globalCompositeOperation = blendMode;
      }
      if (this.options.cumulative && key > tile.maxDate) {
        //TODO: precache because this tile is not going to change
        key = tile.maxDate;
      }
      var tileMax = this.options.resolution * (256/this.options.resolution - 1)
      var activePixels = tile.timeCount[key];
      if(activePixels) {
        var pixelIndex = tile.timeIndex[key];
        for(var p = 0; p < activePixels; ++p) {
          var posIdx = tile.renderDataPos[pixelIndex + p];
          var c = tile.renderData[pixelIndex + p];
          if(c) {
           var sp = sprites[c];
           if(!sp) {
             sp = sprites[c] = this.generateSprite(shader, c, _.extend({ zoom: tile.z, 'frame-offset': frame_offset }, shaderVars));
           }
           //var x = tile.x[posIdx]*res - (sp.width >> 1);
           //var y = (256 - res - res*tile.y[posIdx]) - (sp.height >> 1);
           var x = tile.x[posIdx]- (sp.width >> 1);
           var y = tileMax - tile.y[posIdx]; // flip mercator
           ctx.drawImage(sp, x, y - (sp.height >> 1));
          }
        }
      }
      prof.end(true);
    },

    setBlendMode: function(b) {
      this.options.blendmode = b;
    },

    /**
     * get active points for a step in active zoom
     * returns a list of bounding boxes [[sw, ne] , [], []] where ne is a {lat: .., lon: ...} obj
     * empty list if there is no active pixels
     */
    getActivePointsBBox: function(tile, step) {
      var positions = [];
      var mercator = new torque.Mercator();

      var tileMax = this.options.resolution * (256/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx]; // flip mercator
         positions.push(mercator.tilePixelBBox(
           tile.coord.x,
           tile.coord.y,
           tile.coord.z,
           x, y
         ));
        }
      }
      return positions;
    }

  };

  // exports public api
  exports.torque.renderer.Point = PointRenderer;

})(typeof exports === "undefined" ? this : exports);
<commit_msg>tile size moved to a constant<commit_after>(function(exports) {
  exports.torque = exports.torque || {};
  exports.torque.renderer = exports.torque.renderer || {};

  var TAU = Math.PI * 2;
  var DEFAULT_CARTOCSS = [
    '#layer {',
    '  marker-fill: #662506;',
    '  marker-width: 4;',
    '  [value > 1] { marker-fill: #FEE391; }',
    '  [value > 2] { marker-fill: #FEC44F; }',
    '  [value > 3] { marker-fill: #FE9929; }',
    '  [value > 4] { marker-fill: #EC7014; }',
    '  [value > 5] { marker-fill: #CC4C02; }',
    '  [value > 6] { marker-fill: #993404; }',
    '  [value > 7] { marker-fill: #662506; }',
    '}'
  ].join('\n');

  //
  // this renderer just render points depending of the value
  //
  function PointRenderer(canvas, options) {
    if (!canvas) {
      throw new Error("canvas can't be undefined");
    }
    this.options = options;
    this._canvas = canvas;
    this._ctx = canvas.getContext('2d');
    this._sprites = []; // sprites per layer
    this._shader = null;
    this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
    this.TILE_SIZE = 256;
  }

  PointRenderer.prototype = {

    setCanvas: function(canvas) {
      this._canvas = canvas;
      this._ctx = canvas.getContext('2d');
    },

    //
    // sets the cartocss style to render stuff
    //
    setCartoCSS: function(cartocss) {
      // clean sprites
      this.setShader(new carto.RendererJS().render(cartocss));
    },

    setShader: function(shader) {
      // clean sprites
      this._sprites = [];
      this._shader = shader;
    },

    clearSpriteCache: function() {
      this._sprites = [];
    },

    //
    // generate sprite based on cartocss style
    //
    generateSprite: function(shader, value, shaderVars) {
      var prof = Profiler.metric('torque.renderer.point.generateSprite').start();
      var st = shader.getStyle('canvas-2d', {
        value: value
      }, shaderVars);

      var pointSize = st['point-radius'];
      if (!pointSize) {
        throw new Error("marker-width property should be set");
      }

      var canvas = document.createElement('canvas');

      // take into account the exterior ring to calculate the size
      var canvasSize = (st.lineWidth || 0) + pointSize*2;
      var ctx = canvas.getContext('2d');
      var w = ctx.width = canvas.width = ctx.height = canvas.height = Math.ceil(canvasSize);
      ctx.translate(w/2, w/2);

      if(st['point-file'] || st['marker-file']) {
        torque.cartocss.renderSprite(ctx, st);
      } else {
        var mt = st['marker-type'];
        if (mt && mt === 'rectangle') {
          torque.cartocss.renderRectangle(ctx, st);
        } else {
          torque.cartocss.renderPoint(ctx, st);
        }
      }
      prof.end(true);
      return canvas;
    },

    //
    // renders all the layers (and frames for each layer) from cartocss
    //
    renderTile: function(tile, key) {
      var prof = Profiler.metric('torque.renderer.point.renderLayers').start();
      var layers = this._shader.getLayers();
      for(var i = 0, n = layers.length; i < n; ++i ) {
        var layer = layers[i];
        if (layer.name() !== "Map") {
          var sprites = this._sprites[i] || (this._sprites[i] = {});
          // frames for each layer
          for(var fr = 0; fr < layer.frames().length; ++fr) {
            var frame = layer.frames()[fr];
            var fr_sprites = sprites[frame] || (sprites[frame] = []);
            this._renderTile(tile, key - frame, frame, fr_sprites, layer);
          }
        }
      }
      prof.end(true);
    },

    //
    // renders a tile in the canvas for key defined in
    // the torque tile
    //
    _renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
      if(!this._canvas) return;

      var prof = Profiler.metric('torque.renderer.point.renderTile').start();
      var ctx = this._ctx;
      var blendMode = shader.eval('comp-op') || this.options.blendmode;
      if(blendMode) {
        ctx.globalCompositeOperation = blendMode;
      }
      if (this.options.cumulative && key > tile.maxDate) {
        //TODO: precache because this tile is not going to change
        key = tile.maxDate;
      }
      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1)
      var activePixels = tile.timeCount[key];
      if(activePixels) {
        var pixelIndex = tile.timeIndex[key];
        for(var p = 0; p < activePixels; ++p) {
          var posIdx = tile.renderDataPos[pixelIndex + p];
          var c = tile.renderData[pixelIndex + p];
          if(c) {
           var sp = sprites[c];
           if(!sp) {
             sp = sprites[c] = this.generateSprite(shader, c, _.extend({ zoom: tile.z, 'frame-offset': frame_offset }, shaderVars));
           }
           var x = tile.x[posIdx]- (sp.width >> 1);
           var y = tileMax - tile.y[posIdx]; // flip mercator
           ctx.drawImage(sp, x, y - (sp.height >> 1));
          }
        }
      }
      prof.end(true);
    },

    setBlendMode: function(b) {
      this.options.blendmode = b;
    },

    /**
     * get active points for a step in active zoom
     * returns a list of bounding boxes [[sw, ne] , [], []] where ne is a {lat: .., lon: ...} obj
     * empty list if there is no active pixels
     */
    getActivePointsBBox: function(tile, step) {
      var positions = [];
      var mercator = new torque.Mercator();

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx]; // flip mercator
         positions.push(mercator.tilePixelBBox(
           tile.coord.x,
           tile.coord.y,
           tile.coord.z,
           x, y
         ));
        }
      }
      return positions;
    }

  };

  // exports public api
  exports.torque.renderer.Point = PointRenderer;

})(typeof exports === "undefined" ? this : exports);
<|endoftext|>


<commit_before>var torque = require('../');
var cartocss = require('./cartocss_render');
var Profiler = require('../profiler');
var carto = global.carto || require('carto');

  var TAU = Math.PI * 2;
  var DEFAULT_CARTOCSS = [
    '#layer {',
    '  marker-fill: #662506;',
    '  marker-width: 4;',
    '  [value > 1] { marker-fill: #FEE391; }',
    '  [value > 2] { marker-fill: #FEC44F; }',
    '  [value > 3] { marker-fill: #FE9929; }',
    '  [value > 4] { marker-fill: #EC7014; }',
    '  [value > 5] { marker-fill: #CC4C02; }',
    '  [value > 6] { marker-fill: #993404; }',
    '  [value > 7] { marker-fill: #662506; }',
    '}'
  ].join('\n');

  var COMP_OP_TO_CANVAS = {
    "src": 'source-over',
    "src-over": 'source-over',
    "dst-over": 'destination-over',
    "src-in": 'source-in',
    "dst-in": 'destination-in',
    "src-out": 'source-out',
    "dst-out": 'destination-out',
    "src-atop": 'source-atop',
    "dst-atop": 'destination-atop',
    "xor": 'xor',
    "darken": 'darken',
    "lighten": 'lighten'
  }

  function compop2canvas(compop) {
    return COMP_OP_TO_CANVAS[compop] || compop;
  }

  //
  // this renderer just render points depending of the value
  //
  function PointRenderer(canvas, options) {
    if (!canvas) {
      throw new Error("canvas can't be undefined");
    }
    this.options = options;
    this._canvas = canvas;
    this._ctx = canvas.getContext('2d');
    this._sprites = []; // sprites per layer
    this._shader = null;
    this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
    this.TILE_SIZE = 256;
    this._icons = {};
  }

  torque.extend(PointRenderer.prototype, torque.Event, {

    clearCanvas: function() {
      var canvas = this._canvas;
      var color = this._Map['-torque-clear-color']
      // shortcut for the default value
      if (color  === "rgba(255, 255, 255, 0)" || !color) {
        this._canvas.width = this._canvas.width;
      } else {
        var ctx = this._ctx;
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        var compop = this._Map['comp-op']
        ctx.globalCompositeOperation = compop2canvas(compop);
        ctx.fillStyle = color;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
      }
    },

    setCanvas: function(canvas) {
      this._canvas = canvas;
      this._ctx = canvas.getContext('2d');
    },

    //
    // sets the cartocss style to render stuff
    //
    setCartoCSS: function(cartocss) {
      // clean sprites
      this.setShader(new carto.RendererJS().render(cartocss));
    },

    setShader: function(shader) {
      // clean sprites
      this._sprites = [];
      this._shader = shader;
      this._Map = this._shader.getDefault().getStyle({}, { zoom: 0 });
    },

    clearSpriteCache: function() {
      this._sprites = [];
    },

    //
    // generate sprite based on cartocss style
    //
    generateSprite: function(shader, value, shaderVars) {
      var self = this;
      var prof = Profiler.metric('torque.renderer.point.generateSprite').start();
      var st = shader.getStyle({
        value: value
      }, shaderVars);

      var pointSize = st['marker-width'];
      if (!pointSize) {
        return null;
      }

      if (st['marker-opacity'] === 0 && !st['marker-line-opacity']) {
        return null;
      }

      var canvas = this._createCanvas();
      // take into account the exterior ring to calculate the size
      var canvasSize = (st['marker-line-width'] || 0) + pointSize*2;
      var ctx = canvas.getContext('2d');
      var w = ctx.width = canvas.width = ctx.height = canvas.height = Math.ceil(canvasSize);
      ctx.translate(w/2, w/2);

      var img_names = this._shader.getImageURLs();
      if(img_names.length > 0){
        if(Object.keys(this._icons).length === 0){
          for (var i = 0; i<img_names.length; i++){
            var new_img = this._createImage();
            self._icons[img_names[i]] = null;
            if (typeof self._icons.itemsToLoad === 'undefined'){
              self._icons.itemsToLoad = img_names.length;
            }
            new_img.onload = function(e){
              self._icons[this.src] = this;
              if(Object.keys(self._icons).length === img_names.length + 1){
                self._icons.itemsToLoad--;
                if(self._icons.itemsToLoad === 0){
                  self.clearSpriteCache();
                  self.fire("allIconsLoaded");
                }
              }
            };
            new_img.onerror = function(){

            };
            new_img.src = img_names[i];
          }

        }
        if(this._icons.itemsToLoad==0) {
          var img_name = st["marker-file"] || st["point-file"];
          var img = this._icons[img_name];
          img.w = st['marker-width'] || img.width;
          img.h = st['marker-width'] || st['marker-height'];
          cartocss.renderSprite(ctx, img);
        }
      }
      else {
        var mt = st['marker-type'];
        if (mt && mt === 'rectangle') {
          cartocss.renderRectangle(ctx, st);
        } else {
          cartocss.renderPoint(ctx, st);
        }
      }
      prof.end(true);
      if (torque.flags.sprites_to_images) {
        var i = this._createImage();
        i.src = canvas.toDataURL();
        return i;
      }
      return canvas;
    },

    //
    // renders all the layers (and frames for each layer) from cartocss
    //
    renderTile: function(tile, key) {
      var prof = Profiler.metric('torque.renderer.point.renderLayers').start();
      var layers = this._shader.getLayers();
      for(var i = 0, n = layers.length; i < n; ++i ) {
        var layer = layers[i];
        if (layer.name() !== "Map") {
          var sprites = this._sprites[i] || (this._sprites[i] = {});
          // frames for each layer
          for(var fr = 0; fr < layer.frames().length; ++fr) {
            var frame = layer.frames()[fr];
            var fr_sprites = sprites[frame] || (sprites[frame] = []);
            this._renderTile(tile, key - frame, frame, fr_sprites, layer);
          }
        }
      }
      prof.end(true);
    },

    _createCanvas: function() {
      return this.options.canvasClass
        ? new this.options.canvasClass()
        : document.createElement('canvas');
    },

    _createImage: function() {
      return this.options.imageClass
        ? new this.options.imageClass()
        : new Image();
    },

    //
    // renders a tile in the canvas for key defined in
    // the torque tile
    //
    _renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
      if(!this._canvas) return;

      var prof = Profiler.metric('torque.renderer.point.renderTile').start();
      var ctx = this._ctx;
      var blendMode = compop2canvas(shader.eval('comp-op')) || this.options.blendmode;
      if(blendMode) {
        ctx.globalCompositeOperation = blendMode;
      }
      if (this.options.cumulative && key > tile.maxDate) {
        //TODO: precache because this tile is not going to change
        key = tile.maxDate;
      }
      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1)
      var activePixels = tile.timeCount[key];
      if(activePixels) {
        var pixelIndex = tile.timeIndex[key];
        for(var p = 0; p < activePixels; ++p) {
          var posIdx = tile.renderDataPos[pixelIndex + p];
          var c = tile.renderData[pixelIndex + p];
          if(c) {
           var sp = sprites[c];
           if(sp === undefined) {
             sp = sprites[c] = this.generateSprite(shader, c, torque.extend({ zoom: tile.z, 'frame-offset': frame_offset }, shaderVars));
           }
           if (sp) {
             var x = tile.x[posIdx]- (sp.width >> 1);
             var y = tileMax - tile.y[posIdx]; // flip mercator
             ctx.drawImage(sp, x, y - (sp.height >> 1));
           }
          }
        }
      }
      prof.end(true);
    },

    setBlendMode: function(b) {
      this.options.blendmode = b;
    },

    /**
     * get active points for a step in active zoom
     * returns a list of bounding boxes [[sw, ne] , [], []] where ne is a {lat: .., lon: ...} obj
     * empty list if there is no active pixels
     */
    getActivePointsBBox: function(tile, step) {
      var positions = [];
      var mercator = new torque.Mercator();

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx]; // flip mercator
         positions.push(mercator.tilePixelBBox(
           tile.coord.x,
           tile.coord.y,
           tile.coord.z,
           x, y
         ));
        }
      }
      return positions;
    },

    // return the value for x, y (tile coordinates)
    // null for no value
    getValueFor: function(tile, step, px, py) {
      var mercator = new torque.Mercator();
      var res = this.options.resolution;
      var res2 = res >> 1;

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx];
         var dx = px + res2 - x;
         var dy = py + res2 - y;
         if (dx >= 0 && dx < res && dy >= 0 && dy < res) {
           return {
             value: c,
             bbox: mercator.tilePixelBBox(
               tile.coord.x,
               tile.coord.y,
               tile.coord.z,
               x - res2, y - res2, res
             )
           }
         }
        }
      }
      return null;
    },
    _preloadIcons: function(){
      var img_name = this._shader.layers[1].shader["marker-file"];
      var imagesToLoad = 1;
      if(img_name && !(img_name in this._icons)){
        var new_img = new Image();
        new_img.onload(function(){
          imagesToLoad--;
          if(imagesToLoad == 0){
            this.fire("iconsloaded");
          }
        });
        new_img.src = img_name;
        this._icons[img_name] = new_img;
      }
      else{
        this.fire("iconsloaded");
      }

      // TODO: get icons for conditional styles too
      // if (typeof obj["marker-file"] !== 'undefined'){
      //   iconFiles.push(obj["marker-file"]);
      // }
      // for(var i = 0; i< layers.length){

      // }
      // }
    }

  });

  // exports public api
module.exports = PointRenderer;
<commit_msg>defaults to point rendering in case marker-file errors, shows error in console<commit_after>var torque = require('../');
var cartocss = require('./cartocss_render');
var Profiler = require('../profiler');
var carto = global.carto || require('carto');

  var TAU = Math.PI * 2;
  var DEFAULT_CARTOCSS = [
    '#layer {',
    '  marker-fill: #662506;',
    '  marker-width: 4;',
    '  [value > 1] { marker-fill: #FEE391; }',
    '  [value > 2] { marker-fill: #FEC44F; }',
    '  [value > 3] { marker-fill: #FE9929; }',
    '  [value > 4] { marker-fill: #EC7014; }',
    '  [value > 5] { marker-fill: #CC4C02; }',
    '  [value > 6] { marker-fill: #993404; }',
    '  [value > 7] { marker-fill: #662506; }',
    '}'
  ].join('\n');

  var COMP_OP_TO_CANVAS = {
    "src": 'source-over',
    "src-over": 'source-over',
    "dst-over": 'destination-over',
    "src-in": 'source-in',
    "dst-in": 'destination-in',
    "src-out": 'source-out',
    "dst-out": 'destination-out',
    "src-atop": 'source-atop',
    "dst-atop": 'destination-atop',
    "xor": 'xor',
    "darken": 'darken',
    "lighten": 'lighten'
  }

  function compop2canvas(compop) {
    return COMP_OP_TO_CANVAS[compop] || compop;
  }

  //
  // this renderer just render points depending of the value
  //
  function PointRenderer(canvas, options) {
    if (!canvas) {
      throw new Error("canvas can't be undefined");
    }
    this.options = options;
    this._canvas = canvas;
    this._ctx = canvas.getContext('2d');
    this._sprites = []; // sprites per layer
    this._shader = null;
    this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
    this.TILE_SIZE = 256;
    this._icons = {};
    this._forcePoints = false;
  }

  torque.extend(PointRenderer.prototype, torque.Event, {

    clearCanvas: function() {
      var canvas = this._canvas;
      var color = this._Map['-torque-clear-color']
      // shortcut for the default value
      if (color  === "rgba(255, 255, 255, 0)" || !color) {
        this._canvas.width = this._canvas.width;
      } else {
        var ctx = this._ctx;
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        var compop = this._Map['comp-op']
        ctx.globalCompositeOperation = compop2canvas(compop);
        ctx.fillStyle = color;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
      }
    },

    setCanvas: function(canvas) {
      this._canvas = canvas;
      this._ctx = canvas.getContext('2d');
    },

    //
    // sets the cartocss style to render stuff
    //
    setCartoCSS: function(cartocss) {
      // clean sprites
      this.setShader(new carto.RendererJS().render(cartocss));
    },

    setShader: function(shader) {
      // clean sprites
      this._sprites = [];
      this._shader = shader;
      this._Map = this._shader.getDefault().getStyle({}, { zoom: 0 });
    },

    clearSpriteCache: function() {
      this._sprites = [];
    },

    //
    // generate sprite based on cartocss style
    //
    generateSprite: function(shader, value, shaderVars) {
      var self = this;
      var prof = Profiler.metric('torque.renderer.point.generateSprite').start();
      var st = shader.getStyle({
        value: value
      }, shaderVars);

      var pointSize = st['marker-width'];
      if (!pointSize) {
        return null;
      }

      if (st['marker-opacity'] === 0 && !st['marker-line-opacity']) {
        return null;
      }

      var canvas = this._createCanvas();
      // take into account the exterior ring to calculate the size
      var canvasSize = (st['marker-line-width'] || 0) + pointSize*2;
      var ctx = canvas.getContext('2d');
      var w = ctx.width = canvas.width = ctx.height = canvas.height = Math.ceil(canvasSize);
      ctx.translate(w/2, w/2);

      var img_names = this._shader.getImageURLs();
      if(img_names.length > 0 && !this._forcePoints){
        if(Object.keys(this._icons).length === 0){
          for (var i = 0; i<img_names.length; i++){
            var new_img = this._createImage();
            self._icons[img_names[i]] = null;
            if (typeof self._icons.itemsToLoad === 'undefined'){
              self._icons.itemsToLoad = img_names.length;
            }
            new_img.onload = function(e){
              self._icons[this.src] = this;
              if(Object.keys(self._icons).length === img_names.length + 1){
                self._icons.itemsToLoad--;
                if(self._icons.itemsToLoad === 0){
                  self.clearSpriteCache();
                  self.fire("allIconsLoaded");
                }
              }
            };
            new_img.onerror = function(){
              self._forcePoints = true;
              self.clearSpriteCache();
              console.error("Couldn't get marker-file " + this.src);
            };
            new_img.src = img_names[i];
          }

        }
        if(this._icons.itemsToLoad==0) {
          var img_name = st["marker-file"] || st["point-file"];
          var img = this._icons[img_name];
          img.w = st['marker-width'] || img.width;
          img.h = st['marker-width'] || st['marker-height'];
          cartocss.renderSprite(ctx, img);
        }
      }
      else {
        var mt = st['marker-type'];
        if (mt && mt === 'rectangle') {
          cartocss.renderRectangle(ctx, st);
        } else {
          cartocss.renderPoint(ctx, st);
        }
      }
      prof.end(true);
      if (torque.flags.sprites_to_images) {
        var i = this._createImage();
        i.src = canvas.toDataURL();
        return i;
      }
      return canvas;
    },

    //
    // renders all the layers (and frames for each layer) from cartocss
    //
    renderTile: function(tile, key) {
      var prof = Profiler.metric('torque.renderer.point.renderLayers').start();
      var layers = this._shader.getLayers();
      for(var i = 0, n = layers.length; i < n; ++i ) {
        var layer = layers[i];
        if (layer.name() !== "Map") {
          var sprites = this._sprites[i] || (this._sprites[i] = {});
          // frames for each layer
          for(var fr = 0; fr < layer.frames().length; ++fr) {
            var frame = layer.frames()[fr];
            var fr_sprites = sprites[frame] || (sprites[frame] = []);
            this._renderTile(tile, key - frame, frame, fr_sprites, layer);
          }
        }
      }
      prof.end(true);
    },

    _createCanvas: function() {
      return this.options.canvasClass
        ? new this.options.canvasClass()
        : document.createElement('canvas');
    },

    _createImage: function() {
      return this.options.imageClass
        ? new this.options.imageClass()
        : new Image();
    },

    //
    // renders a tile in the canvas for key defined in
    // the torque tile
    //
    _renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
      if(!this._canvas) return;

      var prof = Profiler.metric('torque.renderer.point.renderTile').start();
      var ctx = this._ctx;
      var blendMode = compop2canvas(shader.eval('comp-op')) || this.options.blendmode;
      if(blendMode) {
        ctx.globalCompositeOperation = blendMode;
      }
      if (this.options.cumulative && key > tile.maxDate) {
        //TODO: precache because this tile is not going to change
        key = tile.maxDate;
      }
      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1)
      var activePixels = tile.timeCount[key];
      if(activePixels) {
        var pixelIndex = tile.timeIndex[key];
        for(var p = 0; p < activePixels; ++p) {
          var posIdx = tile.renderDataPos[pixelIndex + p];
          var c = tile.renderData[pixelIndex + p];
          if(c) {
           var sp = sprites[c];
           if(sp === undefined) {
             sp = sprites[c] = this.generateSprite(shader, c, torque.extend({ zoom: tile.z, 'frame-offset': frame_offset }, shaderVars));
           }
           if (sp) {
             var x = tile.x[posIdx]- (sp.width >> 1);
             var y = tileMax - tile.y[posIdx]; // flip mercator
             ctx.drawImage(sp, x, y - (sp.height >> 1));
           }
          }
        }
      }
      prof.end(true);
    },

    setBlendMode: function(b) {
      this.options.blendmode = b;
    },

    /**
     * get active points for a step in active zoom
     * returns a list of bounding boxes [[sw, ne] , [], []] where ne is a {lat: .., lon: ...} obj
     * empty list if there is no active pixels
     */
    getActivePointsBBox: function(tile, step) {
      var positions = [];
      var mercator = new torque.Mercator();

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx]; // flip mercator
         positions.push(mercator.tilePixelBBox(
           tile.coord.x,
           tile.coord.y,
           tile.coord.z,
           x, y
         ));
        }
      }
      return positions;
    },

    // return the value for x, y (tile coordinates)
    // null for no value
    getValueFor: function(tile, step, px, py) {
      var mercator = new torque.Mercator();
      var res = this.options.resolution;
      var res2 = res >> 1;

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx];
         var dx = px + res2 - x;
         var dy = py + res2 - y;
         if (dx >= 0 && dx < res && dy >= 0 && dy < res) {
           return {
             value: c,
             bbox: mercator.tilePixelBBox(
               tile.coord.x,
               tile.coord.y,
               tile.coord.z,
               x - res2, y - res2, res
             )
           }
         }
        }
      }
      return null;
    },
    _preloadIcons: function(){
      var img_name = this._shader.layers[1].shader["marker-file"];
      var imagesToLoad = 1;
      if(img_name && !(img_name in this._icons)){
        var new_img = new Image();
        new_img.onload(function(){
          imagesToLoad--;
          if(imagesToLoad == 0){
            this.fire("iconsloaded");
          }
        });
        new_img.src = img_name;
        this._icons[img_name] = new_img;
      }
      else{
        this.fire("iconsloaded");
      }

      // TODO: get icons for conditional styles too
      // if (typeof obj["marker-file"] !== 'undefined'){
      //   iconFiles.push(obj["marker-file"]);
      // }
      // for(var i = 0; i< layers.length){

      // }
      // }
    }

  });

  // exports public api
module.exports = PointRenderer;
<|endoftext|>