<commit_before>#!/usr/bin/env nodejs
var _ = require('lodash');
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
var debug = require('debug')('realityreduction');
var moment = require('moment');
var nconf = require('nconf');

var utils = require('../lib/utils');
var mongo = require('../lib/mongo');
var timutils = require('../lib/timeutils');

var cfgFile = "config/settings.json";
nconf.argv().env().file({ file: cfgFile });

/*
 * This batch produce (many, potentially updating) entries for one collection:
 *   `reality`: chronologically ordered postId list, with accessory data used by postId
 *
 * TODO update has to be done on the collection:
 *   `perception`: timeline with medatada expanded. This collection would be the chronological
 *                 perception of the users, maybe would be already aggregated, for example with
 *                 semantic analysis of the content processed
 */

if(!_.parseInt(nconf.get('DAYS')))
    throw new Error("DAYS is required, specifiy the start-until window of time");

var timeFilter = timutils.doFilter(
        nconf.get('HOURSAFTER'),
        nconf.get('DAYSAGO'),
        nconf.get('HOURSAGO'),
        _.parseInt(nconf.get('DAYS')), 'd'
    );

var keys = [
    'id',
    'userPseudo',
    'publicationUTime',
    'impressionTime',
    'impressionOrder',
    'postId',
    'permaLink',
    'timelineId',
    'counter'
];

debug("Executing timewindow: %s and nation",
    timutils.prettify(timeFilter));

function getRelativeInfo(htmlId) {

    var sequence = {
        $lookup: {
            from: nconf.get('schema').timelines,
            localField: 'timelineId',
            foreignField: 'id',
            as: "timeline"
         }
    };

    return mongo
        .lookup(nconf.get('schema').impressions, { $match: { htmlId: htmlId }}, sequence)
        .then(_.first)
        .then(function(c) {
            var f = _.pick(c, [ 'timelineId', 'userId', 'impressionOrder', 'impressionTime' ]);
            var s = _.pick(c.timeline[0], [ 'geoip', 'startTime' ]);
            return _.extend(f, s);
        })
        .catch(function(error) {
            debug("Error: %s %s", error, htmlId);
        });
    ;
};

function getExisting(postId) {

    return mongo
        .read(nconf.get('schema').reality, { postId: postId })
        .then(_.first)
        .catch(function(error) {
            debug("Error getExisting: %s %s", error, postId);
        });
};

function getMetadata(present, html) {
    var now = _.omit(html, ['_id', 'publicationUTime', 'savingTime', 'id',
                            'userId', 'impressionId', 'timelineId', 'html', 'postId',
                            /* and parsers meta-results ... */
                            'postType', 'feedUTime' ]);

    if(_.size(_.keys(now)) < _.size(_.keys(present))) {
        debug("Strange situation, returning %j instead of %j", present, now);
        return present;
    }
    return now;
};

function reality(html, i, x) {

    /* here we take the postId, we're to check for every postId if is already in the DB
     * and update the entry or upsert.
     *
     * postId is an index and is unique
     */

    return Promise
        .all([ getRelativeInfo(html.id), getExisting(html.postId) ])
        .then(function(infos) {
            var related = infos[0];
            var existent = infos[1];

            if(!related || !related.timelineId)
                throw new Error("missing related!" + html.id);
                /* likely do not mix, and is a connection error */

            /* debug("related %s", JSON.stringify(related, undefined, 2));
            debug("existent %s", JSON.stringify(existent, undefined, 2)); */

            if(!existent) {
                debug("%d/%d ++ %s userId %s postId %s", i, x, html.savingTime, html.userId, html.postId);
                existent = { 'postId': _.toString(html.postId), 'publicationUTime': html.publicationUTime, timelines: [], updates: 0 };
            }
            else if(_.find(existent.timelines, {id: related.timelineId })) {
                debug("%d/%d --- Present, %s", i,x, html.savingTime);
                return true;
            }

            /* as cleaning mechanism, if something has 1 update after five days, is deleted ? */
            /* maybe if got access from two or more users, only ? */
            existent.updates += 1;
            existent.metadata = getMetadata(existent.metadata, html);
            existent.timelines.push({
                'id': related.timelineId,
                'impressionTime': new Date(related.impressionTime),
                'impressionOrder': related.impressionOrder,
                'startTime': new Date(related.startTime),
                'geoip': related.geoip,
                'userPseudo' : utils.numId2Words([ _.parseInt(existent.postId), related.userId])
            });

            if( existent.publicationUTime != html.publicationUTime )
                debug("Strange: %d %d %d",
                    _.parseInt(existent.publicationUTime),
                    _.parseInt(html.publicationUTime),
                    _.parseInt(existent.publicationUTime) - _.parseInt(html.publicationUTime) );

            if(!existent.publicationTime)
                existent.publicationTime = new Date(moment(html.publicationUTime * 1000).toISOString());

            var t = _.countBy(existent.timelines, 'userPseudo');
            if(_.size(t) > 2)
                debug("someone new: %s", JSON.stringify(t, undefined, 2));

            return mongo
                .upsertOne(nconf.get('schema').reality, {postId: existent.postId}, existent )
                .then(function(result) {
                    return true;
                })
                .catch(function(error) {
                    debug("Error: %j", error);
                    return false;
                });
        });

}

function getHTMLs(skip, blockSize) {

    var filter = {
        postId: { "$exists": true },
        publicationUTime: { "$exists": true },
        savingTime: {
            "$gt": new Date(timeFilter.start),
            "$lt": new Date(timeFilter.end)
        }
    };

    debug("Selecting timelines as: with previously read %d blockSize %d",
        skip, blockSize);

    return mongo
        .readLimit(nconf.get('schema').htmls, filter, {}, blockSize, skip);
};

function saveReality(skip, blockSize) {

    debug("Iterating over a %d block skipping %d", blockSize, skip);
    return getHTMLs(skip, blockSize)
        .tap(function(htmls) {
            debug("~~ skipping %d block of %d working on %d",
                skip, blockSize, _.size(htmls));
        })
        .map(reality, { concurrency: _.parseInt(nconf.get('CONCURRENCY')) || 1 })
        .then(function(results) {
            if(_.size(results) < blockSize) {
                debug("Process completed! %d < %d", _.size(results), blockSize);
                return 0;
            } else {
                debug("Still to do skipping %d", skip + blockSize);
                return 1;
            }
        });
};

return saveReality(_.parseInt(nconf.get('SKIP')) || 0, _.parseInt(nconf.get('BLOCK')) || 2000 );
<commit_msg>smooth and repeatable<commit_after>#!/usr/bin/env nodejs
var _ = require('lodash');
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
var debug = require('debug')('realityreduction');
var moment = require('moment');
var nconf = require('nconf');

var utils = require('../lib/utils');
var mongo = require('../lib/mongo');
var timutils = require('../lib/timeutils');

var cfgFile = "config/settings.json";
nconf.argv().env().file({ file: cfgFile });

/*
 * This batch produce (many, potentially updating) entries for one collection:
 *   `reality`: chronologically ordered postId list, with accessory data used by postId
 *
 * TODO update has to be done on the collection:
 *   `perception`: timeline with medatada expanded. This collection would be the chronological
 *                 perception of the users, maybe would be already aggregated, for example with
 *                 semantic analysis of the content processed
 */

if(!_.parseInt(nconf.get('DAYS')))
    throw new Error("DAYS is required, specifiy the start-until window of time");

var timeFilter = timutils.doFilter(
        nconf.get('HOURSAFTER'),
        nconf.get('DAYSAGO'),
        nconf.get('HOURSAGO'),
        _.parseInt(nconf.get('DAYS')), 'd'
    );

var keys = [
    'id',
    'userPseudo',
    'publicationUTime',
    'impressionTime',
    'impressionOrder',
    'postId',
    'permaLink',
    'timelineId',
    'counter'
];

debug("Executing timewindow: %s and nation",
    timutils.prettify(timeFilter));

function getRelativeInfo(htmlId) {

    var sequence = {
        $lookup: {
            from: nconf.get('schema').timelines,
            localField: 'timelineId',
            foreignField: 'id',
            as: "timeline"
         }
    };

    return mongo
        .lookup(nconf.get('schema').impressions, { $match: { htmlId: htmlId }}, sequence)
        .then(_.first)
        .then(function(c) {
            var f = _.pick(c, [ 'timelineId', 'userId', 'impressionOrder', 'impressionTime' ]);
            var s = _.pick(c.timeline[0], [ 'geoip', 'startTime' ]);
            return _.extend(f, s);
        })
        .catch(function(error) {
            debug("Error: %s %s", error, htmlId);
        });
    ;
};

function getExisting(postId) {

    return mongo
        .read(nconf.get('schema').reality, { postId: postId })
        .then(_.first)
        .catch(function(error) {
            debug("Error getExisting: %s %s", error, postId);
        });
};

function getMetadata(present, html) {
    var now = _.omit(html, ['_id', 'publicationUTime', 'savingTime', 'id',
                            'userId', 'impressionId', 'timelineId', 'html', 'postId',
                            /* and parsers meta-results ... */
                            'postType', 'feedUTime' ]);

    if(_.size(_.keys(now)) < _.size(_.keys(present))) {
        debug("Strange situation, returning %j instead of %j", present, now);
        return present;
    }
    return now;
};

function reality(html, i, x) {

    /* here we take the postId, we're to check for every postId if is already in the DB
     * and update the entry or upsert.
     *
     * postId is an index and is unique
     */

    return Promise
        .all([ getRelativeInfo(html.id), getExisting(html.postId) ])
        .then(function(infos) {
            var related = infos[0];
            var existent = infos[1];

            if(!related || !related.timelineId)
                throw new Error("missing related!" + html.id);
                /* likely do not mix, and is a connection error */

            /* debug("related %s", JSON.stringify(related, undefined, 2));
            debug("existent %s", JSON.stringify(existent, undefined, 2)); */

            if(!existent) {
                debug("%d/%d %s NEW userId %s postId %s", i, x, html.savingTime, html.userId, html.postId);
                existent = { 'postId': _.toString(html.postId), 'publicationUTime': html.publicationUTime, timelines: [], updates: 0 };
            }
            else if(_.find(existent.timelines, {id: related.timelineId })) {
                debug("%d/%d  __ Present %s", i,x, html.savingTime);
                return true;
            } else {
                debug("%d/%d %s +update postId %s", i, x, html.savingTime, html.postId);
            }

            /* as cleaning mechanism, if something has 1 update after five days, is deleted ? */
            /* maybe if got access from two or more users, only ? */
            existent.updates += 1;
            existent.metadata = getMetadata(existent.metadata, html);
            existent.timelines.push({
                'id': related.timelineId,
                'impressionTime': new Date(related.impressionTime),
                'impressionOrder': related.impressionOrder,
                'startTime': new Date(related.startTime),
                'geoip': related.geoip,
                'userPseudo' : utils.numId2Words([ _.parseInt(existent.postId), related.userId])
            });

            if( existent.publicationUTime != html.publicationUTime )
                debug("Strange: %d %d %d",
                    _.parseInt(existent.publicationUTime),
                    _.parseInt(html.publicationUTime),
                    _.parseInt(existent.publicationUTime) - _.parseInt(html.publicationUTime) );

            if(!existent.publicationTime)
                existent.publicationTime = new Date(moment(html.publicationUTime * 1000).toISOString());

            var t = _.countBy(existent.timelines, 'userPseudo');
            if(_.size(t) > 2)
                debug("someone new: %s", JSON.stringify(t, undefined, 2));

            return mongo
                .upsertOne(nconf.get('schema').reality, {postId: existent.postId}, existent )
                .then(function(result) {
                    return true;
                })
                .catch(function(error) {
                    debug("Error: %j", error);
                    return false;
                });
        });

}

function getHTMLs(skip, blockSize) {

    var filter = {
        postId: { "$exists": true },
        publicationUTime: { "$exists": true },
        savingTime: {
            "$gt": new Date(timeFilter.start),
            "$lt": new Date(timeFilter.end)
        }
    };

    debug("Selecting timelines as: with previously read %d blockSize %d",
        skip, blockSize);

    return mongo
        .readLimit(nconf.get('schema').htmls, filter, {}, blockSize, skip);
};

function saveReality(skip, blockSize) {

    debug("Iterating over a %d block skipping %d", blockSize, skip);
    return getHTMLs(skip, blockSize)
        .tap(function(htmls) {
            debug("~~ skipping %d block of %d working on %d",
                skip, blockSize, _.size(htmls));
        })
        .map(reality, { concurrency: _.parseInt(nconf.get('CONCURRENCY')) || 1 })
        .then(function(results) {
            if(_.size(results) < blockSize) {
                debug("Process completed! %d < %d", _.size(results), blockSize);
                return 0;
            } else {
                debug("Still to do skipping %d", skip + blockSize);
                return 1;
            }
        });
};

return saveReality(_.parseInt(nconf.get('SKIP')) || 0, _.parseInt(nconf.get('BLOCK')) || 2000 );
<|endoftext|>


<commit_before>var util = require('../lib/test-utils.js');
var expect = require('chai').expect;

describe('fs.access', function () {
  beforeEach(util.setup);
  afterEach(util.cleanup);

  it('should expose access mode flags on fs and fs.constants', function() {
    var fs = util.fs();

    // F_OK
    expect(fs.F_OK).to.equal(0);
    expect(fs.constants.F_OK).to.equal(0);

    // R_OK
    expect(fs.R_OK).to.equal(4);
    expect(fs.constants.R_OK).to.equal(4);

    // W_OK
    expect(fs.W_OK).to.equal(2);
    expect(fs.constants.W_OK).to.equal(2);

    // X_OK
    expect(fs.X_OK).to.equal(1);
    expect(fs.constants.X_OK).to.equal(1);
  });

  it('should be a function', function () {
    var fs = util.fs();
    expect(typeof fs.access).to.equal('function');
  });

  it('should return an error if file does not exist', function (done) {
    var fs = util.fs();

    fs.access('/tmp', fs.constants.F_OK, function (error) {
      expect(error).to.exist;
      expect(error.code).to.equal('ENOENT');
      done();
    });
  });

  it('should return no error if file does exist and mode = F_OK', function (done) {
    var fs = util.fs();
    var contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.access('/myfile', fs.constants.F_OK, function (error) {
        expect(error).not.to.exist;
        done();
      });
    });
  });

  it('should return no error if file does exist and mode = R_OK', function (done) {
    var fs = util.fs();
    var contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.access('/myfile', fs.constants.R_OK, function (error) {
        expect(error).not.to.exist;
        done();
      });
    });
  });

  it('should return no error if file does exist and mode = W_OK', function (done) {
    var fs = util.fs();
    var contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.access('/myfile', fs.constants.W_OK, function (error) {
        expect(error).not.to.exist;
        done();
      });
    });
  });

  it('should return an error if file is not executable and mode = X_OK', function (done) {
    var fs = util.fs();
    var contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.chmod('/myfile', '644', function(error){
        if (error) throw error;

        fs.access('/myfile', fs.constants.X_OK, function (error) {
          expect(error).to.exist;
          expect(error.code).to.equal('EACCES');
          done();
        });
      });
    });
  });

  it('should return no error if file does exist and mode = X_OK', function (done) {
    var fs = util.fs();
    var contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.chmod('/myfile', 0o777, function(error) {
        if (error) throw error;

        fs.access('/myfile', fs.constants.X_OK, function (error) {
          expect(error).not.to.exist;
          done();
        });
      });
    });
  });

  it('should return no error if file does exist and no mode is passed', function (done) {
    var fs = util.fs();
    var contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.access('/myfile', function (error) {
        expect(error).not.to.exist;
        done();
      });
    });
  });

  it('should return no error if file does exist and mode = R_OK | W_OK', function (done) {
    var fs = util.fs();
    var contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.access('/myfile', fs.constants.R_OK | fs.constants.W_OK, function (error) {
        expect(error).not.to.exist;
        done();
      });
    });
  });
});
<commit_msg>Fixed #665: Replaced var with let or const and added strict mode fs.a… (#688)<commit_after>'use strict';

const util = require('../lib/test-utils.js');
const expect = require('chai').expect;

describe('fs.access', function () {
  beforeEach(util.setup);
  afterEach(util.cleanup);

  it('should expose access mode flags on fs and fs.constants', function() {
    const fs = util.fs();

    // F_OK
    expect(fs.F_OK).to.equal(0);
    expect(fs.constants.F_OK).to.equal(0);

    // R_OK
    expect(fs.R_OK).to.equal(4);
    expect(fs.constants.R_OK).to.equal(4);

    // W_OK
    expect(fs.W_OK).to.equal(2);
    expect(fs.constants.W_OK).to.equal(2);

    // X_OK
    expect(fs.X_OK).to.equal(1);
    expect(fs.constants.X_OK).to.equal(1);
  });

  it('should be a function', function () {
    const fs = util.fs();
    expect(typeof fs.access).to.equal('function');
  });

  it('should return an error if file does not exist', function (done) {
    const fs = util.fs();

    fs.access('/tmp', fs.constants.F_OK, function (error) {
      expect(error).to.exist;
      expect(error.code).to.equal('ENOENT');
      done();
    });
  });

  it('should return no error if file does exist and mode = F_OK', function (done) {
    const fs = util.fs();
    const contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.access('/myfile', fs.constants.F_OK, function (error) {
        expect(error).not.to.exist;
        done();
      });
    });
  });

  it('should return no error if file does exist and mode = R_OK', function (done) {
    const fs = util.fs();
    const contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.access('/myfile', fs.constants.R_OK, function (error) {
        expect(error).not.to.exist;
        done();
      });
    });
  });

  it('should return no error if file does exist and mode = W_OK', function (done) {
    const fs = util.fs();
    const contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.access('/myfile', fs.constants.W_OK, function (error) {
        expect(error).not.to.exist;
        done();
      });
    });
  });

  it('should return an error if file is not executable and mode = X_OK', function (done) {
    const fs = util.fs();
    const contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.chmod('/myfile', '644', function(error){
        if (error) throw error;

        fs.access('/myfile', fs.constants.X_OK, function (error) {
          expect(error).to.exist;
          expect(error.code).to.equal('EACCES');
          done();
        });
      });
    });
  });

  it('should return no error if file does exist and mode = X_OK', function (done) {
    const fs = util.fs();
    const contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.chmod('/myfile', 0o777, function(error) {
        if (error) throw error;

        fs.access('/myfile', fs.constants.X_OK, function (error) {
          expect(error).not.to.exist;
          done();
        });
      });
    });
  });

  it('should return no error if file does exist and no mode is passed', function (done) {
    const fs = util.fs();
    const contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.access('/myfile', function (error) {
        expect(error).not.to.exist;
        done();
      });
    });
  });

  it('should return no error if file does exist and mode = R_OK | W_OK', function (done) {
    const fs = util.fs();
    const contents = 'This is a file.';

    fs.writeFile('/myfile', contents, function (error) {
      if (error) throw error;

      fs.access('/myfile', fs.constants.R_OK | fs.constants.W_OK, function (error) {
        expect(error).not.to.exist;
        done();
      });
    });
  });
});
<|endoftext|>


<commit_before>/**
 Copyright 2014 Gordon Williams (gw@pur3.co.uk)

 This Source Code is subject to the terms of the Mozilla Public
 License, v2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.

 ------------------------------------------------------------------
  Automatically load any referenced modules
 ------------------------------------------------------------------
**/
"use strict";
(function(){

  function init() {
    Espruino.Core.Config.add("MODULE_URL", {
      section : "Communications",
      name : "Module URL",
      description : "Where to search online for modules when `require()` is used",
      type : "string",
      defaultValue : "https://www.espruino.com/modules"
    });
    Espruino.Core.Config.add("MODULE_EXTENSIONS", {
      section : "Communications",
      name : "Module Extensions",
      description : "The file extensions to use for each module. These are checked in order and the first that exists is used. One or more file extensions (including the dot) separated by `|`",
      type : "string",
      defaultValue : ".min.js|.js"
    });
    Espruino.Core.Config.add("MODULE_AS_FUNCTION", {
      section : "Communications",
      name : "Modules uploaded as functions (BETA)",
      description : "Espruino 1v90 and later ONLY. Upload modules as Functions, allowing any functions inside them to be loaded directly from flash when 'Save on Send' is enabled.",
      type : "boolean",
      defaultValue : false
    });

    Espruino.Core.Config.add("MODULE_PROXY_ENABLED", {
      section : "Communications",
      name : "Enable Proxy",
      description : "Enable Proxy for loading the modules when `require()` is used (only in native IDE)",
      type : "boolean",
      defaultValue : false
    });

    Espruino.Core.Config.add("MODULE_PROXY_URL", {
      section : "Communications",
      name : "Proxy URL",
      description : "Proxy URL for loading the modules when `require()` is used (only in native IDE)",
      type : "string",
      defaultValue : ""
    });

    Espruino.Core.Config.add("MODULE_PROXY_PORT", {
      section : "Communications",
      name : "Proxy Port",
      description : "Proxy Port for loading the modules when `require()` is used (only in native IDE)",
      type : "string",
      defaultValue : ""
    });

    // When code is sent to Espruino, search it for modules and add extra code required to load them
    Espruino.addProcessor("transformForEspruino", function(code, callback) {
      loadModules(code, callback);
    });
  }

  function isBuiltIn(module) {
    var d = Espruino.Core.Env.getData();
    // If we got data from the device itself, use that as the
    // definitive answer
    if ("MODULES" in d)
      return d.MODULES.split(",").indexOf("fs");
    // Otherwise try and figure it out from JSON
    if ("info" in d &&
        "builtin_modules" in d.info &&
        d.info.builtin_modules.indexOf(module)>=0)
      return true;
    // Otherwise assume we don't have it
    return false;
  }

  /** Find any instances of require(...) in the code string and return a list */
  var getModulesRequired = function(code) {
    var modules = [];

    var lex = Espruino.Core.Utils.getLexer(code);
    var tok = lex.next();
    var state = 0;
    while (tok!==undefined) {
      if (state==0 && tok.str=="require") {
        state=1;
      } else if (state==1 && tok.str=="(") {
        state=2;
      } else if (state==2 && (tok.type=="STRING")) {
        state=0;
        var module = tok.value;
        if (!isBuiltIn(module) && modules.indexOf(module)<0)
          modules.push(module);
      } else
        state = 0;
      tok = lex.next();
    }

    return modules;
  };

  /** Called from loadModule when a module is loaded. Parse it for other modules it might use
   *  and resolve dfd after all submodules have been loaded */
  function moduleLoaded(resolve, requires, modName, data, loadedModuleData, alreadyMinified){
    // Check for any modules used from this module that we don't already have
    var newRequires = getModulesRequired(data);
    console.log(" - "+modName+" requires "+JSON.stringify(newRequires));
    // if we need new modules, set them to load and get their promises
    var newPromises = [];
    for (var i in newRequires) {
      if (requires.indexOf(newRequires[i])<0) {
        console.log("   Queueing "+newRequires[i]);
        requires.push(newRequires[i]);
        newPromises.push(loadModule(requires, newRequires[i], loadedModuleData));
      } else {
        console.log("   Already loading "+newRequires[i]);
      }
    }

    var loadProcessedModule = function (moduleCode) {
      // add the module to the beginning of our array
      if (Espruino.Config.MODULE_AS_FUNCTION)
        loadedModuleData.unshift("Modules.addCached(" + JSON.stringify(modName) + ",function(){" + moduleCode + "});");
      else
        loadedModuleData.unshift("Modules.addCached(" + JSON.stringify(modName) + "," + JSON.stringify(moduleCode) + ");");
      // if we needed to load something, wait until we have all promises complete before resolving our promise!
      Promise.all(newPromises).then(function(){ resolve(); });
    }
    if (alreadyMinified)
      loadProcessedModule(data);
    else
      Espruino.callProcessor("transformModuleForEspruino", data, loadProcessedModule);
  }

  /** Given a module name (which could be a URL), try and find it. Return
   * a deferred thingybob which signals when we're done. */
  function loadModule(requires, fullModuleName, loadedModuleData) {
    return new Promise(function(resolve, reject) {
      // First off, try and find this module using callProcessor
      Espruino.callProcessor("getModule",
        { moduleName:fullModuleName, moduleCode:undefined },
        function(data) {
          if (data.moduleCode!==undefined) {
            // great! it found something. Use it.
            moduleLoaded(resolve, requires, fullModuleName, data.moduleCode, loadedModuleData, false);
          } else {
            // otherwise try and load the module the old way...
            console.log("loadModule("+fullModuleName+")");

            var urls = []; // Array of where to look for this module
            var modName; // Simple name of the module
            if(Espruino.Core.Utils.isURL(fullModuleName)) {
              modName = fullModuleName.substr(fullModuleName.lastIndexOf("/") + 1).split(".")[0];
              urls = [ fullModuleName ];
            } else {
              modName = fullModuleName;
              Espruino.Config.MODULE_URL.split("|").forEach(function (url) {
                url = url.trim();
                if (url.length!=0)
                  Espruino.Config.MODULE_EXTENSIONS.split("|").forEach(function (extension) {
                    urls.push(url + "/" + fullModuleName + extension);
                  })
              });
            };

            // Recursively go through all the urls
            (function download(urls) {
              if (urls.length==0) {
                Espruino.Core.Notifications.warning("Module "+fullModuleName+" not found");
                return resolve();
              }
              var dlUrl = urls[0];
              Espruino.Core.Utils.getURL(dlUrl, function (data) {
                if (data!==undefined) {
                  // we got it!
                  moduleLoaded(resolve, requires, fullModuleName, data, loadedModuleData, dlUrl.substr(-7)==".min.js");
                } else {
                  // else try next
                  download(urls.slice(1));
                }
              });
            })(urls);
          }
        });

    });
  }

  /** Finds instances of 'require' and then ensures that
   those modules are loaded into the module cache beforehand
   (by inserting the relevant 'addCached' commands into 'code' */
  function loadModules(code, callback){
    var loadedModuleData = [];
    var requires = getModulesRequired(code);
    if (requires.length == 0) {
      // no modules needed - just return
      callback(code);
    } else {
      // Kick off the module loading (each returns a promise)
      var promises = requires.map(function (moduleName) {
        return loadModule(requires, moduleName, loadedModuleData);
      });
      // When all promises are complete
      Promise.all(promises).then(function(){
        callback(loadedModuleData.join("\n") + "\n" + code);
      });
    }
  };

  Espruino.Core.Modules = {
    init : init
  };
}());
<commit_msg>argh.<commit_after>/**
 Copyright 2014 Gordon Williams (gw@pur3.co.uk)

 This Source Code is subject to the terms of the Mozilla Public
 License, v2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.

 ------------------------------------------------------------------
  Automatically load any referenced modules
 ------------------------------------------------------------------
**/
"use strict";
(function(){

  function init() {
    Espruino.Core.Config.add("MODULE_URL", {
      section : "Communications",
      name : "Module URL",
      description : "Where to search online for modules when `require()` is used",
      type : "string",
      defaultValue : "https://www.espruino.com/modules"
    });
    Espruino.Core.Config.add("MODULE_EXTENSIONS", {
      section : "Communications",
      name : "Module Extensions",
      description : "The file extensions to use for each module. These are checked in order and the first that exists is used. One or more file extensions (including the dot) separated by `|`",
      type : "string",
      defaultValue : ".min.js|.js"
    });
    Espruino.Core.Config.add("MODULE_AS_FUNCTION", {
      section : "Communications",
      name : "Modules uploaded as functions (BETA)",
      description : "Espruino 1v90 and later ONLY. Upload modules as Functions, allowing any functions inside them to be loaded directly from flash when 'Save on Send' is enabled.",
      type : "boolean",
      defaultValue : false
    });

    Espruino.Core.Config.add("MODULE_PROXY_ENABLED", {
      section : "Communications",
      name : "Enable Proxy",
      description : "Enable Proxy for loading the modules when `require()` is used (only in native IDE)",
      type : "boolean",
      defaultValue : false
    });

    Espruino.Core.Config.add("MODULE_PROXY_URL", {
      section : "Communications",
      name : "Proxy URL",
      description : "Proxy URL for loading the modules when `require()` is used (only in native IDE)",
      type : "string",
      defaultValue : ""
    });

    Espruino.Core.Config.add("MODULE_PROXY_PORT", {
      section : "Communications",
      name : "Proxy Port",
      description : "Proxy Port for loading the modules when `require()` is used (only in native IDE)",
      type : "string",
      defaultValue : ""
    });

    // When code is sent to Espruino, search it for modules and add extra code required to load them
    Espruino.addProcessor("transformForEspruino", function(code, callback) {
      loadModules(code, callback);
    });
  }

  function isBuiltIn(module) {
    var d = Espruino.Core.Env.getData();
    // If we got data from the device itself, use that as the
    // definitive answer
    if ("MODULES" in d)
      return d.MODULES.split(",").indexOf(module)>=0;
    // Otherwise try and figure it out from JSON
    if ("info" in d &&
        "builtin_modules" in d.info &&
        d.info.builtin_modules.indexOf(module)>=0)
      return true;
    // Otherwise assume we don't have it
    return false;
  }

  /** Find any instances of require(...) in the code string and return a list */
  var getModulesRequired = function(code) {
    var modules = [];

    var lex = Espruino.Core.Utils.getLexer(code);
    var tok = lex.next();
    var state = 0;
    while (tok!==undefined) {
      if (state==0 && tok.str=="require") {
        state=1;
      } else if (state==1 && tok.str=="(") {
        state=2;
      } else if (state==2 && (tok.type=="STRING")) {
        state=0;
        var module = tok.value;
        if (!isBuiltIn(module) && modules.indexOf(module)<0)
          modules.push(module);
      } else
        state = 0;
      tok = lex.next();
    }

    return modules;
  };

  /** Called from loadModule when a module is loaded. Parse it for other modules it might use
   *  and resolve dfd after all submodules have been loaded */
  function moduleLoaded(resolve, requires, modName, data, loadedModuleData, alreadyMinified){
    // Check for any modules used from this module that we don't already have
    var newRequires = getModulesRequired(data);
    console.log(" - "+modName+" requires "+JSON.stringify(newRequires));
    // if we need new modules, set them to load and get their promises
    var newPromises = [];
    for (var i in newRequires) {
      if (requires.indexOf(newRequires[i])<0) {
        console.log("   Queueing "+newRequires[i]);
        requires.push(newRequires[i]);
        newPromises.push(loadModule(requires, newRequires[i], loadedModuleData));
      } else {
        console.log("   Already loading "+newRequires[i]);
      }
    }

    var loadProcessedModule = function (moduleCode) {
      // add the module to the beginning of our array
      if (Espruino.Config.MODULE_AS_FUNCTION)
        loadedModuleData.unshift("Modules.addCached(" + JSON.stringify(modName) + ",function(){" + moduleCode + "});");
      else
        loadedModuleData.unshift("Modules.addCached(" + JSON.stringify(modName) + "," + JSON.stringify(moduleCode) + ");");
      // if we needed to load something, wait until we have all promises complete before resolving our promise!
      Promise.all(newPromises).then(function(){ resolve(); });
    }
    if (alreadyMinified)
      loadProcessedModule(data);
    else
      Espruino.callProcessor("transformModuleForEspruino", data, loadProcessedModule);
  }

  /** Given a module name (which could be a URL), try and find it. Return
   * a deferred thingybob which signals when we're done. */
  function loadModule(requires, fullModuleName, loadedModuleData) {
    return new Promise(function(resolve, reject) {
      // First off, try and find this module using callProcessor
      Espruino.callProcessor("getModule",
        { moduleName:fullModuleName, moduleCode:undefined },
        function(data) {
          if (data.moduleCode!==undefined) {
            // great! it found something. Use it.
            moduleLoaded(resolve, requires, fullModuleName, data.moduleCode, loadedModuleData, false);
          } else {
            // otherwise try and load the module the old way...
            console.log("loadModule("+fullModuleName+")");

            var urls = []; // Array of where to look for this module
            var modName; // Simple name of the module
            if(Espruino.Core.Utils.isURL(fullModuleName)) {
              modName = fullModuleName.substr(fullModuleName.lastIndexOf("/") + 1).split(".")[0];
              urls = [ fullModuleName ];
            } else {
              modName = fullModuleName;
              Espruino.Config.MODULE_URL.split("|").forEach(function (url) {
                url = url.trim();
                if (url.length!=0)
                  Espruino.Config.MODULE_EXTENSIONS.split("|").forEach(function (extension) {
                    urls.push(url + "/" + fullModuleName + extension);
                  })
              });
            };

            // Recursively go through all the urls
            (function download(urls) {
              if (urls.length==0) {
                Espruino.Core.Notifications.warning("Module "+fullModuleName+" not found");
                return resolve();
              }
              var dlUrl = urls[0];
              Espruino.Core.Utils.getURL(dlUrl, function (data) {
                if (data!==undefined) {
                  // we got it!
                  moduleLoaded(resolve, requires, fullModuleName, data, loadedModuleData, dlUrl.substr(-7)==".min.js");
                } else {
                  // else try next
                  download(urls.slice(1));
                }
              });
            })(urls);
          }
        });

    });
  }

  /** Finds instances of 'require' and then ensures that
   those modules are loaded into the module cache beforehand
   (by inserting the relevant 'addCached' commands into 'code' */
  function loadModules(code, callback){
    var loadedModuleData = [];
    var requires = getModulesRequired(code);
    if (requires.length == 0) {
      // no modules needed - just return
      callback(code);
    } else {
      // Kick off the module loading (each returns a promise)
      var promises = requires.map(function (moduleName) {
        return loadModule(requires, moduleName, loadedModuleData);
      });
      // When all promises are complete
      Promise.all(promises).then(function(){
        callback(loadedModuleData.join("\n") + "\n" + code);
      });
    }
  };

  Espruino.Core.Modules = {
    init : init
  };
}());
<|endoftext|>


<commit_before>var Chess = require('chess.js').Chess,
    white = require('../ai.js'),
    // black = require('../sample-players/rnd-jesus.js'),
    black = require('../sample-players/endgamer.js'),
    // black = require('../sample-players/minmaxer.js'),
    chess = new Chess(),

    SUPPORT_UNICODE = true,

    unicodeMap = {
        'K': '\u2654',
        'Q': '\u2655',
        'R': '\u2656',
        'B': '\u2657',
        'N': '\u2658',
        'P': '\u2659',
        'k': '\u265A',
        'q': '\u265B',
        'r': '\u265C',
        'b': '\u265D',
        'n': '\u265E',
        'p': '\u265F'
    };

var unicode = function (ascii) {
    if (!SUPPORT_UNICODE) {
        return ascii;
    }
    return Object.keys(unicodeMap).reduce(function (acc, val) {
        return acc.replace(new RegExp(val, 'g'), unicodeMap[val]);
    }, ascii);
};

var reason = function (chess) {
    if (chess.in_checkmate()) {
        var winner = chess.turn() === 'w' ? 'Black' : 'White';
        return winner + ' won by checkmate';
    }

    if (chess.insufficient_material()) {
        return 'Draw by insufficient material';
    }

    if (chess.in_stalemate()) {
        return 'Draw by stalemate';
    }

    if (chess.in_threefold_repetition()) {
        return 'Draw by threefold repetition';
    }

    return 'Draw since the game lasted over 100 moves';
};

var doMove = function (chess, white, black, move) {
    chess.move(move);
    console.log(unicode(chess.ascii() + '\n\r K = White, k = ') + 'Black');

    setTimeout(function () {
        play(chess, white, black);
    }, 10);
};

var play = function (chess, white, black) {
    if (chess.game_over()) {
        console.log(reason(chess));
        return;
    };

    var board = chess.fen(),
        player = chess.turn() === 'w' ? white : black;
        move = player.move(board);

    if (typeof move === "string") {
        doMove(chess, white, black, move);
    } else {
        move.then(function (move) {
            doMove(chess, white, black, move);
        }).catch(function (err) {
            console.log(err.error);
            doMove(chess, white, black, err.move);
        });
    }
};

play(chess, white, black);<commit_msg>Change back to playing random and not endgame<commit_after>var Chess = require('chess.js').Chess,
    white = require('../ai.js'),
    black = require('../sample-players/rnd-jesus.js'),
    // black = require('../sample-players/endgamer.js'),
    // black = require('../sample-players/minmaxer.js'),
    chess = new Chess(),

    SUPPORT_UNICODE = true,

    unicodeMap = {
        'K': '\u2654',
        'Q': '\u2655',
        'R': '\u2656',
        'B': '\u2657',
        'N': '\u2658',
        'P': '\u2659',
        'k': '\u265A',
        'q': '\u265B',
        'r': '\u265C',
        'b': '\u265D',
        'n': '\u265E',
        'p': '\u265F'
    };

var unicode = function (ascii) {
    if (!SUPPORT_UNICODE) {
        return ascii;
    }
    return Object.keys(unicodeMap).reduce(function (acc, val) {
        return acc.replace(new RegExp(val, 'g'), unicodeMap[val]);
    }, ascii);
};

var reason = function (chess) {
    if (chess.in_checkmate()) {
        var winner = chess.turn() === 'w' ? 'Black' : 'White';
        return winner + ' won by checkmate';
    }

    if (chess.insufficient_material()) {
        return 'Draw by insufficient material';
    }

    if (chess.in_stalemate()) {
        return 'Draw by stalemate';
    }

    if (chess.in_threefold_repetition()) {
        return 'Draw by threefold repetition';
    }

    return 'Draw since the game lasted over 100 moves';
};

var doMove = function (chess, white, black, move) {
    chess.move(move);
    console.log(unicode(chess.ascii() + '\n\r K = White, k = ') + 'Black');

    setTimeout(function () {
        play(chess, white, black);
    }, 10);
};

var play = function (chess, white, black) {
    if (chess.game_over()) {
        console.log(reason(chess));
        return;
    };

    var board = chess.fen(),
        player = chess.turn() === 'w' ? white : black;
        move = player.move(board);

    if (typeof move === "string") {
        doMove(chess, white, black, move);
    } else {
        move.then(function (move) {
            doMove(chess, white, black, move);
        }).catch(function (err) {
            console.log(err.error);
            doMove(chess, white, black, err.move);
        });
    }
};

play(chess, white, black);<|endoftext|>


<commit_before>var DOMutil = require('../../../DOMutil');
var Points = require('./points');

function Bargraph(groupId, options) {
  this.groupId = groupId;
  this.options = options;
}

Bargraph.prototype.getYRange = function(groupData) {
  var yMin = groupData[0].y;
  var yMax = groupData[0].y;
  for (var j = 0; j < groupData.length; j++) {
    yMin = yMin > groupData[j].y ? groupData[j].y : yMin;
    yMax = yMax < groupData[j].y ? groupData[j].y : yMax;
  }
  return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation};
};

Bargraph.prototype.getData = function(groupData) {
  var combinedData = [];
  for (var j = 0; j < groupData.length; j++) {
    combinedData.push({
      x: groupData[j].x,
      y: groupData[j].y,
      groupId: this.groupId
    });
  }
  return combinedData;
}

/**
 * draw a bar graph
 *
 * @param groupIds
 * @param processedGroupData
 */
Bargraph.draw = function (groupIds, processedGroupData, framework) {
  var combinedData = [];
  var intersections = {};
  var coreDistance;
  var key, drawData;
  var group;
  var i,j;
  var barPoints = 0;

  // combine all barchart data
  for (i = 0; i < groupIds.length; i++) {
    group = framework.groups[groupIds[i]];
    if (group.options.style === 'bar') {
      if (group.visible === true && (framework.options.groups.visibility[groupIds[i]] === undefined || framework.options.groups.visibility[groupIds[i]] === true)) {
        for (j = 0; j < processedGroupData[groupIds[i]].length; j++) {
          combinedData.push({
            x: processedGroupData[groupIds[i]][j].x,
            y: processedGroupData[groupIds[i]][j].y,
            groupId: groupIds[i],
            label: processedGroupData[groupIds[i]][j].label
          });
          barPoints += 1;
        }
      }
    }
  }

  if (barPoints === 0) {return;}

  // sort by time and by group
  combinedData.sort(function (a, b) {
    if (a.x === b.x) {
      return a.groupId < b.groupId ? -1 : 1;
    }
    else {
      return a.x - b.x;
    }
  });

  // get intersections
  Bargraph._getDataIntersections(intersections, combinedData);

  // plot barchart
  for (i = 0; i < combinedData.length; i++) {
    group = framework.groups[combinedData[i].groupId];
    var minWidth = 0.1 * group.options.barChart.width;

    key = combinedData[i].x;
    var heightOffset = 0;
    if (intersections[key] === undefined) {
      if (i+1 < combinedData.length) {coreDistance = Math.abs(combinedData[i+1].x - key);}
      if (i > 0)                     {coreDistance = Math.min(coreDistance,Math.abs(combinedData[i-1].x - key));}
      drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth);
    }
    else {
      var nextKey = i + (intersections[key].amount - intersections[key].resolved);
      var prevKey = i - (intersections[key].resolved + 1);
      if (nextKey < combinedData.length) {coreDistance = Math.abs(combinedData[nextKey].x - key);}
      if (prevKey > 0)                   {coreDistance = Math.min(coreDistance,Math.abs(combinedData[prevKey].x - key));}
      drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth);
      intersections[key].resolved += 1;

      if (group.options.stack === true) {
        if (combinedData[i].y < group.zeroPosition) {
          heightOffset = intersections[key].accumulatedNegative;
          intersections[key].accumulatedNegative += group.zeroPosition - combinedData[i].y;
        }
        else {
          heightOffset = intersections[key].accumulatedPositive;
          intersections[key].accumulatedPositive += group.zeroPosition - combinedData[i].y;
        }
      }
      else if (group.options.barChart.sideBySide === true) {
        drawData.width = drawData.width / intersections[key].amount;
        drawData.offset += (intersections[key].resolved) * drawData.width - (0.5*drawData.width * (intersections[key].amount+1));
        if (group.options.barChart.align === 'left')       {drawData.offset -= 0.5*drawData.width;}
        else if (group.options.barChart.align === 'right') {drawData.offset += 0.5*drawData.width;}
      }
    }
    console.log(group)
    DOMutil.drawBar(combinedData[i].x + drawData.offset, combinedData[i].y - heightOffset, drawData.width, group.zeroPosition - combinedData[i].y, group.className + ' vis-bar', framework.svgElements, framework.svg, group.style);
    // draw points
    if (group.options.drawPoints.enabled === true) {
      Points.draw([combinedData[i]], group, framework, drawData.offset);
      //DOMutil.drawPoint(combinedData[i].x + drawData.offset, combinedData[i].y, group, framework.svgElements, framework.svg);
    }
  }
};

/**
 * Fill the intersections object with counters of how many datapoints share the same x coordinates
 * @param intersections
 * @param combinedData
 * @private
 */
Bargraph._getDataIntersections = function (intersections, combinedData) {
  // get intersections
  var coreDistance;
  for (var i = 0; i < combinedData.length; i++) {
    if (i + 1 < combinedData.length) {
      coreDistance = Math.abs(combinedData[i + 1].x - combinedData[i].x);
    }
    if (i > 0) {
      coreDistance = Math.min(coreDistance, Math.abs(combinedData[i - 1].x - combinedData[i].x));
    }
    if (coreDistance === 0) {
      if (intersections[combinedData[i].x] === undefined) {
        intersections[combinedData[i].x] = {amount: 0, resolved: 0, accumulatedPositive: 0, accumulatedNegative: 0};
      }
      intersections[combinedData[i].x].amount += 1;
    }
  }
};

/**
 * Get the width and offset for bargraphs based on the coredistance between datapoints
 *
 * @param coreDistance
 * @param group
 * @param minWidth
 * @returns {{width: Number, offset: Number}}
 * @private
 */
Bargraph._getSafeDrawData = function (coreDistance, group, minWidth) {
  var width, offset;
  if (coreDistance < group.options.barChart.width && coreDistance > 0) {
    width = coreDistance < minWidth ? minWidth : coreDistance;

    offset = 0; // recalculate offset with the new width;
    if (group.options.barChart.align === 'left') {
      offset -= 0.5 * coreDistance;
    }
    else if (group.options.barChart.align === 'right') {
      offset += 0.5 * coreDistance;
    }
  }
  else {
    // default settings
    width = group.options.barChart.width;
    offset = 0;
    if (group.options.barChart.align === 'left') {
      offset -= 0.5 * group.options.barChart.width;
    }
    else if (group.options.barChart.align === 'right') {
      offset += 0.5 * group.options.barChart.width;
    }
  }

  return {width: width, offset: offset};
};

Bargraph.getStackedYRange = function(combinedData, groupRanges, groupIds, groupLabel, orientation) {
  if (combinedData.length > 0) {
    // sort by time and by group
    combinedData.sort(function (a, b) {
      if (a.x === b.x) {
        return a.groupId < b.groupId ? -1 : 1;
      }
      else {
        return a.x - b.x;
      }
    });
    var intersections = {};

    Bargraph._getDataIntersections(intersections, combinedData);
    groupRanges[groupLabel] = Bargraph._getStackedYRange(intersections, combinedData);
    groupRanges[groupLabel].yAxisOrientation = orientation;
    groupIds.push(groupLabel);
  }
}

Bargraph._getStackedYRange = function (intersections, combinedData) {
  var key;
  var yMin = combinedData[0].y;
  var yMax = combinedData[0].y;
  for (var i = 0; i < combinedData.length; i++) {
    key = combinedData[i].x;
    if (intersections[key] === undefined) {
      yMin = yMin > combinedData[i].y ? combinedData[i].y : yMin;
      yMax = yMax < combinedData[i].y ? combinedData[i].y : yMax;
    }
    else {
      if (combinedData[i].y < 0) {
        intersections[key].accumulatedNegative += combinedData[i].y;
      }
      else {
        intersections[key].accumulatedPositive += combinedData[i].y;
      }
    }
  }
  for (var xpos in intersections) {
    if (intersections.hasOwnProperty(xpos)) {
      yMin = yMin > intersections[xpos].accumulatedNegative ? intersections[xpos].accumulatedNegative : yMin;
      yMin = yMin > intersections[xpos].accumulatedPositive ? intersections[xpos].accumulatedPositive : yMin;
      yMax = yMax < intersections[xpos].accumulatedNegative ? intersections[xpos].accumulatedNegative : yMax;
      yMax = yMax < intersections[xpos].accumulatedPositive ? intersections[xpos].accumulatedPositive : yMax;
    }
  }

  return {min: yMin, max: yMax};
};

module.exports = Bargraph;<commit_msg>removed log<commit_after>var DOMutil = require('../../../DOMutil');
var Points = require('./points');

function Bargraph(groupId, options) {
  this.groupId = groupId;
  this.options = options;
}

Bargraph.prototype.getYRange = function(groupData) {
  var yMin = groupData[0].y;
  var yMax = groupData[0].y;
  for (var j = 0; j < groupData.length; j++) {
    yMin = yMin > groupData[j].y ? groupData[j].y : yMin;
    yMax = yMax < groupData[j].y ? groupData[j].y : yMax;
  }
  return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation};
};

Bargraph.prototype.getData = function(groupData) {
  var combinedData = [];
  for (var j = 0; j < groupData.length; j++) {
    combinedData.push({
      x: groupData[j].x,
      y: groupData[j].y,
      groupId: this.groupId
    });
  }
  return combinedData;
}

/**
 * draw a bar graph
 *
 * @param groupIds
 * @param processedGroupData
 */
Bargraph.draw = function (groupIds, processedGroupData, framework) {
  var combinedData = [];
  var intersections = {};
  var coreDistance;
  var key, drawData;
  var group;
  var i,j;
  var barPoints = 0;

  // combine all barchart data
  for (i = 0; i < groupIds.length; i++) {
    group = framework.groups[groupIds[i]];
    if (group.options.style === 'bar') {
      if (group.visible === true && (framework.options.groups.visibility[groupIds[i]] === undefined || framework.options.groups.visibility[groupIds[i]] === true)) {
        for (j = 0; j < processedGroupData[groupIds[i]].length; j++) {
          combinedData.push({
            x: processedGroupData[groupIds[i]][j].x,
            y: processedGroupData[groupIds[i]][j].y,
            groupId: groupIds[i],
            label: processedGroupData[groupIds[i]][j].label
          });
          barPoints += 1;
        }
      }
    }
  }

  if (barPoints === 0) {return;}

  // sort by time and by group
  combinedData.sort(function (a, b) {
    if (a.x === b.x) {
      return a.groupId < b.groupId ? -1 : 1;
    }
    else {
      return a.x - b.x;
    }
  });

  // get intersections
  Bargraph._getDataIntersections(intersections, combinedData);

  // plot barchart
  for (i = 0; i < combinedData.length; i++) {
    group = framework.groups[combinedData[i].groupId];
    var minWidth = 0.1 * group.options.barChart.width;

    key = combinedData[i].x;
    var heightOffset = 0;
    if (intersections[key] === undefined) {
      if (i+1 < combinedData.length) {coreDistance = Math.abs(combinedData[i+1].x - key);}
      if (i > 0)                     {coreDistance = Math.min(coreDistance,Math.abs(combinedData[i-1].x - key));}
      drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth);
    }
    else {
      var nextKey = i + (intersections[key].amount - intersections[key].resolved);
      var prevKey = i - (intersections[key].resolved + 1);
      if (nextKey < combinedData.length) {coreDistance = Math.abs(combinedData[nextKey].x - key);}
      if (prevKey > 0)                   {coreDistance = Math.min(coreDistance,Math.abs(combinedData[prevKey].x - key));}
      drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth);
      intersections[key].resolved += 1;

      if (group.options.stack === true) {
        if (combinedData[i].y < group.zeroPosition) {
          heightOffset = intersections[key].accumulatedNegative;
          intersections[key].accumulatedNegative += group.zeroPosition - combinedData[i].y;
        }
        else {
          heightOffset = intersections[key].accumulatedPositive;
          intersections[key].accumulatedPositive += group.zeroPosition - combinedData[i].y;
        }
      }
      else if (group.options.barChart.sideBySide === true) {
        drawData.width = drawData.width / intersections[key].amount;
        drawData.offset += (intersections[key].resolved) * drawData.width - (0.5*drawData.width * (intersections[key].amount+1));
        if (group.options.barChart.align === 'left')       {drawData.offset -= 0.5*drawData.width;}
        else if (group.options.barChart.align === 'right') {drawData.offset += 0.5*drawData.width;}
      }
    }
    DOMutil.drawBar(combinedData[i].x + drawData.offset, combinedData[i].y - heightOffset, drawData.width, group.zeroPosition - combinedData[i].y, group.className + ' vis-bar', framework.svgElements, framework.svg, group.style);
    // draw points
    if (group.options.drawPoints.enabled === true) {
      Points.draw([combinedData[i]], group, framework, drawData.offset);
      //DOMutil.drawPoint(combinedData[i].x + drawData.offset, combinedData[i].y, group, framework.svgElements, framework.svg);
    }
  }
};

/**
 * Fill the intersections object with counters of how many datapoints share the same x coordinates
 * @param intersections
 * @param combinedData
 * @private
 */
Bargraph._getDataIntersections = function (intersections, combinedData) {
  // get intersections
  var coreDistance;
  for (var i = 0; i < combinedData.length; i++) {
    if (i + 1 < combinedData.length) {
      coreDistance = Math.abs(combinedData[i + 1].x - combinedData[i].x);
    }
    if (i > 0) {
      coreDistance = Math.min(coreDistance, Math.abs(combinedData[i - 1].x - combinedData[i].x));
    }
    if (coreDistance === 0) {
      if (intersections[combinedData[i].x] === undefined) {
        intersections[combinedData[i].x] = {amount: 0, resolved: 0, accumulatedPositive: 0, accumulatedNegative: 0};
      }
      intersections[combinedData[i].x].amount += 1;
    }
  }
};

/**
 * Get the width and offset for bargraphs based on the coredistance between datapoints
 *
 * @param coreDistance
 * @param group
 * @param minWidth
 * @returns {{width: Number, offset: Number}}
 * @private
 */
Bargraph._getSafeDrawData = function (coreDistance, group, minWidth) {
  var width, offset;
  if (coreDistance < group.options.barChart.width && coreDistance > 0) {
    width = coreDistance < minWidth ? minWidth : coreDistance;

    offset = 0; // recalculate offset with the new width;
    if (group.options.barChart.align === 'left') {
      offset -= 0.5 * coreDistance;
    }
    else if (group.options.barChart.align === 'right') {
      offset += 0.5 * coreDistance;
    }
  }
  else {
    // default settings
    width = group.options.barChart.width;
    offset = 0;
    if (group.options.barChart.align === 'left') {
      offset -= 0.5 * group.options.barChart.width;
    }
    else if (group.options.barChart.align === 'right') {
      offset += 0.5 * group.options.barChart.width;
    }
  }

  return {width: width, offset: offset};
};

Bargraph.getStackedYRange = function(combinedData, groupRanges, groupIds, groupLabel, orientation) {
  if (combinedData.length > 0) {
    // sort by time and by group
    combinedData.sort(function (a, b) {
      if (a.x === b.x) {
        return a.groupId < b.groupId ? -1 : 1;
      }
      else {
        return a.x - b.x;
      }
    });
    var intersections = {};

    Bargraph._getDataIntersections(intersections, combinedData);
    groupRanges[groupLabel] = Bargraph._getStackedYRange(intersections, combinedData);
    groupRanges[groupLabel].yAxisOrientation = orientation;
    groupIds.push(groupLabel);
  }
}

Bargraph._getStackedYRange = function (intersections, combinedData) {
  var key;
  var yMin = combinedData[0].y;
  var yMax = combinedData[0].y;
  for (var i = 0; i < combinedData.length; i++) {
    key = combinedData[i].x;
    if (intersections[key] === undefined) {
      yMin = yMin > combinedData[i].y ? combinedData[i].y : yMin;
      yMax = yMax < combinedData[i].y ? combinedData[i].y : yMax;
    }
    else {
      if (combinedData[i].y < 0) {
        intersections[key].accumulatedNegative += combinedData[i].y;
      }
      else {
        intersections[key].accumulatedPositive += combinedData[i].y;
      }
    }
  }
  for (var xpos in intersections) {
    if (intersections.hasOwnProperty(xpos)) {
      yMin = yMin > intersections[xpos].accumulatedNegative ? intersections[xpos].accumulatedNegative : yMin;
      yMin = yMin > intersections[xpos].accumulatedPositive ? intersections[xpos].accumulatedPositive : yMin;
      yMax = yMax < intersections[xpos].accumulatedNegative ? intersections[xpos].accumulatedNegative : yMax;
      yMax = yMax < intersections[xpos].accumulatedPositive ? intersections[xpos].accumulatedPositive : yMax;
    }
  }

  return {min: yMin, max: yMax};
};

module.exports = Bargraph;<|endoftext|>


<commit_before>const fs = require('fs')
const os = require('os')

const REPLACEMENT_ENV = process.argv[2]
const ENV_TYPE = process.argv[3]

// Environment Setup
let myEnv
if (ENV_TYPE === 'ci') {
	myEnv = process.env
} else {
	myEnv = require(os.homedir() + '/.campusmobile/env.js') // eslint-disable-line
}

// File Paths
const APP_SETTINGS_PATH = './app/AppSettings.js',
	SSO_SERVICE_PATH = './app/services/ssoService.js',
	IOS_INFO_PLIST_PATH = './ios/CampusMobile/Info.plist',
	ANDROID_STRINGS_PATH = './android/app/src/main/res/values/strings.xml',
	ANDROID_MANIFEST_PATH = './android/app/src/main/AndroidManifest.xml',
	IOS_GOOGLE_SERVICES_PATH = './ios/GoogleService-Info.plist',
	ANDROID_GOOGLE_SERVICES_PATH = './android/app/google-services.json'

// Placeholder Values
const PH = {
	APP_NAME_PH: 'CampusMobile',
	GOOGLE_ANALYTICS_ID_PH: 'GOOGLE_ANALYTICS_ID_PH',
	GOOGLE_MAPS_API_KEY_PH: 'GOOGLE_MAPS_API_KEY_PH',
	FIREBASE_KEY_PH: 'FIREBASE_KEY_PH',
	BUGSNAG_KEY_PH: 'BUGSNAG_KEY_PH',
	AUTH_SERVICE_API_KEY_PH: 'AUTH_SERVICE_API_KEY_PH',
	GS_PROJECT_ID_PH: 'GS_PROJECT_ID_PH',
	GS_STORAGE_BUCKET_PH: 'GS_STORAGE_BUCKET_PH',
	GS_FIREBASE_URL_PH: 'GS_FIREBASE_URL_PH',
	GS_PROJECT_NUMBER_PH: 'GS_PROJECT_NUMBER_PH', // iOS: GCM_SENDER_ID, Android: project_info.project_number
	GS_IOS_CLIENT_ID_PH: 'GS_IOS_CLIENT_ID_PH',
	GS_IOS_REVERSED_CLIENT_ID_PH: 'GS_IOS_REVERSED_CLIENT_ID_PH',
	GS_IOS_API_KEY_PH: 'GS_IOS_API_KEY_PH',
	GS_IOS_BUNDLE_ID_PH: 'GS_IOS_BUNDLE_ID_PH',
	GS_IOS_STORAGE_BUCKET_PH: 'GS_IOS_STORAGE_BUCKET_PH',
	GS_IOS_APP_ID_PH: '1:1:ios:1',
	GS_ANDROID_CLIENT_ID_PH: 'GS_ANDROID_CLIENT_ID_PH',
	GS_ANDROID_API_KEY_PH: 'GS_ANDROID_API_KEY_PH',
	GS_ANDROID_APP_ID_PH: '1:1:android:1',
	GS_ANDROID_BUNDLE_ID_PH: 'edu.ucsd',
}

if (REPLACEMENT_ENV === 'prod' || REPLACEMENT_ENV === 'qa') {
	// AppSettings.js
	makeReplacements(APP_SETTINGS_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.APP_NAME, qaVal: myEnv.APP_NAME, phVal: PH.APP_NAME_PH },
		{ prodVal: myEnv.GOOGLE_ANALYTICS_ID_PROD, qaVal: myEnv.GOOGLE_ANALYTICS_ID_QA, phVal: PH.GOOGLE_ANALYTICS_ID_PH },
	])

	// ssoService.js
	makeReplacements(SSO_SERVICE_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.AUTH_SERVICE_API_KEY_PROD, qaVal: myEnv.AUTH_SERVICE_API_KEY_QA, phVal: PH.AUTH_SERVICE_API_KEY_PH },
	])

	// Info.plist
	makeReplacements(IOS_INFO_PLIST_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.APP_NAME, qaVal: myEnv.APP_NAME, phVal: PH.APP_NAME_PH },
		{ prodVal: myEnv.BUGSNAG_KEY, qaVal: myEnv.BUGSNAG_KEY, phVal: PH.BUGSNAG_KEY_PH }
	])

	// strings.xml
	makeReplacements(ANDROID_STRINGS_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.APP_NAME, qaVal: myEnv.APP_NAME, phVal: PH.APP_NAME_PH },
	])

	// AndroidManifest.xml
	makeReplacements(ANDROID_MANIFEST_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.GOOGLE_MAPS_API_KEY, qaVal: myEnv.GOOGLE_MAPS_API_KEY, phVal: PH.GOOGLE_MAPS_API_KEY_PH },
		{ prodVal: myEnv.BUGSNAG_KEY, qaVal: myEnv.BUGSNAG_KEY, phVal: PH.BUGSNAG_KEY_PH }
	])

	// GoogleService-Info.plist
	makeReplacements(IOS_GOOGLE_SERVICES_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.GS_IOS_PROD_CLIENT_ID, 				qaVal: myEnv.GS_IOS_QA_CLIENT_ID, 				phVal: PH.GS_IOS_CLIENT_ID_PH },
		{ prodVal: myEnv.GS_IOS_PROD_REVERSED_CLIENT_ID,		qaVal: myEnv.GS_IOS_QA_REVERSED_CLIENT_ID, 		phVal: PH.GS_IOS_REVERSED_CLIENT_ID_PH },
		{ prodVal: myEnv.GS_IOS_PROD_API_KEY, 					qaVal: myEnv.GS_IOS_QA_API_KEY, 				phVal: PH.GS_IOS_API_KEY_PH },
		{ prodVal: myEnv.GS_IOS_BUNDLE_ID, 						qaVal: myEnv.GS_IOS_BUNDLE_ID, 					phVal: PH.GS_IOS_BUNDLE_ID_PH },
		{ prodVal: myEnv.GS_IOS_PROD_APP_ID, 					qaVal: myEnv.GS_IOS_QA_APP_ID, 					phVal: PH.GS_IOS_APP_ID_PH },
		{ prodVal: myEnv.GS_PROD_FIREBASE_URL, 					qaVal: myEnv.GS_QA_FIREBASE_URL, 				phVal: PH.GS_FIREBASE_URL_PH },
		{ prodVal: myEnv.GS_PROD_STORAGE_BUCKET, 				qaVal: myEnv.GS_QA_STORAGE_BUCKET, 				phVal: PH.GS_STORAGE_BUCKET_PH },
		{ prodVal: myEnv.GS_PROD_PROJECT_ID, 					qaVal: myEnv.GS_QA_PROJECT_ID, 					phVal: PH.GS_PROJECT_ID_PH },
		{ prodVal: myEnv.GS_PROD_PROJECT_NUMBER, 				qaVal: myEnv.GS_QA_PROJECT_NUMBER, 				phVal: PH.GS_PROJECT_NUMBER_PH },
	])

	// google-services.json
	makeReplacements(ANDROID_GOOGLE_SERVICES_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.GS_ANDROID_PROD_CLIENT_ID, 			qaVal: myEnv.GS_ANDROID_QA_CLIENT_ID, 			phVal: PH.GS_ANDROID_CLIENT_ID_PH },
		{ prodVal: myEnv.GS_ANDROID_PROD_API_KEY, 				qaVal: myEnv.GS_ANDROID_QA_API_KEY, 			phVal: PH.GS_ANDROID_API_KEY_PH },
		{ prodVal: myEnv.GS_ANDROID_PROD_APP_ID, 				qaVal: myEnv.GS_ANDROID_QA_APP_ID, 				phVal: PH.GS_ANDROID_APP_ID_PH },
		{ prodVal: myEnv.GS_ANDROID_BUNDLE_ID, 					qaVal: myEnv.GS_ANDROID_BUNDLE_ID, 				phVal: PH.GS_ANDROID_BUNDLE_ID_PH },
		{ prodVal: myEnv.GS_PROD_FIREBASE_URL, 					qaVal: myEnv.GS_QA_FIREBASE_URL, 				phVal: PH.GS_FIREBASE_URL_PH },
		{ prodVal: myEnv.GS_PROD_STORAGE_BUCKET, 				qaVal: myEnv.GS_QA_STORAGE_BUCKET, 				phVal: PH.GS_STORAGE_BUCKET_PH },
		{ prodVal: myEnv.GS_PROD_PROJECT_ID, 					qaVal: myEnv.GS_QA_PROJECT_ID, 					phVal: PH.GS_PROJECT_ID_PH },
		{ prodVal: myEnv.GS_PROD_PROJECT_NUMBER, 				qaVal: myEnv.GS_QA_PROJECT_NUMBER, 				phVal: PH.GS_PROJECT_NUMBER_PH },
	])
} else {
	console.log('Error: Replacement type not specififed.')
}

function makeReplacements(FILE_PATH, ENV, REPLACEMENTS) {
	fs.readFile(FILE_PATH, 'utf8', (err, data) => {
		if (!err) {
			for (let i = 0; REPLACEMENTS.length > i; i++) {
				if (ENV === 'prod') {
					data = data.replace(REPLACEMENTS[i].phVal, REPLACEMENTS[i].prodVal)
				} else if (ENV === 'qa') {
					data = data.replace(REPLACEMENTS[i].phVal, REPLACEMENTS[i].qaVal)
				}
			}
			fs.writeFile(FILE_PATH, data, 'utf8', (writeErr) => {
				if (writeErr) {
					return console.log(err)
				} else {
					console.log('SUCCESS: File ' + FILE_PATH + ' updated with ' + ENV + ' values.')
				}
			})
		} else {
			return console.log('Error: ' + err)
		}
	})
}
<commit_msg>add app version to ci<commit_after>const fs = require('fs')
const os = require('os')

const REPLACEMENT_ENV = process.argv[2]
const ENV_TYPE = process.argv[3]

// Environment Setup
let myEnv
if (ENV_TYPE === 'ci') {
	myEnv = process.env
} else {
	myEnv = require(os.homedir() + '/.campusmobile/env.js') // eslint-disable-line
}

// File Paths
const APP_SETTINGS_PATH = './app/AppSettings.js',
	SSO_SERVICE_PATH = './app/services/ssoService.js',
	IOS_INFO_PLIST_PATH = './ios/CampusMobile/Info.plist',
	IOS_GOOGLE_SERVICES_PATH = './ios/GoogleService-Info.plist',
	ANDROID_STRINGS_PATH = './android/app/src/main/res/values/strings.xml',
	ANDROID_MANIFEST_PATH = './android/app/src/main/AndroidManifest.xml',
	ANDROID_GOOGLE_SERVICES_PATH = './android/app/google-services.json',
	ANDROID_APP_BUILD_GRADLE_PATH = './android/app/build.gradle'

// Placeholder Values
const PH = {
	APP_NAME_PH: 'CampusMobile',
	APP_VERSION_PH: '1.0.0',
	GOOGLE_ANALYTICS_ID_PH: 'GOOGLE_ANALYTICS_ID_PH',
	GOOGLE_MAPS_API_KEY_PH: 'GOOGLE_MAPS_API_KEY_PH',
	FIREBASE_KEY_PH: 'FIREBASE_KEY_PH',
	BUGSNAG_KEY_PH: 'BUGSNAG_KEY_PH',
	AUTH_SERVICE_API_KEY_PH: 'AUTH_SERVICE_API_KEY_PH',
	GS_PROJECT_ID_PH: 'GS_PROJECT_ID_PH',
	GS_STORAGE_BUCKET_PH: 'GS_STORAGE_BUCKET_PH',
	GS_FIREBASE_URL_PH: 'GS_FIREBASE_URL_PH',
	GS_PROJECT_NUMBER_PH: 'GS_PROJECT_NUMBER_PH', // iOS: GCM_SENDER_ID, Android: project_info.project_number
	GS_IOS_CLIENT_ID_PH: 'GS_IOS_CLIENT_ID_PH',
	GS_IOS_REVERSED_CLIENT_ID_PH: 'GS_IOS_REVERSED_CLIENT_ID_PH',
	GS_IOS_API_KEY_PH: 'GS_IOS_API_KEY_PH',
	GS_IOS_BUNDLE_ID_PH: 'GS_IOS_BUNDLE_ID_PH',
	GS_IOS_STORAGE_BUCKET_PH: 'GS_IOS_STORAGE_BUCKET_PH',
	GS_IOS_APP_ID_PH: '1:1:ios:1',
	GS_ANDROID_CLIENT_ID_PH: 'GS_ANDROID_CLIENT_ID_PH',
	GS_ANDROID_API_KEY_PH: 'GS_ANDROID_API_KEY_PH',
	GS_ANDROID_APP_ID_PH: '1:1:android:1',
	GS_ANDROID_BUNDLE_ID_PH: 'edu.ucsd',
}

if (REPLACEMENT_ENV === 'prod' || REPLACEMENT_ENV === 'qa') {
	// AppSettings.js
	makeReplacements(APP_SETTINGS_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.APP_NAME, qaVal: myEnv.APP_NAME, phVal: PH.APP_NAME_PH },
		{ prodVal: myEnv.GOOGLE_ANALYTICS_ID_PROD, qaVal: myEnv.GOOGLE_ANALYTICS_ID_QA, phVal: PH.GOOGLE_ANALYTICS_ID_PH },
	])

	// ssoService.js
	makeReplacements(SSO_SERVICE_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.AUTH_SERVICE_API_KEY_PROD, qaVal: myEnv.AUTH_SERVICE_API_KEY_QA, phVal: PH.AUTH_SERVICE_API_KEY_PH },
	])

	// Info.plist
	makeReplacements(IOS_INFO_PLIST_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.APP_NAME, qaVal: myEnv.APP_NAME, phVal: PH.APP_NAME_PH },
		{ prodVal: myEnv.APP_VERSION, qaVal: myEnv.APP_VERSION, phVal: PH.APP_VERSION_PH },
		{ prodVal: myEnv.BUGSNAG_KEY, qaVal: myEnv.BUGSNAG_KEY, phVal: PH.BUGSNAG_KEY_PH }
	])

	// build.gradle
	makeReplacements(ANDROID_APP_BUILD_GRADLE_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.APP_VERSION, qaVal: myEnv.APP_VERSION, phVal: PH.APP_VERSION_PH },
	])

	// strings.xml
	makeReplacements(ANDROID_STRINGS_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.APP_NAME, qaVal: myEnv.APP_NAME, phVal: PH.APP_NAME_PH },
	])

	// AndroidManifest.xml
	makeReplacements(ANDROID_MANIFEST_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.APP_VERSION, qaVal: myEnv.APP_VERSION, phVal: PH.APP_VERSION_PH },
		{ prodVal: myEnv.GOOGLE_MAPS_API_KEY, qaVal: myEnv.GOOGLE_MAPS_API_KEY, phVal: PH.GOOGLE_MAPS_API_KEY_PH },
		{ prodVal: myEnv.BUGSNAG_KEY, qaVal: myEnv.BUGSNAG_KEY, phVal: PH.BUGSNAG_KEY_PH }
	])

	// GoogleService-Info.plist
	makeReplacements(IOS_GOOGLE_SERVICES_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.GS_IOS_PROD_CLIENT_ID, 				qaVal: myEnv.GS_IOS_QA_CLIENT_ID, 				phVal: PH.GS_IOS_CLIENT_ID_PH },
		{ prodVal: myEnv.GS_IOS_PROD_REVERSED_CLIENT_ID,		qaVal: myEnv.GS_IOS_QA_REVERSED_CLIENT_ID, 		phVal: PH.GS_IOS_REVERSED_CLIENT_ID_PH },
		{ prodVal: myEnv.GS_IOS_PROD_API_KEY, 					qaVal: myEnv.GS_IOS_QA_API_KEY, 				phVal: PH.GS_IOS_API_KEY_PH },
		{ prodVal: myEnv.GS_IOS_BUNDLE_ID, 						qaVal: myEnv.GS_IOS_BUNDLE_ID, 					phVal: PH.GS_IOS_BUNDLE_ID_PH },
		{ prodVal: myEnv.GS_IOS_PROD_APP_ID, 					qaVal: myEnv.GS_IOS_QA_APP_ID, 					phVal: PH.GS_IOS_APP_ID_PH },
		{ prodVal: myEnv.GS_PROD_FIREBASE_URL, 					qaVal: myEnv.GS_QA_FIREBASE_URL, 				phVal: PH.GS_FIREBASE_URL_PH },
		{ prodVal: myEnv.GS_PROD_STORAGE_BUCKET, 				qaVal: myEnv.GS_QA_STORAGE_BUCKET, 				phVal: PH.GS_STORAGE_BUCKET_PH },
		{ prodVal: myEnv.GS_PROD_PROJECT_ID, 					qaVal: myEnv.GS_QA_PROJECT_ID, 					phVal: PH.GS_PROJECT_ID_PH },
		{ prodVal: myEnv.GS_PROD_PROJECT_NUMBER, 				qaVal: myEnv.GS_QA_PROJECT_NUMBER, 				phVal: PH.GS_PROJECT_NUMBER_PH },
	])

	// google-services.json
	makeReplacements(ANDROID_GOOGLE_SERVICES_PATH, REPLACEMENT_ENV, [
		{ prodVal: myEnv.GS_ANDROID_PROD_CLIENT_ID, 			qaVal: myEnv.GS_ANDROID_QA_CLIENT_ID, 			phVal: PH.GS_ANDROID_CLIENT_ID_PH },
		{ prodVal: myEnv.GS_ANDROID_PROD_API_KEY, 				qaVal: myEnv.GS_ANDROID_QA_API_KEY, 			phVal: PH.GS_ANDROID_API_KEY_PH },
		{ prodVal: myEnv.GS_ANDROID_PROD_APP_ID, 				qaVal: myEnv.GS_ANDROID_QA_APP_ID, 				phVal: PH.GS_ANDROID_APP_ID_PH },
		{ prodVal: myEnv.GS_ANDROID_BUNDLE_ID, 					qaVal: myEnv.GS_ANDROID_BUNDLE_ID, 				phVal: PH.GS_ANDROID_BUNDLE_ID_PH },
		{ prodVal: myEnv.GS_PROD_FIREBASE_URL, 					qaVal: myEnv.GS_QA_FIREBASE_URL, 				phVal: PH.GS_FIREBASE_URL_PH },
		{ prodVal: myEnv.GS_PROD_STORAGE_BUCKET, 				qaVal: myEnv.GS_QA_STORAGE_BUCKET, 				phVal: PH.GS_STORAGE_BUCKET_PH },
		{ prodVal: myEnv.GS_PROD_PROJECT_ID, 					qaVal: myEnv.GS_QA_PROJECT_ID, 					phVal: PH.GS_PROJECT_ID_PH },
		{ prodVal: myEnv.GS_PROD_PROJECT_NUMBER, 				qaVal: myEnv.GS_QA_PROJECT_NUMBER, 				phVal: PH.GS_PROJECT_NUMBER_PH },
	])
} else {
	console.log('Error: Replacement type not specififed.')
}

function makeReplacements(FILE_PATH, ENV, REPLACEMENTS) {
	fs.readFile(FILE_PATH, 'utf8', (err, data) => {
		if (!err) {
			for (let i = 0; REPLACEMENTS.length > i; i++) {
				if (ENV === 'prod') {
					data = data.replace(REPLACEMENTS[i].phVal, REPLACEMENTS[i].prodVal)
				} else if (ENV === 'qa') {
					data = data.replace(REPLACEMENTS[i].phVal, REPLACEMENTS[i].qaVal)
				}
			}
			fs.writeFile(FILE_PATH, data, 'utf8', (writeErr) => {
				if (writeErr) {
					return console.log(err)
				} else {
					console.log('SUCCESS: File ' + FILE_PATH + ' updated with ' + ENV + ' values.')
				}
			})
		} else {
			return console.log('Error: ' + err)
		}
	})
}
<|endoftext|>


<commit_before>const fs = require('fs-extra-promise');
const mkdirp = require('mkdirp');
const path = require('path');

const transformPackage = require('../../core/transform-package.js');
const _setSrcPackageName = require('./_set-src-package-name.js');
const _setTestProject2PkgDependency = require('./_set-test-project-2-pkg-dependency.js');

/**
 * @private
 */
const _updateUrls = (pkg) => {
    if(!(pkg.name && pkg.config && pkg.config.scope)) {
        return pkg;
    }

    const repo = pkg.repository = {...pkg.repository } || {};

    repo.type = repo.type || 'git';
    repo.url = (repo.url && !repo.url.match(/^git\+https:\/\/github\.com\/[^/]+\/[^/]+\.git$/))?
        repo.url:
        `git+https://github.com/${_toCannonical(pkg.config.scope)}/${_toCannonical(pkg.name)}.git`;

    const bugs = pkg.bugs = {...pkg.bugs } || {};

    bugs.url = (bugs.url && !bugs.url.match(/^https:\/\/github\.com\/[^/]+\/[^/]+\/issues$/))?
        bugs.url:
        `https://github.com/${_toCannonical(pkg.config.scope)}/${_toCannonical(pkg.name)}/issues`;

    const homepage = (pkg.homepage && !pkg.homepage.match(/^https:\/\/github\.com\/[^/]+\/[^/]+$/))?
        pkg.homepage:
        `https://github.com/${_toCannonical(pkg.config.scope)}/${_toCannonical(pkg.name)}`;

    return {
        ...pkg,
        repository: repo,
        homepage: homepage,
        bugs: bugs
    };
}

/**
 * @private
 */
const _toCannonical = (name) => {
    if(typeof(name) !== 'string') {
        return null;
    }

    return name.toLowerCase()
        .replace(/^[^a-z1-9]+/, '')
        .replace(/[^a-z1-9]+$/, '')
        .replace(/[^a-z1-9]+/g, '-')
}

/**
 * Sets the name of the package and also updates that name in the
 * template/example Unity package under test.
 *
 * @param {string} pkgRoot abs path to the package root.
 *
 * @param {string} options.package_name
 *      new name for the package, if not set defaults to existing package name
 *
 * @param {string} options.package_scope
 *      new config.scope for package
 *
 * @param {function(err, packages)} callback
 *      Packages here is an array with an object for each package affected,
 *      [{path: '/some/package.json', package: { name: 'package_name', ... } }]
 *
 * @returns if no callback function passed, returns a Promise
 */
const setPackageName = (pkgRoot, options, callback) => {

    if (typeof(options) === 'function') {
        callback = options;
        options = {};
    }

    options = options || {};

    if (options.verbose) {
        console.log(`unity-npm-utils::unityPackage.setPackageName package_root=${pkgRoot}`)
    }

    const promise = new Promise((resolve, reject) => {

        const pkgJsonPath = path.join(pkgRoot, 'package.json');
        const testPkgJsonPath = path.join(pkgRoot, 'test', 'package.json');

        const newPkgName = _toCannonical(options.package_name) || p.name.name;

        transformPackage({
            package_path: pkgRoot,
            transform: (p, cb) => {
                p.name = newPkgName;

                if(options.package_scope) {
                    p.config = { ...(p.config || {}), scope: _toCannonical(options.package_scope) }
                }

                p = _updateUrls(p);

                return cb(null, p);
            }
        })
        .then(p => {
            return Promise.all([
                _setSrcPackageName(pkgRoot, newPkgName),
                _setTestProject2PkgDependency(pkgRoot)
            ])
        })
        .then(allDone => resolve(pkgRoot))
        .catch(e => reject(e));
    });

    return (callback) ?
        promise.then(r => callback(null, r)).catch(e => callback(e)) : promise;
}

module.exports = setPackageName;
<commit_msg>fixed bug in setPackageName when package_name not passed as option<commit_after>const fs = require('fs-extra-promise');
const mkdirp = require('mkdirp');
const path = require('path');

const transformPackage = require('../../core/transform-package.js');
const _setSrcPackageName = require('./_set-src-package-name.js');
const _setTestProject2PkgDependency = require('./_set-test-project-2-pkg-dependency.js');

/**
 * @private
 */
const _updateUrls = (pkg) => {
    if(!(pkg.name && pkg.config && pkg.config.scope)) {
        return pkg;
    }

    const repo = pkg.repository = {...pkg.repository } || {};

    repo.type = repo.type || 'git';
    repo.url = (repo.url && !repo.url.match(/^git\+https:\/\/github\.com\/[^/]+\/[^/]+\.git$/))?
        repo.url:
        `git+https://github.com/${_toCannonical(pkg.config.scope)}/${_toCannonical(pkg.name)}.git`;

    const bugs = pkg.bugs = {...pkg.bugs } || {};

    bugs.url = (bugs.url && !bugs.url.match(/^https:\/\/github\.com\/[^/]+\/[^/]+\/issues$/))?
        bugs.url:
        `https://github.com/${_toCannonical(pkg.config.scope)}/${_toCannonical(pkg.name)}/issues`;

    const homepage = (pkg.homepage && !pkg.homepage.match(/^https:\/\/github\.com\/[^/]+\/[^/]+$/))?
        pkg.homepage:
        `https://github.com/${_toCannonical(pkg.config.scope)}/${_toCannonical(pkg.name)}`;

    return {
        ...pkg,
        repository: repo,
        homepage: homepage,
        bugs: bugs
    };
}

/**
 * @private
 */
const _toCannonical = (name) => {
    if(typeof(name) !== 'string') {
        return null;
    }

    return name.toLowerCase()
        .replace(/^[^a-z1-9]+/, '')
        .replace(/[^a-z1-9]+$/, '')
        .replace(/[^a-z1-9]+/g, '-')
}

/**
 * Sets the name of the package and also updates that name in the
 * template/example Unity package under test.
 *
 * @param {string} pkgRoot abs path to the package root.
 *
 * @param {string} options.package_name
 *      new name for the package, if not set defaults to existing package name
 *
 * @param {string} options.package_scope
 *      new config.scope for package
 *
 * @param {function(err, packages)} callback
 *      Packages here is an array with an object for each package affected,
 *      [{path: '/some/package.json', package: { name: 'package_name', ... } }]
 *
 * @returns if no callback function passed, returns a Promise
 */
const setPackageName = (pkgRoot, options, callback) => {

    if (typeof(options) === 'function') {
        callback = options;
        options = {};
    }

    options = options || {};

    if (options.verbose) {
        console.log(`unity-npm-utils::unityPackage.setPackageName package_root=${pkgRoot}`)
    }

    const promise = new Promise((resolve, reject) => {

        const pkgJsonPath = path.join(pkgRoot, 'package.json');
        const testPkgJsonPath = path.join(pkgRoot, 'test', 'package.json');

        var newPkgName = null;

        transformPackage({
            package_path: pkgRoot,
            transform: (p, cb) => {

                p.name = newPkgName = _toCannonical(options.package_name) || p.name;

                if(options.package_scope) {
                    p.config = { ...(p.config || {}), scope: _toCannonical(options.package_scope) }
                }

                p = _updateUrls(p);

                return cb(null, p);
            }
        })
        .then(p => {
            return Promise.all([
                _setSrcPackageName(pkgRoot, newPkgName),
                _setTestProject2PkgDependency(pkgRoot)
            ])
        })
        .then(allDone => resolve(pkgRoot))
        .catch(e => reject(e));
    });

    return (callback) ?
        promise.then(r => callback(null, r)).catch(e => callback(e)) : promise;
}

module.exports = setPackageName;
<|endoftext|>


<commit_before>(function(window, document, undefined){

  var CharacterRotator = function(rootElement) {
    this.rootElement = rootElement;
  };

  CharacterRotator.prototype = {

    CLASS_ROTATED: 'rotated',

    REGEXP_ROTATED: new RegExp('\\brotated\\b'),

    REGEXP_SPACES: /^\s+$/,

    /**
     * Restore all rotated characters to their non-rotated selfs.
     * TODO restore whole tree
     */
    restore: function() {
      var rotations = this.rootElement.querySelectorAll('.' + this.CLASS_ROTATED),
        textContent = [].map.call(rotations, function(elem){ return elem.textContent }).join('');
      this.rootElement.innerHTML = textContent;
    },

    /**
     * Rotate *all* the characters within the HTML tree
     * rooted at the node specified during the construction of
     * this CharacterRotator.
     */
    rotate: function() {
      var textNodes = this.getTextNodes(),
        self = this,
        i = textNodes.length,
        j,
        node,
        parent,
        tmpFrag,
        spans,
        span,
        spanRect;

      while( i-- ) {
        node = textNodes[i];
        parent = node.parentElement;

        if( this.REGEXP_ROTATED.test( parent.className ) ) {
          continue;
        }

        tmpFrag = document.createDocumentFragment();
        node.nodeValue.replace(/(.)/g, function( match ) {
          var tmpSpan = document.createElement('span');
          tmpSpan.className = self.CLASS_ROTATED;
          tmpSpan.setAttribute('style', 'display:inline;');
          tmpSpan.innerHTML = match;
          tmpFrag.appendChild(tmpSpan);
        });

        parent.replaceChild(tmpFrag, node);
        spans = parent.getElementsByClassName(this.CLASS_ROTATED);
        j = spans.length;

        while( j-- ) {
          span = spans[j];
          spanRect = span.getBoundingClientRect();
          span.style.left = spanRect.left + 'px';
          span.style.top = spanRect.top + 'px';
        }
      }

      // make sure the spans are inline-block so we can apply transformations to them
      // TODO add css to document to do this
      spans = document.getElementsByClassName(this.CLASS_ROTATED);
      j = spans.length;
      while( j-- ) {
        span = spans[j];
        span.style.display = 'inline-block';
      }

      // apply random rotation
      j = spans.length;
      while( j-- ) {
        this.randomlyRotate( spans[j] );
      }
    },

    randomlyRotate: function(element) {
      var degrees = Math.ceil(Math.random() * 4) * 90,
        transform = 'rotate(' + degrees +'deg)',
        css = {},
        prop;

      css['transform'] = transform;
      css['mozTransform'] = transform;
      css['webkitTransform'] =  transform;

      for( prop in css ) {
        element.style[prop] = css[prop];
      }
    },

    /**
     * Retrieve all text nodes which are not
     * made of space characters.
     **/
    getTextNodes: function() {
      var walker = document.createTreeWalker(
          this.rootElement,
          NodeFilter.SHOW_TEXT,
          null,
          false
        ),
        node = walker.nextNode(),
        textNodes = [];

      while(node) {

        if( !this.REGEXP_SPACES.test( node.nodeValue ) ) {
          textNodes.push(node);
        }

        node = walker.nextNode();
      }

      return textNodes;
    }

  };

  window.CharacterRotator = CharacterRotator;

}(window, document));<commit_msg>Maintain whitespace space when rotating letters<commit_after>(function(window, document, undefined){

  var CharacterRotator = function(rootElement) {
    this.rootElement = rootElement;
  };

  CharacterRotator.prototype = {

    CLASS_ROTATED: 'rotated',

    REGEXP_ROTATED: new RegExp('\\brotated\\b'),

    REGEXP_SPACES: /^\s+$/,

    /**
     * Restore all rotated characters to their non-rotated selfs.
     * TODO restore whole tree
     */
    restore: function() {
      var rotations = this.rootElement.querySelectorAll('.' + this.CLASS_ROTATED),
        textContent = [].map.call(rotations, function(elem){ return elem.textContent }).join('');
      this.rootElement.innerHTML = textContent;
    },

    /**
     * Rotate *all* the characters within the HTML tree
     * rooted at the node specified during the construction of
     * this CharacterRotator.
     */
    rotate: function() {
      var textNodes = this.getTextNodes(),
        self = this,
        i = textNodes.length,
        j,
        node,
        parent,
        tmpFrag,
        spans,
        span,
        spanRect;

      while( i-- ) {
        node = textNodes[i];
        parent = node.parentElement;

        if( this.REGEXP_ROTATED.test( parent.className ) ) {
          continue;
        }

        tmpFrag = document.createDocumentFragment();
        node.nodeValue.replace(/(.)/g, function( match ) {
          var tmpSpan = document.createElement('span');
          tmpSpan.className = self.CLASS_ROTATED;
          tmpSpan.setAttribute('style', 'display:inline;white-space:pre;');
          tmpSpan.innerHTML = match;
          tmpFrag.appendChild(tmpSpan);
        });

        parent.replaceChild(tmpFrag, node);
        spans = parent.getElementsByClassName(this.CLASS_ROTATED);
        j = spans.length;

        while( j-- ) {
          span = spans[j];
          spanRect = span.getBoundingClientRect();
          span.style.left = spanRect.left + 'px';
          span.style.top = spanRect.top + 'px';
        }
      }

      // make sure the spans are inline-block so we can apply transformations to them
      // TODO add css to document to do this
      spans = document.getElementsByClassName(this.CLASS_ROTATED);
      j = spans.length;
      while( j-- ) {
        span = spans[j];
        span.style.display = 'inline-block';
      }

      // apply random rotation
      j = spans.length;
      while( j-- ) {
        this.randomlyRotate( spans[j] );
      }
    },

    randomlyRotate: function(element) {
      var degrees = Math.ceil(Math.random() * 4) * 90,
        transform = 'rotate(' + degrees +'deg)',
        css = {},
        prop;

      css['transform'] = transform;
      css['mozTransform'] = transform;
      css['webkitTransform'] =  transform;

      for( prop in css ) {
        element.style[prop] = css[prop];
      }
    },

    /**
     * Retrieve all text nodes which are not
     * made of space characters.
     **/
    getTextNodes: function() {
      var walker = document.createTreeWalker(
          this.rootElement,
          NodeFilter.SHOW_TEXT,
          null,
          false
        ),
        node = walker.nextNode(),
        textNodes = [];

      while(node) {

        if( !this.REGEXP_SPACES.test( node.nodeValue ) ) {
          textNodes.push(node);
        }

        node = walker.nextNode();
      }

      return textNodes;
    }

  };

  window.CharacterRotator = CharacterRotator;

}(window, document));<|endoftext|>


<commit_before>/* global moment */

(function($) {
  'use strict';

  var dateRangePicker = {
    init: function() {
      this.$picker = $('.js-date-range-picker');

      this.$picker.daterangepicker({
        ranges: {
          'Today': [moment(), moment()],
          'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
          'Last 7 Days': [moment().subtract(6, 'days'), moment()],
          'Last 30 Days': [moment().subtract(29, 'days'), moment()],
          'This Month': [moment().startOf('month'), moment().endOf('month')],
          'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
        },
        locale: {
          format: 'DD/MM/YYYY',
          cancelLabel: 'Clear'
        },
        autoUpdateInput: false
      });

      this.$picker.on('apply.daterangepicker', function(ev, picker) {
        $(this).val(picker.startDate.format('DD/MM/YYYY') + ' - ' + picker.endDate.format('DD/MM/YYYY'));
      });

      this.$picker.on('cancel.daterangepicker', function() {
        $(this).val('');
      });
    }
  };

  window.PWPlanner = window.PWPlanner || {};
  window.PWPlanner.dateRangePicker = dateRangePicker;

})(jQuery);
<commit_msg>Add 'tomorrow' to date range filter<commit_after>/* global moment */

(function($) {
  'use strict';

  var dateRangePicker = {
    init: function() {
      this.$picker = $('.js-date-range-picker');

      this.$picker.daterangepicker({
        ranges: {
          'Today': [moment(), moment()],
          'Tomorrow': [moment().add(1, 'days'), moment().add(1, 'days')],
          'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
          'Last 7 Days': [moment().subtract(6, 'days'), moment()],
          'Last 30 Days': [moment().subtract(29, 'days'), moment()],
          'This Month': [moment().startOf('month'), moment().endOf('month')],
          'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
        },
        locale: {
          format: 'DD/MM/YYYY',
          cancelLabel: 'Clear'
        },
        autoUpdateInput: false
      });

      this.$picker.on('apply.daterangepicker', function(ev, picker) {
        $(this).val(picker.startDate.format('DD/MM/YYYY') + ' - ' + picker.endDate.format('DD/MM/YYYY'));
      });

      this.$picker.on('cancel.daterangepicker', function() {
        $(this).val('');
      });
    }
  };

  window.PWPlanner = window.PWPlanner || {};
  window.PWPlanner.dateRangePicker = dateRangePicker;

})(jQuery);
<|endoftext|>