<commit_before>'use strict';

var url = require('url');
var cluster = require('cluster');
var bunyan = require('bunyan');
var deck = require('deck');
var exitHook = require('exit-hook');

var args = process.argv.slice(2);
var config = args[0];
if (!config || config === 'undefined') throw new Error('Missing config!');

config = JSON.parse(config);

process.on('message', function(msg) {
  if (msg.type === 'config' && msg.config) config = msg.config;
});

// Responds to the cluster disconnect signal/event from the master process
exitHook(function (next) { next(); });

// todo : we could move the log creation out to the service init file.
//        and/or use a modified consule.log object or pico as default.
var log = bunyan.createLogger({
  name: config.name,
  version: config.version,
  worker: cluster.isWorker ? cluster.worker.id : 'unknown',
  level: config.log_level
});

function getURL (service, path, query) {
  var record = deck.pick(config[service] || []);
  if (!record || !record.host) {
    log.warn(new Error('Didn\'t find a record for ' + service));
    return;
  }

  var uo = url.parse('http://' + record.host + ':' + record.port);
  if (path) {
    if (Array.isArray(path)) path = path.join('/');
    uo.pathname = path;
  }
  if (query) {
    uo.query = query;
  }
  return url.format(uo);
}

config.log = log;
config.getURL = getURL;
module.exports = config;
<commit_msg>Generate client id<commit_after>'use strict';

var os = require('os');
var url = require('url');
var cluster = require('cluster');
var bunyan = require('bunyan');
var deck = require('deck');
var exitHook = require('exit-hook');

var args = process.argv.slice(2);
var config = args[0];
if (!config || config === 'undefined') throw new Error('Missing config!');

config = JSON.parse(config);

process.on('message', function(msg) {
  if (msg.type === 'config' && msg.config) config = msg.config;
});

// Responds to the cluster disconnect signal/event from the master process
exitHook(function (next) { next(); });

// todo : we could move the log creation out to the service init file.
//        and/or use a modified consule.log object or pico as default.
var log = bunyan.createLogger({
  name: config.name,
  version: config.version,
  worker: cluster.isWorker ? cluster.worker.id : 'unknown',
  level: config.log_level
});

function getURL (service, path, query) {
  var record = deck.pick(config[service] || []);
  if (!record || !record.host) {
    log.warn(new Error('Didn\'t find a record for ' + service));
    return;
  }

  var uo = url.parse('http://' + record.host + ':' + record.port);
  if (path) {
    if (Array.isArray(path)) path = path.join('/');
    uo.pathname = path;
  }
  if (query) {
    uo.query = query;
  }
  return url.format(uo);
}

function clientId () {
  return [config.name, 'v' + config.version, config.environment, process.pid, os.hostname()].join('_');
}

config.log = log;
config.getURL = getURL;
config.clientId = clientId;
module.exports = config;
<|endoftext|>


<commit_before>var Monitors = {};

const Monitor = require('../models/monitor');
const renderError = require('../lib/renderError');
const monitorCron = require('../lib/monitorCron');
// const badge = require('../lib/badge');
const moment = require('moment');

Monitors.new = (req, res)=> {
    return res.render('monitor/edit')
};

Monitors.newPost = (req, res)=> {
    const name = req.body.name;
    var url = req.body.url;
    const username = req.user.username;
    const email = req.user.emails[0].value;

    //add 'http://' if missing
    var prefix = 'http://';
    if (url.substr(0, prefix.length) !== prefix) {
        url = prefix + url;
    }

    new Monitor({
        name,
        url,
        username,
        email
    })
        .save()
        .then(monitor=> {
            monitorCron.add(monitor);
            return res.redirect('/site/' + monitor.id);
        })
        .catch(err=> {
            return renderError(err, res)
        });

};

Monitors.mine = (req, res)=> {

    var currentUsername = req.user.username;

    Monitor
        .filter({username: currentUsername})
        .run()
        .then(monitors=> {
            res.render('monitor/mine', {monitors});
        })
        .catch(err => renderError(err, res));
};

Monitors.show = (req, res)=> {
    var id = req.params.id;
    Monitor.get(id)
        .getJoin({responses: true})
        .run()
        .then((monitor)=> {

            var graph = {
                labels: [],
                data: []
            };

            monitor.responses.map(function (r) {
                graph.data.push(r.time);
                graph.labels.push(
                    {
                        meta: moment(r.date).fromNow(),
                        value: r.time //ms
                    }
                )
            });

            return res.render('monitor/show', {monitor, graph});
        })
        .catch((err)=> {
            console.log('error:', err);
            return renderError(err, res);
        })
};

Monitors.edit = (req, res)=> {

};

Monitors.delete = (req, res)=> {

};

Monitors.upPercentBadge = (req, res)=> {
    var id = req.params.id;

    Monitor.get(id).run()
        .then((monitor)=> {
            monitor.getUpPercentBadge().then((svg)=> {
                return res.type('image/svg+xml').send(svg);
            }).catch(err=> {
                console.log(err)
            });
        })
        .catch((err)=> {
            console.log(err)
        })
};
Monitors.averageResponseBadge = (req, res)=> {
    var id = req.params.id;

    Monitor.get(id).run()
        .then((monitor)=> {
            monitor.getAvgResponseBadge().then((svg)=> {
                return res.type('image/svg+xml').send(svg);
            }).catch(err=> {
                console.log(err)
            });
        })
        .catch((err)=> {
            console.log(err)
        })
};

Monitors.statusBadge = (req, res)=> {
    var id = req.params.id;

    Monitor.get(id).run()
        .then((monitor)=> {
            monitor.getStatusBadge().then((svg)=> {
                return res.type('image/svg+xml').send(svg);
            }).catch(err=> {
                console.log(err)
            });
        })
        .catch((err)=> {
            console.log(err)
        })
};

module.exports = Monitors;<commit_msg>always use http (for now)<commit_after>var Monitors = {};

const Monitor = require('../models/monitor');
const renderError = require('../lib/renderError');
const monitorCron = require('../lib/monitorCron');
// const badge = require('../lib/badge');
const moment = require('moment');

Monitors.new = (req, res)=> {
    return res.render('monitor/edit')
};

Monitors.newPost = (req, res)=> {
    const name = req.body.name;
    var url = req.body.url;
    const username = req.user.username;
    const email = req.user.emails[0].value;

    url = subject.replace(/.*?:\/\//g, "http://");

    new Monitor({
        name,
        url,
        username,
        email
    })
        .save()
        .then(monitor=> {
            monitorCron.add(monitor);
            return res.redirect('/site/' + monitor.id);
        })
        .catch(err=> {
            return renderError(err, res)
        });

};

Monitors.mine = (req, res)=> {

    var currentUsername = req.user.username;

    Monitor
        .filter({username: currentUsername})
        .run()
        .then(monitors=> {
            res.render('monitor/mine', {monitors});
        })
        .catch(err => renderError(err, res));
};

Monitors.show = (req, res)=> {
    var id = req.params.id;
    Monitor.get(id)
        .getJoin({responses: true})
        .run()
        .then((monitor)=> {

            var graph = {
                labels: [],
                data: []
            };

            monitor.responses.map(function (r) {
                graph.data.push(r.time);
                graph.labels.push(
                    {
                        meta: moment(r.date).fromNow(),
                        value: r.time //ms
                    }
                )
            });

            return res.render('monitor/show', {monitor, graph});
        })
        .catch((err)=> {
            console.log('error:', err);
            return renderError(err, res);
        })
};

Monitors.edit = (req, res)=> {

};

Monitors.delete = (req, res)=> {

};

Monitors.upPercentBadge = (req, res)=> {
    var id = req.params.id;

    Monitor.get(id).run()
        .then((monitor)=> {
            monitor.getUpPercentBadge().then((svg)=> {
                return res.type('image/svg+xml').send(svg);
            }).catch(err=> {
                console.log(err)
            });
        })
        .catch((err)=> {
            console.log(err)
        })
};
Monitors.averageResponseBadge = (req, res)=> {
    var id = req.params.id;

    Monitor.get(id).run()
        .then((monitor)=> {
            monitor.getAvgResponseBadge().then((svg)=> {
                return res.type('image/svg+xml').send(svg);
            }).catch(err=> {
                console.log(err)
            });
        })
        .catch((err)=> {
            console.log(err)
        })
};

Monitors.statusBadge = (req, res)=> {
    var id = req.params.id;

    Monitor.get(id).run()
        .then((monitor)=> {
            monitor.getStatusBadge().then((svg)=> {
                return res.type('image/svg+xml').send(svg);
            }).catch(err=> {
                console.log(err)
            });
        })
        .catch((err)=> {
            console.log(err)
        })
};

module.exports = Monitors;<|endoftext|>


<commit_before>var Purchase = require('../models/Purchase');
var User = require('../models/User');
module.exports = function( req, res ) {

  Purchase.findOne({ url_hash: req.params.hash }, function(err, purchase) {
    if (err) return next(err);
    if( purchase != null ) {
      console.log( purchase );
      console.log( purchase.claimed );
      if( purchase.claimed ) {
        res.send('This purchased has been redeemed to ' + purchase.email + '. Thanks!');
      }
      else{
        if( req.user != undefined ) {
          User.findById(req.user.id, function (err, user) {
            if (err) return next(err);
            var bonus = 0;
            if( user.special_redeemed != false ){
              if( purchase.offer_code == 'boundstar') {
                bonus = 2;
                user.special_redeemed = true;
              }
            }
            user.server_tokens = +user.server_tokens + ( +purchase.price / 50 ) + bonus;
            user.save(function (err) {
              if (err) return next(err);
              purchase.claimed = true;
              purchase.save(function(err) {
                if (err) { return err; }
                console.log( 'purchase claimed' );
                req.flash('success', { msg: 'Redeemed '+( +purchase.price / 50 ) + bonus + ' tokens to account' + purchase.email + '. Thanks!'});
                res.redirect('/');
              });
            });
          });
        }
        else {
          req.flash('success', { msg: 'Please login before checking the status of a purchase.'});
          res.redirect('/login')
        }
      }
    }
    else {
      res.send( 'Can\'t find it...' );
    }
  });
}<commit_msg>var type fix, silly + concats…<commit_after>var Purchase = require('../models/Purchase');
var User = require('../models/User');
module.exports = function( req, res ) {

  Purchase.findOne({ url_hash: req.params.hash }, function(err, purchase) {
    if (err) return next(err);
    if( purchase != null ) {
      console.log( purchase );
      console.log( purchase.claimed );
      if( purchase.claimed ) {
        res.send('This purchased has been redeemed to ' + purchase.email + '. Thanks!');
      }
      else{
        if( req.user != undefined ) {
          User.findById(req.user.id, function (err, user) {
            if (err) return next(err);
            var bonus = 0;
            if( user.special_redeemed != false ){
              if( purchase.offer_code === 'boundstar') {
                bonus = 2;
                user.special_redeemed = true;
              }
            }
            user.server_tokens = parseInt(user.server_tokens) + ( parseInt(purchase.price) / 50 ) + parseInt(bonus);
            user.save(function (err) {
              if (err) return next(err);
              purchase.claimed = true;
              purchase.save(function(err) {
                if (err) { return err; }
                console.log( 'purchase claimed' );
                req.flash('success', { msg: 'Redeemed '+( parseInt(purchase.price) / 50 ) + parseInt(bonus) + ' tokens to account ' + purchase.email + '. Thanks!'});
                res.redirect('/');
              });
            });
          });
        }
        else {
          req.flash('success', { msg: 'Please login before checking the status of a purchase.'});
          res.redirect('/login')
        }
      }
    }
    else {
      res.send( 'Can\'t find it...' );
    }
  });
}<|endoftext|>


<commit_before>function id(x) {
    return document.getElementById(x);
}

function cls(x) {
    return document.getElementsByClassName(x);
}
<commit_msg>Update dom.js<commit_after>function id(x) {return document.getElementById(x);}
function cls(x) {return document.getElementsByClassName(x);}
function value(x) {return id(x).value;}
<|endoftext|>


<commit_before>const assert = require("chai").assert;
const Box = require("@truffle/box");
const {
  determineTestFilesToRun
} = require("../../../lib/commands/test/determineTestFilesToRun");
const Artifactor = require("@truffle/artifactor");
const Resolver = require("@truffle/resolver");
const MemoryStream = require("memorystream");
const path = require("path");
const fs = require("fs-extra");
const glob = require("glob");
const WorkflowCompile = require("@truffle/workflow-compile");
const Test = require("../../../lib/testing/test");

let config;
output = "";

function updateFile(filename) {
  const fileToUpdate = path.resolve(
    path.join(config.contracts_directory, filename)
  );

  // Update the modification time to simulate an edit.
  const newTime = new Date().getTime();
  fs.utimesSync(fileToUpdate, newTime, newTime);
}

describe("test command", () => {
  let memStream;

  before("Create a sandbox", async () => {
    config = await Box.sandbox("default");
    config.resolver = new Resolver(config);
    config.artifactor = new Artifactor(config.contracts_build_directory);
    config.networks = {
      default: {
        network_id: "1"
      },
      secondary: {
        network_id: "12345"
      }
    };
    config.network = "default";
    config.logger = { log: val => val && memStream.write(val) };
  });

  beforeEach(() => {
    memStream = new MemoryStream();
    memStream.on("data", data => {
      output += data.toString();
    });
  });

  after("Cleanup tmp files", () => {
    const files = glob.sync("tmp-*");
    files.forEach(file => fs.removeSync(file));
  });

  afterEach("Clear MemoryStream", () => (output = ""));

  it("Check test with subdirectories", () => {
    let testFiles = determineTestFilesToRun({ config });
    let testFilesCount = testFiles.length;

    let filename = path.join(
      config.test_directory,
      "sub_directory",
      "test.sol"
    );
    fs.createFileSync(filename);

    filename = path.join(config.test_directory, "sub_directory", "test.js");
    fs.createFileSync(filename);

    filename = path.join(
      config.test_directory,
      "sub_directory",
      "sub_sub_directory",
      "test.js"
    );
    fs.createFileSync(filename);

    let dirName = path.join(
      config.test_directory,
      "sub_directory",
      "empty_sub_directory"
    );

    // Create empty subdirectory to check if
    // determineTestFilesTo run function can process it without crashing
    fs.ensureDirSync(dirName);

    let newTestFiles = determineTestFilesToRun({ config });
    assert.equal(
      newTestFiles.length,
      testFilesCount + 3,
      "Wrong number of files discovered"
    );
  });

  it("runs test with --compile-none flag", async () => {
    const solidityTestFiles = [];
    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: true,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      0,
      "It should try to compile 0 contracts With compileNone == false"
    );
  });

  it("can run test WITHOUT --compile-none flag", async () => {
    const solidityTestFiles = [];
    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: false,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      3,
      "It should compile 3 contracts With compileNone == true"
    );
  });

  it("compiles all initial contracts", async () => {
    const { contracts } = await WorkflowCompile.compile(
      config.with({
        all: false,
        quiet: true
      })
    );
    assert.equal(
      Object.keys(contracts).length,
      0,
      "Should compile zero contracts. Test command was run before and everything should be up to date"
    );
  });

  it("run test without --compile-none flag after running build", async () => {
    const solidityTestFiles = [];
    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: false,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      0,
      "It should try to compile 0 contracts With compileNone == false. Because there are no updated files."
    );
  });

  it("runs test after updating one contract.", async () => {
    updateFile("ConvertLib.sol");

    const solidityTestFiles = [];

    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: false,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      2,
      "It should compile 2 files, updated file and its ancestor,  and --compile-none is not set."
    );
  });

  it("Update all contracts and build it.", async () => {
    updateFile("ConvertLib.sol");
    updateFile("MetaCoin.sol");
    updateFile("Migrations.sol");

    const { contracts } = await WorkflowCompile.compile(
      config.with({
        all: false,
        quiet: false
      })
    );
    assert.equal(
      Object.keys(contracts).length,
      3,
      "Should compile 3 contracts."
    );
  });

  it("Check if  files are picked from subdirectories in test directory.", async () => {
    // This allows to create customized directory structure to test more than one level of sub directories.
    let fileStructrure = {
      name: "sub_directory",
      files: ["test1.sol", "test2.js"],
      subdirs: [
        {
          name: "sub_sub_directory",
          files: ["test3.sol", "test4.js"]
        },
        {
          name: "sub_sub_directory2",
          files: ["test5.js", "test6.sol", "test7.sol"],
          subdirs: [
            {
              name: "one_more_sub",
              files: [
                "test8.sol",
                "test9.sol",
                "test10.sol",
                "test10.sol",
                "test11.sol"
              ]
            },
            {
              name: "one_more_sub2",
              files: [
                "test12.sol",
                "test13.sol",
                "test14.sol",
                "test14.sol",
                "test15.sol"
              ],
              subdirs: [
                {
                  name: "solidity_only_subdir",
                  files: ["test16.sol", "test17.sol", "test18.sol"]
                },
                {
                  name: "js_only_subdir",
                  files: ["test19.js", "test19.js", "test20.js"]
                },
                {
                  name: "empty_sub_sub_directory",
                  files: []
                }
              ]
            }
          ]
        }
      ]
    };

    // Create file in recursion. Used instead foreach since foreach loop doesn't wait for files to be created
    // Function does not count already existing files.
    function createFile(dirName, files, index) {
      // return zero if there are no files to create
      if (!files[index]) return 0;
      var fileName = path.join(dirName, files[index]);
      let filesCount = 0;
      if (!fs.existsSync(fileName)) {
        fs.createFileSync(fileName);
        filesCount++;
      }
      if (files.length > index + 1) {
        filesCount += createFile(dirName, files, index + 1);
      }

      return filesCount;
    }

    // Create files using dirStruct object. Count newly created files and skip existing files.
    // Returns number of new files.
    function createTestSubDir(dirName, dirStruct) {
      var numOfFiles = 0;

      numOfFiles = createFile(dirName, dirStruct.files, 0);

      if (dirStruct.subdirs) {
        dirStruct.subdirs.forEach(val => {
          numOfFiles += createTestSubDir(
            path.join(dirName, dirStruct.name, val.name),
            val
          );
        });
      }
      return numOfFiles;
    }

    // Call method used by Test to discover existing test files. Then create subdirectories and test files in these
    // subdirectories. Then run Test method again and check if number discovered increased.
    let testFiles = determineTestFilesToRun({ config });
    const testFilesCount = testFiles.length;

    const newTestFiles = createTestSubDir(
      config.test_directory,
      fileStructrure
    );

    testFiles = determineTestFilesToRun({ config });
    assert.equal(
      testFiles.length,
      testFilesCount + newTestFiles,
      "Wrong number of files discovered"
    );
  });
}).timeout(1000);
<commit_msg>Correct another path<commit_after>const assert = require("chai").assert;
const Box = require("@truffle/box");
const {
  determineTestFilesToRun
} = require("../../../lib/commands/test/determineTestFilesToRun");
const Artifactor = require("@truffle/artifactor");
const Resolver = require("@truffle/resolver");
const MemoryStream = require("memorystream");
const path = require("path");
const fs = require("fs-extra");
const glob = require("glob");
const WorkflowCompile = require("@truffle/workflow-compile");
const Test = require("../../../lib/testing/Test");

let config;
output = "";

function updateFile(filename) {
  const fileToUpdate = path.resolve(
    path.join(config.contracts_directory, filename)
  );

  // Update the modification time to simulate an edit.
  const newTime = new Date().getTime();
  fs.utimesSync(fileToUpdate, newTime, newTime);
}

describe("test command", () => {
  let memStream;

  before("Create a sandbox", async () => {
    config = await Box.sandbox("default");
    config.resolver = new Resolver(config);
    config.artifactor = new Artifactor(config.contracts_build_directory);
    config.networks = {
      default: {
        network_id: "1"
      },
      secondary: {
        network_id: "12345"
      }
    };
    config.network = "default";
    config.logger = { log: val => val && memStream.write(val) };
  });

  beforeEach(() => {
    memStream = new MemoryStream();
    memStream.on("data", data => {
      output += data.toString();
    });
  });

  after("Cleanup tmp files", () => {
    const files = glob.sync("tmp-*");
    files.forEach(file => fs.removeSync(file));
  });

  afterEach("Clear MemoryStream", () => (output = ""));

  it("Check test with subdirectories", () => {
    let testFiles = determineTestFilesToRun({ config });
    let testFilesCount = testFiles.length;

    let filename = path.join(
      config.test_directory,
      "sub_directory",
      "test.sol"
    );
    fs.createFileSync(filename);

    filename = path.join(config.test_directory, "sub_directory", "test.js");
    fs.createFileSync(filename);

    filename = path.join(
      config.test_directory,
      "sub_directory",
      "sub_sub_directory",
      "test.js"
    );
    fs.createFileSync(filename);

    let dirName = path.join(
      config.test_directory,
      "sub_directory",
      "empty_sub_directory"
    );

    // Create empty subdirectory to check if
    // determineTestFilesTo run function can process it without crashing
    fs.ensureDirSync(dirName);

    let newTestFiles = determineTestFilesToRun({ config });
    assert.equal(
      newTestFiles.length,
      testFilesCount + 3,
      "Wrong number of files discovered"
    );
  });

  it("runs test with --compile-none flag", async () => {
    const solidityTestFiles = [];
    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: true,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      0,
      "It should try to compile 0 contracts With compileNone == false"
    );
  });

  it("can run test WITHOUT --compile-none flag", async () => {
    const solidityTestFiles = [];
    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: false,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      3,
      "It should compile 3 contracts With compileNone == true"
    );
  });

  it("compiles all initial contracts", async () => {
    const { contracts } = await WorkflowCompile.compile(
      config.with({
        all: false,
        quiet: true
      })
    );
    assert.equal(
      Object.keys(contracts).length,
      0,
      "Should compile zero contracts. Test command was run before and everything should be up to date"
    );
  });

  it("run test without --compile-none flag after running build", async () => {
    const solidityTestFiles = [];
    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: false,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      0,
      "It should try to compile 0 contracts With compileNone == false. Because there are no updated files."
    );
  });

  it("runs test after updating one contract.", async () => {
    updateFile("ConvertLib.sol");

    const solidityTestFiles = [];

    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: false,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      2,
      "It should compile 2 files, updated file and its ancestor,  and --compile-none is not set."
    );
  });

  it("Update all contracts and build it.", async () => {
    updateFile("ConvertLib.sol");
    updateFile("MetaCoin.sol");
    updateFile("Migrations.sol");

    const { contracts } = await WorkflowCompile.compile(
      config.with({
        all: false,
        quiet: false
      })
    );
    assert.equal(
      Object.keys(contracts).length,
      3,
      "Should compile 3 contracts."
    );
  });

  it("Check if  files are picked from subdirectories in test directory.", async () => {
    // This allows to create customized directory structure to test more than one level of sub directories.
    let fileStructrure = {
      name: "sub_directory",
      files: ["test1.sol", "test2.js"],
      subdirs: [
        {
          name: "sub_sub_directory",
          files: ["test3.sol", "test4.js"]
        },
        {
          name: "sub_sub_directory2",
          files: ["test5.js", "test6.sol", "test7.sol"],
          subdirs: [
            {
              name: "one_more_sub",
              files: [
                "test8.sol",
                "test9.sol",
                "test10.sol",
                "test10.sol",
                "test11.sol"
              ]
            },
            {
              name: "one_more_sub2",
              files: [
                "test12.sol",
                "test13.sol",
                "test14.sol",
                "test14.sol",
                "test15.sol"
              ],
              subdirs: [
                {
                  name: "solidity_only_subdir",
                  files: ["test16.sol", "test17.sol", "test18.sol"]
                },
                {
                  name: "js_only_subdir",
                  files: ["test19.js", "test19.js", "test20.js"]
                },
                {
                  name: "empty_sub_sub_directory",
                  files: []
                }
              ]
            }
          ]
        }
      ]
    };

    // Create file in recursion. Used instead foreach since foreach loop doesn't wait for files to be created
    // Function does not count already existing files.
    function createFile(dirName, files, index) {
      // return zero if there are no files to create
      if (!files[index]) return 0;
      var fileName = path.join(dirName, files[index]);
      let filesCount = 0;
      if (!fs.existsSync(fileName)) {
        fs.createFileSync(fileName);
        filesCount++;
      }
      if (files.length > index + 1) {
        filesCount += createFile(dirName, files, index + 1);
      }

      return filesCount;
    }

    // Create files using dirStruct object. Count newly created files and skip existing files.
    // Returns number of new files.
    function createTestSubDir(dirName, dirStruct) {
      var numOfFiles = 0;

      numOfFiles = createFile(dirName, dirStruct.files, 0);

      if (dirStruct.subdirs) {
        dirStruct.subdirs.forEach(val => {
          numOfFiles += createTestSubDir(
            path.join(dirName, dirStruct.name, val.name),
            val
          );
        });
      }
      return numOfFiles;
    }

    // Call method used by Test to discover existing test files. Then create subdirectories and test files in these
    // subdirectories. Then run Test method again and check if number discovered increased.
    let testFiles = determineTestFilesToRun({ config });
    const testFilesCount = testFiles.length;

    const newTestFiles = createTestSubDir(
      config.test_directory,
      fileStructrure
    );

    testFiles = determineTestFilesToRun({ config });
    assert.equal(
      testFiles.length,
      testFilesCount + newTestFiles,
      "Wrong number of files discovered"
    );
  });
}).timeout(1000);
<|endoftext|>


<commit_before>/* eslint-disable no-sync, no-console, id-length */
const fs = require('fs')
const path = require('path')
const glob = require('glob')
const chalk = require('chalk')
const semver = require('semver')
const config = require('../lerna.json')
const corePkg = require('../package.json')

const rootPath = path.join(__dirname, '..')
const stripRange = (version) => version.replace(/^[~^]/, '')
const sortRanges = (ranges) =>
  ranges.sort((a, b) => {
    try {
      return semver.compare(stripRange(a), stripRange(b))
    } catch (err) {
      return 1
    }
  })
const patterns = config.packages.map((pkg) => path.join(pkg, 'package.json'))
const flatten = (target, item) => target.concat(item)
const globFlatten = (files, pattern) => glob.sync(pattern).reduce(flatten, files)
const dependencies = patterns
  .reduce(globFlatten, [])
  .map((file) => path.join(rootPath, file))
  .map((file) => fs.readFileSync(file, 'utf8'))
  .map((file) => JSON.parse(file))
  .concat(corePkg)
  .map((file) => ({
    name: file.name,
    deps: Object.assign({}, file.dependencies || {}, file.devDependencies || {}),
  }))

const versionRanges = {}
const fixable = {}

dependencies.forEach((item) => {
  if (!item.name) {
    return
  }

  Object.keys(item.deps).forEach((pkg) => {
    const version = item.deps[pkg]
    versionRanges[pkg] = versionRanges[pkg] || {}
    versionRanges[pkg][version] = versionRanges[pkg][version] || []
    versionRanges[pkg][version].push(item.name)
  })
})

Object.keys(versionRanges).forEach((depName) => {
  const versions = Object.keys(versionRanges[depName])
  if (versions.length === 1) {
    return
  }

  const plain = versions
    .map(stripRange)
    .filter((version) => /^\d+\.\d+\.\d+/.test(version))
    .sort(semver.rcompare)

  const greatestVersion = plain[0]
  const greatestMajor = `${semver.major(greatestVersion)}.0.0`
  const greatestRange = `^${greatestVersion}`

  console.log('')
  console.log(chalk.cyan(depName))

  sortRanges(versions).forEach((range) => {
    const packages = versionRanges[depName][range]

    let isFixable
    try {
      isFixable = semver.satisfies(stripRange(range), `^${greatestMajor}`)
    } catch (err) {
      return
    }

    const isGreatest = range === greatestRange
    const sign = isGreatest || isFixable ? chalk.green('✔') : chalk.red('✖')

    console.log(`  ${chalk[isGreatest ? 'green' : 'yellow'](range)}:`)
    console.log(`    ${sign} ${packages.join(`\n    ${sign} `)}`)

    if (range === greatestRange || !isFixable) {
      return
    }

    packages.forEach((pkgName) => {
      fixable[pkgName] = fixable[pkgName] || []
      fixable[pkgName].push({depName, version: greatestRange})
    })
  })
})

const fixablePackages = Object.keys(fixable)

fixablePackages.forEach((pkg) => {
  const toFix = fixable[pkg]
  const manifestPath =
    pkg === corePkg.name
      ? path.join(rootPath, 'package.json')
      : path.join(rootPath, 'packages', pkg, 'package.json')

  // eslint-disable-next-line import/no-dynamic-require
  const manifest = require(manifestPath)
  toFix.forEach((dep) => {
    const depSection = (manifest.dependencies || {})[dep.depName]
      ? manifest.dependencies
      : manifest.devDependencies

    depSection[dep.depName] =
      dep.depName.indexOf('@sanity/') === 0 ? dep.version.replace(/^[~^]/, '') : dep.version
  })

  const json = `${JSON.stringify(manifest, null, 2)}\n`
  fs.writeFileSync(manifestPath, json, 'utf-8')
})

if (fixablePackages.length > 0) {
  console.log('')
  console.log(
    [
      'Updated version ranges for %d packages,',
      'you might want to run "npm run bootstrap"',
      'and run some tests before pushing changes',
    ].join(' '),
    fixablePackages.length
  )
}
<commit_msg>chore: render path to `package.json` when running `npm run versions`<commit_after>/* eslint-disable no-sync, no-console, id-length */
const fs = require('fs')
const path = require('path')
const glob = require('glob')
const chalk = require('chalk')
const semver = require('semver')
const config = require('../lerna.json')
const corePkg = require('../package.json')

const rootPath = path.join(__dirname, '..')
const stripRange = (version) => version.replace(/^[~^]/, '')
const sortRanges = (ranges) =>
  ranges.sort((a, b) => {
    try {
      return semver.compare(stripRange(a), stripRange(b))
    } catch (err) {
      return 1
    }
  })
const patterns = config.packages.map((pkg) => path.join(pkg, 'package.json'))
const flatten = (target, item) => target.concat(item)
const globFlatten = (files, pattern) => glob.sync(pattern).reduce(flatten, files)
const pkgs = patterns
  .reduce(globFlatten, [])
  .map((file) => path.join(rootPath, file))
  .map((file) => ({contents: fs.readFileSync(file, 'utf8'), file}))
  .map(({contents, file}) => ({file, pkg: JSON.parse(contents)}))
  .concat([{file: path.join(rootPath, 'package.json'), pkg: corePkg}])
  .map(({file, pkg}) => ({
    file,
    name: pkg.name,
    deps: Object.assign({}, pkg.dependencies || {}, pkg.devDependencies || {}),
  }))

const versionRanges = {}
const fixable = {}

pkgs.forEach((pkg) => {
  if (!pkg.name) {
    return
  }

  Object.keys(pkg.deps).forEach((depName) => {
    const version = pkg.deps[depName]
    versionRanges[depName] = versionRanges[depName] || {}
    versionRanges[depName][version] = versionRanges[depName][version] || []
    versionRanges[depName][version].push(pkg.name)
  })
})

Object.keys(versionRanges).forEach((depName) => {
  const versions = Object.keys(versionRanges[depName])
  if (versions.length === 1) {
    return
  }

  const plain = versions
    .map(stripRange)
    .filter((version) => /^\d+\.\d+\.\d+/.test(version))
    .sort(semver.rcompare)

  const greatestVersion = plain[0]
  const greatestMajor = `${semver.major(greatestVersion)}.0.0`
  const greatestRange = `^${greatestVersion}`

  console.log('')
  console.log(chalk.cyan(depName))

  sortRanges(versions).forEach((range) => {
    const packages = versionRanges[depName][range]

    let isFixable
    try {
      isFixable = semver.satisfies(stripRange(range), `^${greatestMajor}`)
    } catch (err) {
      return
    }

    const isGreatest = range === greatestRange
    const sign = isGreatest || isFixable ? chalk.green('✔') : chalk.red('✖')

    console.log(`  ${chalk[isGreatest ? 'green' : 'yellow'](range)}:`)
    console.log(
      `    ${sign} ${packages
        .map((pkgName) => {
          // eslint-disable-next-line max-nested-callbacks
          const pkg = pkgs.find((p) => p.name === pkgName)

          return `${pkgName} ${chalk.gray(path.relative(rootPath, pkg.file))}`
        })
        .join(`\n    ${sign} `)}`
    )

    if (range === greatestRange || !isFixable) {
      return
    }

    packages.forEach((pkgName) => {
      fixable[pkgName] = fixable[pkgName] || []
      fixable[pkgName].push({depName, version: greatestRange})
    })
  })
})

const fixablePackages = Object.keys(fixable)

fixablePackages.forEach((pkg) => {
  const toFix = fixable[pkg]
  const manifestPath =
    pkg === corePkg.name
      ? path.join(rootPath, 'package.json')
      : path.join(rootPath, 'packages', pkg, 'package.json')

  // eslint-disable-next-line import/no-dynamic-require
  const manifest = require(manifestPath)
  toFix.forEach((dep) => {
    const depSection = (manifest.dependencies || {})[dep.depName]
      ? manifest.dependencies
      : manifest.devDependencies

    depSection[dep.depName] =
      dep.depName.indexOf('@sanity/') === 0 ? dep.version.replace(/^[~^]/, '') : dep.version
  })

  const json = `${JSON.stringify(manifest, null, 2)}\n`
  fs.writeFileSync(manifestPath, json, 'utf-8')
})

if (fixablePackages.length > 0) {
  console.log('')
  console.log(
    [
      'Updated version ranges for %d packages,',
      'you might want to run "npm run bootstrap"',
      'and run some tests before pushing changes',
    ].join(' '),
    fixablePackages.length
  )
}
<|endoftext|>


<commit_before>import Ticker from "../../dlib/util/Ticker.js";

export default class TickerElement extends HTMLElement {
  constructor({ autoplay = false, background = false } = {}) {
    super();

    this._autoplay = autoplay || this.hasAttribute("autoplay");
    this._background = background || this.hasAttribute("background");

    this._paused = true;
    this._pausedByUser = true;
    this._pausedByBlur = false;

    this._updateBinded = this.update.bind(this);
    this._onFocusChangeBinded = this._onFocusChange.bind(this);
  }

  connectedCallback() {
    if (!this._background) {
      window.top.addEventListener("blur", this._onFocusChangeBinded);
      window.top.addEventListener("focus", this._onFocusChangeBinded);
      document.addEventListener("visibilitychange", this._onFocusChangeBinded);
    }
    if (this._autoplay) {
      if (!window.top.document.hasFocus() && !this._background) {
        this._pausedByBlur = true;
        requestAnimationFrame(this._updateBinded);
      }
      this.play();
    }
  }

  disconnectedCallback() {
    this._pausedByBlur = true;
    window.top.removeEventListener("blur", this._onFocusChangeBinded);
    window.top.removeEventListener("focus", this._onFocusChangeBinded);
    document.removeEventListener("visibilitychange", this._onFocusChangeBinded);
  }

  get paused() {
    return this._paused;
  }

  get _pausedByUser() {
    return this.__pausedByUser;
  }

  set _pausedByUser(value) {
    this.__pausedByUser = value;
    this._updatePlaybackState();
  }

  get _pausedByBlur() {
    return this.__pausedByBlur;
  }

  set _pausedByBlur(value) {
    this.__pausedByBlur = value;
    this._updatePlaybackState();
  }

  _onFocusChange(event) {
    switch (event.type) {
      case "visibilitychange":
        if (document.visibilityState !== "visible") {
          this._pausedByBlur = true;
        }
        break;
      case "blur":
        this._pausedByBlur = true;
        break;
      case "focus":
        this._pausedByBlur = false;
        break;
    }
  }

  _updatePlaybackState() {
    const paused = this._pausedByUser || this._pausedByBlur;

    if (paused === this._paused) {
      return;
    }

    this._paused = paused;

    if (this._paused) {
      Ticker.delete(this._updateBinded);
      this.dispatchEvent(new Event("pause"));
    } else {
      Ticker.add(this._updateBinded);
      this.dispatchEvent(new Event("playing"));
    }
  }

  play() {
    this._pausedByUser = false;
  }

  pause() {
    this._pausedByUser = true;
  }

  update() { }
}
<commit_msg>fix triggered event<commit_after>import Ticker from "../../dlib/util/Ticker.js";

export default class TickerElement extends HTMLElement {
  constructor({ autoplay = false, background = false } = {}) {
    super();

    this._autoplay = autoplay || this.hasAttribute("autoplay");
    this._background = background || this.hasAttribute("background");

    this._paused = true;
    this._pausedByUser = true;
    this._pausedByBlur = false;

    this._updateBinded = this.update.bind(this);
    this._onFocusChangeBinded = this._onFocusChange.bind(this);
  }

  connectedCallback() {
    if (!this._background) {
      window.top.addEventListener("blur", this._onFocusChangeBinded);
      window.top.addEventListener("focus", this._onFocusChangeBinded);
      document.addEventListener("visibilitychange", this._onFocusChangeBinded);
    }
    if (this._autoplay) {
      if (!window.top.document.hasFocus() && !this._background) {
        this._pausedByBlur = true;
        requestAnimationFrame(this._updateBinded);
      }
      this.play();
    }
  }

  disconnectedCallback() {
    this._pausedByBlur = true;
    window.top.removeEventListener("blur", this._onFocusChangeBinded);
    window.top.removeEventListener("focus", this._onFocusChangeBinded);
    document.removeEventListener("visibilitychange", this._onFocusChangeBinded);
  }

  get paused() {
    return this._paused;
  }

  get _pausedByUser() {
    return this.__pausedByUser;
  }

  set _pausedByUser(value) {
    this.__pausedByUser = value;
    this._updatePlaybackState();
  }

  get _pausedByBlur() {
    return this.__pausedByBlur;
  }

  set _pausedByBlur(value) {
    this.__pausedByBlur = value;
    this._updatePlaybackState();
  }

  _onFocusChange(event) {
    switch (event.type) {
      case "visibilitychange":
        if (document.visibilityState !== "visible") {
          this._pausedByBlur = true;
        }
        break;
      case "blur":
        this._pausedByBlur = true;
        break;
      case "focus":
        this._pausedByBlur = false;
        break;
    }
  }

  _updatePlaybackState() {
    const paused = this._pausedByUser || this._pausedByBlur;

    if (paused === this._paused) {
      return;
    }

    this._paused = paused;

    if (this._paused) {
      Ticker.delete(this._updateBinded);
      this.dispatchEvent(new Event("pause"));
    } else {
      Ticker.add(this._updateBinded);
      this.dispatchEvent(new Event("play"));
    }
  }

  play() {
    this._pausedByUser = false;
  }

  pause() {
    this._pausedByUser = true;
  }

  update() { }
}
<|endoftext|>


<commit_before>module.exports = {
  env: {
    es6: true
  },
  parserOptions: {
    ecmaVersion: 6,
    sourceType: 'module'
  },
  plugins: [
    'import'
  ],

  settings: {
    'import/resolver': {
      node: {
        extensions: ['.js', '.json']
      }
    },
    'import/extensions': [
      'node_modules'
    ],
    'import/core-modules': [
    ],
    'import/ignore': [
      'node_modules',
      '\\.(coffee|scss|css|less|hbs|svg|json)$'
    ]
  },

  rules: {
    // Static analysis:

    // ensure imports point to files/modules that can be resolved
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unresolved.md
    'import/no-unresolved': [2, { commonjs: true }],

    // ensure named imports coupled with named exports
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/named.md#when-not-to-use-it
    'import/named': 0,

    // ensure default import coupled with default export
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/default.md#when-not-to-use-it
    'import/default': 0,

    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/namespace.md
    'import/namespace': 0,

    // Helpful warnings:

    // disallow invalid exports, e.g. multiple defaults
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/export.md
    'import/export': 2,

    // do not allow a default import name to match a named export
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-named-as-default.md
    'import/no-named-as-default': 2,

    // warn on accessing default export property names that are also named exports
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-named-as-default-member.md
    'import/no-named-as-default-member': 2,

    // disallow use of jsdoc-marked-deprecated imports
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-deprecated.md
    'import/no-deprecated': 0,

    // Forbid the use of extraneous packages
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-extraneous-dependencies.md
    'import/no-extraneous-dependencies': [2, {
      devDependencies: false,
      optionalDependencies: false
    }],

    // Forbid mutable exports
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md
    'import/no-mutable-exports': 2,

    // Module systems:

    // disallow require()
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-commonjs.md
    'import/no-commonjs': 0,

    // disallow AMD require/define
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-amd.md
    'import/no-amd': 2,

    // No Node.js builtin modules
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-nodejs-modules.md
    // TODO: enable?
    'import/no-nodejs-modules': 0,

    // Style guide:

    // disallow non-import statements appearing before import statements
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/imports-first.md
    'import/imports-first': [2, 'absolute-first'],

    // disallow duplicate imports
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-duplicates.md
    'import/no-duplicates': 2,

    // disallow namespace imports
    // TODO: enable?
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-namespace.md
    'import/no-namespace': 0,

    // Ensure consistent use of file extension within the import path
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/extensions.md
    // TODO: enable when https://github.com/benmosher/eslint-plugin-import/issues/390 is resolved
    'import/extensions': [0, 'never'],

    // Enforce a convention in module import order
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/order.md
    // TODO: enable?
    'import/order': [0, {
      groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
      'newlines-between': 'never'
    }],

    // Require a newline after the last import/require in a group
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/newline-after-import.md
    'import/newline-after-import': 2,

    // Require modules with a single export to use a default export
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md
    'import/prefer-default-export': 2,

    // Restrict which files can be imported in a given folder
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-restricted-paths.md
    'import/no-restricted-paths': 0
  }
};
<commit_msg>allow to import devDebendencies and optionalDependencies<commit_after>module.exports = {
  env: {
    es6: true
  },
  parserOptions: {
    ecmaVersion: 6,
    sourceType: 'module'
  },
  plugins: [
    'import'
  ],

  settings: {
    'import/resolver': {
      node: {
        extensions: ['.js', '.json']
      }
    },
    'import/extensions': [
      'node_modules'
    ],
    'import/core-modules': [
    ],
    'import/ignore': [
      'node_modules',
      '\\.(coffee|scss|css|less|hbs|svg|json)$'
    ]
  },

  rules: {
    // Static analysis:

    // ensure imports point to files/modules that can be resolved
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unresolved.md
    'import/no-unresolved': [2, { commonjs: true }],

    // ensure named imports coupled with named exports
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/named.md#when-not-to-use-it
    'import/named': 0,

    // ensure default import coupled with default export
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/default.md#when-not-to-use-it
    'import/default': 0,

    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/namespace.md
    'import/namespace': 0,

    // Helpful warnings:

    // disallow invalid exports, e.g. multiple defaults
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/export.md
    'import/export': 2,

    // do not allow a default import name to match a named export
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-named-as-default.md
    'import/no-named-as-default': 2,

    // warn on accessing default export property names that are also named exports
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-named-as-default-member.md
    'import/no-named-as-default-member': 2,

    // disallow use of jsdoc-marked-deprecated imports
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-deprecated.md
    'import/no-deprecated': 0,

    // Forbid the use of extraneous packages
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-extraneous-dependencies.md
    'import/no-extraneous-dependencies': [2, {
      devDependencies: true,
      optionalDependencies: true
    }],

    // Forbid mutable exports
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md
    'import/no-mutable-exports': 2,

    // Module systems:

    // disallow require()
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-commonjs.md
    'import/no-commonjs': 0,

    // disallow AMD require/define
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-amd.md
    'import/no-amd': 2,

    // No Node.js builtin modules
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-nodejs-modules.md
    // TODO: enable?
    'import/no-nodejs-modules': 0,

    // Style guide:

    // disallow non-import statements appearing before import statements
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/imports-first.md
    'import/imports-first': [2, 'absolute-first'],

    // disallow duplicate imports
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-duplicates.md
    'import/no-duplicates': 2,

    // disallow namespace imports
    // TODO: enable?
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-namespace.md
    'import/no-namespace': 0,

    // Ensure consistent use of file extension within the import path
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/extensions.md
    // TODO: enable when https://github.com/benmosher/eslint-plugin-import/issues/390 is resolved
    'import/extensions': [0, 'never'],

    // Enforce a convention in module import order
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/order.md
    // TODO: enable?
    'import/order': [0, {
      groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
      'newlines-between': 'never'
    }],

    // Require a newline after the last import/require in a group
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/newline-after-import.md
    'import/newline-after-import': 2,

    // Require modules with a single export to use a default export
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md
    'import/prefer-default-export': 2,

    // Restrict which files can be imported in a given folder
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-restricted-paths.md
    'import/no-restricted-paths': 0
  }
};
<|endoftext|>


<commit_before>/* @flow */
const { execSync } = require(`child_process`)
const execa = require(`execa`)
const hostedGitInfo = require(`hosted-git-info`)
const fs = require(`fs-extra`)
const sysPath = require(`path`)
const report = require(`./reporter`)
const url = require(`url`)
const isValid = require(`is-valid-path`)
const existsSync = require(`fs-exists-cached`).sync
const { trackCli, trackError } = require(`gatsby-telemetry`)
const prompts = require(`prompts`)
const opn = require(`better-opn`)

const {
  getPackageManager,
  promptPackageManager,
} = require(`./util/configstore`)
const isTTY = require(`./util/is-tty`)
const spawn = (cmd: string, options: any) => {
  const [file, ...args] = cmd.split(/\s+/)
  return spawnWithArgs(file, args, options)
}
const spawnWithArgs = (file: string, args: string[], options: any) =>
  execa(file, args, { stdio: `inherit`, preferLocal: false, ...options })

// Checks the existence of yarn package and user preference if it exists
// We use yarnpkg instead of yarn to avoid conflict with Hadoop yarn
// Refer to https://github.com/yarnpkg/yarn/issues/673
const shouldUseYarn = async () => {
  try {
    execSync(`yarnpkg --version`, { stdio: `ignore` })

    let packageManager = getPackageManager()
    if (!packageManager) {
      // if package manager is not set:
      //  - prompt user to pick package manager if in interactive console
      //  - default to yarn if not in interactive console
      if (isTTY()) {
        packageManager = (await promptPackageManager()) || `yarn`
      } else {
        packageManager = `yarn`
      }
    }

    return packageManager === `yarn`
  } catch (e) {
    return false
  }
}

const isAlreadyGitRepository = async () => {
  try {
    return await spawn(`git rev-parse --is-inside-work-tree`, {
      stdio: `pipe`,
    }).then(output => output.stdout === `true`)
  } catch (err) {
    return false
  }
}

// Initialize newly cloned directory as a git repo
const gitInit = async rootPath => {
  report.info(`Initialising git in ${rootPath}`)

  return await spawn(`git init`, { cwd: rootPath })
}

// Create a .gitignore file if it is missing in the new directory
const maybeCreateGitIgnore = async rootPath => {
  if (existsSync(sysPath.join(rootPath, `.gitignore`))) {
    return
  }

  report.info(`Creating minimal .gitignore in ${rootPath}`)
  await fs.writeFile(
    sysPath.join(rootPath, `.gitignore`),
    `.cache\nnode_modules\npublic\n`
  )
}

// Create an initial git commit in the new directory
const createInitialGitCommit = async (rootPath, starterUrl) => {
  report.info(`Create initial git commit in ${rootPath}`)

  await spawn(`git add -A`, { cwd: rootPath })
  // use execSync instead of spawn to handle git clients using
  // pgp signatures (with password)
  execSync(`git commit -m "Initial commit from gatsby: (${starterUrl})"`, {
    cwd: rootPath,
  })
}

// Executes `npm install` or `yarn install` in rootPath.
const install = async rootPath => {
  const prevDir = process.cwd()

  report.info(`Installing packages...`)
  process.chdir(rootPath)

  try {
    if (await shouldUseYarn()) {
      await fs.remove(`package-lock.json`)
      await spawn(`yarnpkg`)
    } else {
      await fs.remove(`yarn.lock`)
      await spawn(`npm install`)
    }
  } finally {
    process.chdir(prevDir)
  }
}

const ignored = path => !/^\.(git|hg)$/.test(sysPath.basename(path))

// Copy starter from file system.
const copy = async (starterPath: string, rootPath: string) => {
  // Chmod with 755.
  // 493 = parseInt('755', 8)
  await fs.mkdirp(rootPath, { mode: 493 })

  if (!existsSync(starterPath)) {
    throw new Error(`starter ${starterPath} doesn't exist`)
  }

  if (starterPath === `.`) {
    throw new Error(
      `You can't create a starter from the existing directory. If you want to
      create a new site in the current directory, the trailing dot isn't
      necessary. If you want to create a new site from a local starter, run
      something like "gatsby new new-gatsby-site ../my-gatsby-starter"`
    )
  }

  report.info(`Creating new site from local starter: ${starterPath}`)

  report.log(`Copying local starter to ${rootPath} ...`)

  await fs.copy(starterPath, rootPath, { filter: ignored })

  report.success(`Created starter directory layout`)

  await install(rootPath)

  return true
}

// Clones starter from URI.
const clone = async (hostInfo: any, rootPath: string) => {
  let url
  // Let people use private repos accessed over SSH.
  if (hostInfo.getDefaultRepresentation() === `sshurl`) {
    url = hostInfo.ssh({ noCommittish: true })
    // Otherwise default to normal git syntax.
  } else {
    url = hostInfo.https({ noCommittish: true, noGitPlus: true })
  }

  const branch = hostInfo.committish ? [`-b`, `hostInfo.committish`] : [``]

  report.info(`Creating new site from git: ${url}`)

  const args = [`clone`, ...branch, url, rootPath, `--single-branch`].filter(
    arg => Boolean(arg)
  )

  await spawnWithArgs(`git`, args)

  report.success(`Created starter directory layout`)

  await fs.remove(sysPath.join(rootPath, `.git`))

  await install(rootPath)
  const isGit = await isAlreadyGitRepository()
  if (!isGit) await gitInit(rootPath)
  await maybeCreateGitIgnore(rootPath)
  if (!isGit) await createInitialGitCommit(rootPath, url)
}

const getPaths = async (starterPath: string, rootPath: string) => {
  let selectedOtherStarter = false

  // if no args are passed, prompt user for path and starter
  if (!starterPath && !rootPath) {
    const response = await prompts.prompt([
      {
        type: `text`,
        name: `path`,
        message: `What is your project called?`,
        initial: `my-gatsby-project`,
      },
      {
        type: `select`,
        name: `starter`,
        message: `What starter would you like to use?`,
        choices: [
          { title: `gatsby-starter-default`, value: `gatsby-starter-default` },
          {
            title: `gatsby-starter-hello-world`,
            value: `gatsby-starter-hello-world`,
          },
          { title: `gatsby-starter-blog`, value: `gatsby-starter-blog` },
          { title: `(Use a different starter)`, value: `different` },
        ],
        initial: 0,
      },
    ])
    // exit gracefully if responses aren't provided
    if (!response.starter || !response.path) {
      process.exit()
    }

    selectedOtherStarter = response.starter === `different`
    starterPath = `gatsbyjs/${response.starter}`
    rootPath = response.path
  }

  // set defaults if no root or starter has been set yet
  rootPath = rootPath || process.cwd()
  starterPath = starterPath || `gatsbyjs/gatsby-starter-default`

  return { starterPath, rootPath, selectedOtherStarter }
}

type InitOptions = {
  rootPath?: string,
}

/**
 * Main function that clones or copies the starter.
 */
module.exports = async (starter: string, options: InitOptions = {}) => {
  const { starterPath, rootPath, selectedOtherStarter } = await getPaths(
    starter,
    options.rootPath
  )

  const urlObject = url.parse(rootPath)

  if (selectedOtherStarter) {
    report.info(
      `Opening the starter library at https://gatsby.dev/starters?v=2...\nThe starter library has a variety of options for starters you can browse\n\nYou can then use the gatsby new command with the link to a repository of a starter you'd like to use, for example:\ngatsby new ${rootPath} https://github.com/gatsbyjs/gatsby-starter-default`
    )
    opn(`https://gatsby.dev/starters?v=2`)
    return
  }

  if (urlObject.protocol && urlObject.host) {
    trackError(`NEW_PROJECT_NAME_MISSING`)
    report.panic(
      `It looks like you forgot to add a name for your new project. Try running instead "gatsby new new-gatsby-project ${rootPath}"`
    )
    return
  }

  if (!isValid(rootPath)) {
    report.panic(
      `Could not create a project in "${sysPath.resolve(
        rootPath
      )}" because it's not a valid path`
    )
    return
  }

  if (existsSync(sysPath.join(rootPath, `package.json`))) {
    trackError(`NEW_PROJECT_IS_NPM_PROJECT`)
    report.panic(`Directory ${rootPath} is already an npm project`)
    return
  }

  const hostedInfo = hostedGitInfo.fromUrl(starterPath)

  trackCli(`NEW_PROJECT`, {
    starterName: hostedInfo ? hostedInfo.shortcut() : `local:starter`,
  })
  if (hostedInfo) await clone(hostedInfo, rootPath)
  else await copy(starterPath, rootPath)
  trackCli(`NEW_PROJECT_END`)
}
<commit_msg>fix(gatsby-cli): fix cloning repository with commithash (#17263)<commit_after>/* @flow */
const { execSync } = require(`child_process`)
const execa = require(`execa`)
const hostedGitInfo = require(`hosted-git-info`)
const fs = require(`fs-extra`)
const sysPath = require(`path`)
const report = require(`./reporter`)
const url = require(`url`)
const isValid = require(`is-valid-path`)
const existsSync = require(`fs-exists-cached`).sync
const { trackCli, trackError } = require(`gatsby-telemetry`)
const prompts = require(`prompts`)
const opn = require(`better-opn`)

const {
  getPackageManager,
  promptPackageManager,
} = require(`./util/configstore`)
const isTTY = require(`./util/is-tty`)
const spawn = (cmd: string, options: any) => {
  const [file, ...args] = cmd.split(/\s+/)
  return spawnWithArgs(file, args, options)
}
const spawnWithArgs = (file: string, args: string[], options: any) =>
  execa(file, args, { stdio: `inherit`, preferLocal: false, ...options })

// Checks the existence of yarn package and user preference if it exists
// We use yarnpkg instead of yarn to avoid conflict with Hadoop yarn
// Refer to https://github.com/yarnpkg/yarn/issues/673
const shouldUseYarn = async () => {
  try {
    execSync(`yarnpkg --version`, { stdio: `ignore` })

    let packageManager = getPackageManager()
    if (!packageManager) {
      // if package manager is not set:
      //  - prompt user to pick package manager if in interactive console
      //  - default to yarn if not in interactive console
      if (isTTY()) {
        packageManager = (await promptPackageManager()) || `yarn`
      } else {
        packageManager = `yarn`
      }
    }

    return packageManager === `yarn`
  } catch (e) {
    return false
  }
}

const isAlreadyGitRepository = async () => {
  try {
    return await spawn(`git rev-parse --is-inside-work-tree`, {
      stdio: `pipe`,
    }).then(output => output.stdout === `true`)
  } catch (err) {
    return false
  }
}

// Initialize newly cloned directory as a git repo
const gitInit = async rootPath => {
  report.info(`Initialising git in ${rootPath}`)

  return await spawn(`git init`, { cwd: rootPath })
}

// Create a .gitignore file if it is missing in the new directory
const maybeCreateGitIgnore = async rootPath => {
  if (existsSync(sysPath.join(rootPath, `.gitignore`))) {
    return
  }

  report.info(`Creating minimal .gitignore in ${rootPath}`)
  await fs.writeFile(
    sysPath.join(rootPath, `.gitignore`),
    `.cache\nnode_modules\npublic\n`
  )
}

// Create an initial git commit in the new directory
const createInitialGitCommit = async (rootPath, starterUrl) => {
  report.info(`Create initial git commit in ${rootPath}`)

  await spawn(`git add -A`, { cwd: rootPath })
  // use execSync instead of spawn to handle git clients using
  // pgp signatures (with password)
  execSync(`git commit -m "Initial commit from gatsby: (${starterUrl})"`, {
    cwd: rootPath,
  })
}

// Executes `npm install` or `yarn install` in rootPath.
const install = async rootPath => {
  const prevDir = process.cwd()

  report.info(`Installing packages...`)
  process.chdir(rootPath)

  try {
    if (await shouldUseYarn()) {
      await fs.remove(`package-lock.json`)
      await spawn(`yarnpkg`)
    } else {
      await fs.remove(`yarn.lock`)
      await spawn(`npm install`)
    }
  } finally {
    process.chdir(prevDir)
  }
}

const ignored = path => !/^\.(git|hg)$/.test(sysPath.basename(path))

// Copy starter from file system.
const copy = async (starterPath: string, rootPath: string) => {
  // Chmod with 755.
  // 493 = parseInt('755', 8)
  await fs.mkdirp(rootPath, { mode: 493 })

  if (!existsSync(starterPath)) {
    throw new Error(`starter ${starterPath} doesn't exist`)
  }

  if (starterPath === `.`) {
    throw new Error(
      `You can't create a starter from the existing directory. If you want to
      create a new site in the current directory, the trailing dot isn't
      necessary. If you want to create a new site from a local starter, run
      something like "gatsby new new-gatsby-site ../my-gatsby-starter"`
    )
  }

  report.info(`Creating new site from local starter: ${starterPath}`)

  report.log(`Copying local starter to ${rootPath} ...`)

  await fs.copy(starterPath, rootPath, { filter: ignored })

  report.success(`Created starter directory layout`)

  await install(rootPath)

  return true
}

// Clones starter from URI.
const clone = async (hostInfo: any, rootPath: string) => {
  let url
  // Let people use private repos accessed over SSH.
  if (hostInfo.getDefaultRepresentation() === `sshurl`) {
    url = hostInfo.ssh({ noCommittish: true })
    // Otherwise default to normal git syntax.
  } else {
    url = hostInfo.https({ noCommittish: true, noGitPlus: true })
  }

  const branch = hostInfo.committish ? [`-b`, hostInfo.committish] : []

  report.info(`Creating new site from git: ${url}`)

  const args = [`clone`, ...branch, url, rootPath, `--single-branch`].filter(
    arg => Boolean(arg)
  )

  await spawnWithArgs(`git`, args)

  report.success(`Created starter directory layout`)

  await fs.remove(sysPath.join(rootPath, `.git`))

  await install(rootPath)
  const isGit = await isAlreadyGitRepository()
  if (!isGit) await gitInit(rootPath)
  await maybeCreateGitIgnore(rootPath)
  if (!isGit) await createInitialGitCommit(rootPath, url)
}

const getPaths = async (starterPath: string, rootPath: string) => {
  let selectedOtherStarter = false

  // if no args are passed, prompt user for path and starter
  if (!starterPath && !rootPath) {
    const response = await prompts.prompt([
      {
        type: `text`,
        name: `path`,
        message: `What is your project called?`,
        initial: `my-gatsby-project`,
      },
      {
        type: `select`,
        name: `starter`,
        message: `What starter would you like to use?`,
        choices: [
          { title: `gatsby-starter-default`, value: `gatsby-starter-default` },
          {
            title: `gatsby-starter-hello-world`,
            value: `gatsby-starter-hello-world`,
          },
          { title: `gatsby-starter-blog`, value: `gatsby-starter-blog` },
          { title: `(Use a different starter)`, value: `different` },
        ],
        initial: 0,
      },
    ])
    // exit gracefully if responses aren't provided
    if (!response.starter || !response.path) {
      process.exit()
    }

    selectedOtherStarter = response.starter === `different`
    starterPath = `gatsbyjs/${response.starter}`
    rootPath = response.path
  }

  // set defaults if no root or starter has been set yet
  rootPath = rootPath || process.cwd()
  starterPath = starterPath || `gatsbyjs/gatsby-starter-default`

  return { starterPath, rootPath, selectedOtherStarter }
}

type InitOptions = {
  rootPath?: string,
}

/**
 * Main function that clones or copies the starter.
 */
module.exports = async (starter: string, options: InitOptions = {}) => {
  const { starterPath, rootPath, selectedOtherStarter } = await getPaths(
    starter,
    options.rootPath
  )

  const urlObject = url.parse(rootPath)

  if (selectedOtherStarter) {
    report.info(
      `Opening the starter library at https://gatsby.dev/starters?v=2...\nThe starter library has a variety of options for starters you can browse\n\nYou can then use the gatsby new command with the link to a repository of a starter you'd like to use, for example:\ngatsby new ${rootPath} https://github.com/gatsbyjs/gatsby-starter-default`
    )
    opn(`https://gatsby.dev/starters?v=2`)
    return
  }

  if (urlObject.protocol && urlObject.host) {
    trackError(`NEW_PROJECT_NAME_MISSING`)
    report.panic(
      `It looks like you forgot to add a name for your new project. Try running instead "gatsby new new-gatsby-project ${rootPath}"`
    )
    return
  }

  if (!isValid(rootPath)) {
    report.panic(
      `Could not create a project in "${sysPath.resolve(
        rootPath
      )}" because it's not a valid path`
    )
    return
  }

  if (existsSync(sysPath.join(rootPath, `package.json`))) {
    trackError(`NEW_PROJECT_IS_NPM_PROJECT`)
    report.panic(`Directory ${rootPath} is already an npm project`)
    return
  }

  const hostedInfo = hostedGitInfo.fromUrl(starterPath)

  trackCli(`NEW_PROJECT`, {
    starterName: hostedInfo ? hostedInfo.shortcut() : `local:starter`,
  })
  if (hostedInfo) await clone(hostedInfo, rootPath)
  else await copy(starterPath, rootPath)
  trackCli(`NEW_PROJECT_END`)
}
<|endoftext|>


<commit_before>// -------------------------------------------------------------------------- \\
// File: CalendarEventOccurrence.js                                           \\
// Module: CalendarModel                                                      \\
// Requires: CalendarEvent.js                                                 \\
// Author: Neil Jenkins                                                       \\
// License: © 2010-2015 FastMail Pty Ltd. MIT Licensed.                       \\
// -------------------------------------------------------------------------- \\

/*global O, JMAP */

"use strict";

( function ( JMAP, undefined ) {

var CalendarEvent = JMAP.CalendarEvent;

// ---

var mayPatch = {
    links: true,
    translations: true,
    locations: true,
    participants: true,
    alerts: true
};

var makePatches = function ( path, patches, original, current ) {
    var key;
    if ( original && current && typeof current === 'object' &&
            !( current instanceof Array ) ) {
        for ( key in current ) {
            makePatches(
                path + '/' + key.replace( /~/g, '~0' ).replace( /\//g, '~1' ),
                patches,
                original[ key ],
                current[ key ]
            );
        }
        for ( key in original ) {
            if ( !( key in current ) ) {
                makePatches(
                    path + '/' +
                        key.replace( /~/g, '~0' ).replace( /\//g, '~1' ),
                    patches,
                    original[ key ],
                    null
                );
            }
        }
    } else if ( !O.isEqual( original, current ) ) {
        patches.push([ path, current || null ]);
    }
    return patches;
};

var applyPatch = function ( path, patch, value ) {
    var slash, key;
    while ( true ) {
        slash = path.indexOf( '/' );
        if ( slash > -1 ) {
            key = path.slice( 0, slash );
            path = path.slice( slash + 1 );
        }
        if ( key ) {
            key = key.replace( /~1/g, '/' ).replace( /~0/g, '~' );
        }
        if ( slash > -1 ) {
            value = value[ key ];
        } else {
            if ( patch !== null ) {
                value[ key ] = patch;
            } else {
                delete value[ key ];
            }
            break;
        }
    }
};

var proxyOverrideAttibute = function ( Type, key ) {
    return function ( value ) {
        var original = this.get( 'original' );
        var originalValue = this.getOriginalForKey( key );
        var id = this.id;
        var recurrenceOverrides, recurrenceRule;
        var overrides, keepOverride, path, patches;

        if ( value !== undefined ) {
            // Get current overrides for occurrence
            recurrenceOverrides =
                O.clone( original.get( 'recurrenceOverrides' ) ) || {};
            overrides = recurrenceOverrides[ id ] ||
                ( recurrenceOverrides[ id ] = {} );

            // Clear any previous overrides for this key
            keepOverride = false;
            for ( path in overrides ) {
                if ( path.indexOf( key ) === 0 ) {
                    delete overrides[ path ];
                } else {
                    keepOverride = true;
                }
            }
            // Set if different to parent
            if ( mayPatch[ key ] ) {
                patches = makePatches( key, [], originalValue, value );
                if ( patches.length ) {
                    keepOverride = true;
                    patches.forEach( function ( patch ) {
                        overrides[ patch[0] ] = patch[1];
                    });
                }
            } else if ( !O.isEqual( originalValue, value ) ) {
                keepOverride = true;
                overrides[ key ] = value && value.toJSON ?
                    value.toJSON() : value;
            }

            // Check if we still have any overrides
            if ( !keepOverride ) {
                // Check if matches recurrence rule. If not, keep.
                recurrenceRule = original.get( 'recurrenceRule' );
                if ( recurrenceRule &&
                        recurrenceRule.matches(
                            original.get( 'start' ), this._start
                        )) {
                    delete recurrenceOverrides[ id ];
                }
            }
            if ( !Object.keys( recurrenceOverrides ).length ) {
                recurrenceOverrides = null;
            }

            // Set on original
            original.set( 'recurrenceOverrides', recurrenceOverrides );
        } else {
            overrides = this.get( 'overrides' );
            if ( key in overrides ) {
                return Type.fromJSON ?
                    Type.fromJSON( overrides[ key ] ) :
                    overrides[ key ];
            }
            value = originalValue;
            if ( mayPatch[ key ] ) {
                for ( path in overrides ) {
                    if ( path.indexOf( key ) === 0 ) {
                        if ( value === originalValue ) {
                            value = O.clone( originalValue );
                        }
                        applyPatch( path, overrides[ path ], value );
                    }
                }
            }
        }
        return value;
    }.property( 'overrides', 'original.' + key );
};

var proxyAttribute = function ( _, key ) {
    return this.get( 'original' ).get( key );
}.property().nocache();

var CalendarEventOccurrence = O.Class({

    Extends: O.Object,

    constructor: CalendarEvent,

    isDragging: false,
    isOccurrence: true,

    isEditable: CalendarEvent.prototype.isEditable,
    isInvitation: CalendarEvent.prototype.isInvitation,

    overrides: O.bind( null, 'original*recurrenceOverrides',
    function ( recurrenceOverrides ) {
        var id = this.toObject.id;
        return recurrenceOverrides && recurrenceOverrides[ id ] || {};
    }),

    init: function ( original, id ) {
        this._start = Date.fromJSON( id );

        this.id = id;
        this.original = original;
        // For attachment upload only
        this.store = original.get( 'store' );
        this.storeKey = original.get( 'storeKey' ) + id;

        CalendarEventOccurrence.parent.init.call( this );
        original.on( 'highlightView', this, 'echoEvent' );
    },

    getOriginalForKey: function ( key ) {
        if ( key === 'start' ) {
            return this._start;
        }
        return this.get( 'original' ).get( key );
    },

    getDoppelganger: function ( store ) {
        var original = this.get( 'original' );
        var originalStore = original.get( 'store' );
        if ( originalStore === store ) {
            return this;
        }
        return original.getDoppelganger( store )
                       ._getOccurrenceForRecurrenceId( this.id );
    },

    clone: CalendarEvent.prototype.clone,

    destroy: function () {
        var original = this.get( 'original' );
        var recurrenceOverrides = original.get( 'recurrenceOverrides' );

        recurrenceOverrides = recurrenceOverrides ?
            O.clone( recurrenceOverrides ) : {};
        recurrenceOverrides[ this.id ] = null;
        original.set( 'recurrenceOverrides', recurrenceOverrides );

        this.unload();
    },

    unload: function () {
        this.get( 'original' ).off( 'highlightView', this, 'echoEvent' );
        CalendarEventOccurrence.parent.destroy.call( this );
    },

    is: function ( status ) {
        return this.get( 'original' ).is( status );
    },

    echoEvent: function ( event ) {
        this.fire( event.type, event );
    },

    // ---

    // May not edit calendar prop.
    calendar: proxyAttribute,
    uid: proxyAttribute,
    relatedTo: proxyAttribute,
    prodId: proxyAttribute,

    created: proxyOverrideAttibute( Date, 'created' ),
    updated: proxyOverrideAttibute( Date, 'updated' ),
    sequence: proxyOverrideAttibute( Number, 'sequence' ),

    // ---

    title: proxyOverrideAttibute( String, 'title' ),
    description: proxyOverrideAttibute( String, 'description' ),

    links: proxyOverrideAttibute( Object, 'links' ),

    isUploading: CalendarEvent.prototype.isUploading,
    files: CalendarEvent.prototype.files,
    addFile: CalendarEvent.prototype.addFile,
    removeFile: CalendarEvent.prototype.removeFile,

    // ---

    // locale: proxyOverrideAttibute( String, 'locale' ),
    // localizations: proxyOverrideAttibute( Object, 'localizations' ),

    // ---

    locations: proxyOverrideAttibute( Object, 'locations' ),
    location: CalendarEvent.prototype.location,
    startLocationTimeZone: CalendarEvent.prototype.startLocationTimeZone,
    endLocationTimeZone: CalendarEvent.prototype.endLocationTimeZone,

    // ---

    isAllDay: proxyAttribute,

    start: proxyOverrideAttibute( Date, 'start' ),
    duration: proxyOverrideAttibute( JMAP.Duration, 'duration' ),
    timeZone: proxyOverrideAttibute( O.TimeZone, 'timeZone' ),
    recurrence: proxyAttribute,
    recurrenceOverrides: null,

    getStartInTimeZone: CalendarEvent.prototype.getStartInTimeZone,
    getEndInTimeZone: CalendarEvent.prototype.getEndInTimeZone,

    utcStart: CalendarEvent.prototype.utcStart,
    utcEnd: CalendarEvent.prototype.utcEnd,

    end: CalendarEvent.prototype.end,

    removedDates: null,

    allStartDates: proxyAttribute,
    totalOccurrences: proxyAttribute,

    index: function () {
        var start = this.get( 'start' );
        var original = this.get( 'original' );
        return O.isEqual( start, original.get( 'start' ) ) ? 0 :
            original.get( 'allStartDates' ).binarySearch( this._start );
    }.property().nocache(),

    // ---

    status: proxyOverrideAttibute( String, 'status' ),
    showAsFree: proxyOverrideAttibute( Boolean, 'showAsFree' ),
    replyTo: proxyAttribute,
    participants: proxyOverrideAttibute( Object, 'participants' ),
    participantId: proxyAttribute,

    rsvp: function ( rsvp ) {
        var original = this.get( 'original' );
        var recurrenceOverrides = original.get( 'recurrenceOverrides' );
        var id = this.id;
        // If this is an exception from the organizer, RSVP to just this
        // instance, otherwise RSVP to whole series
        if ( recurrenceOverrides && recurrenceOverrides[ id ] &&
                Object.keys( recurrenceOverrides[ id ] ).some(
                function ( key ) {
                    return key !== 'alerts' && key !== 'useDefaultAlerts';
                })) {
            return CalendarEvent.prototype.rsvp.call( this, rsvp );
        }
        if ( rsvp !== undefined ) {
            original.set( 'rsvp', rsvp );
        }
        return original.get( 'rsvp' );
    }.property( 'participants', 'participantId' ),

    // ---

    useDefaultAlerts: proxyOverrideAttibute( Boolean, 'useDefaultAlerts' ),
    alerts: proxyOverrideAttibute( Object, 'alerts' )
});
O.meta( CalendarEventOccurrence.prototype ).attrs =
    O.meta( CalendarEvent.prototype ).attrs;

JMAP.CalendarEventOccurrence = CalendarEventOccurrence;

}( JMAP ) );
<commit_msg>Fix handling of broken event patches<commit_after>// -------------------------------------------------------------------------- \\
// File: CalendarEventOccurrence.js                                           \\
// Module: CalendarModel                                                      \\
// Requires: CalendarEvent.js                                                 \\
// Author: Neil Jenkins                                                       \\
// License: © 2010-2015 FastMail Pty Ltd. MIT Licensed.                       \\
// -------------------------------------------------------------------------- \\

/*global O, JMAP */

"use strict";

( function ( JMAP, undefined ) {

var CalendarEvent = JMAP.CalendarEvent;

// ---

var mayPatch = {
    links: true,
    translations: true,
    locations: true,
    participants: true,
    alerts: true
};

var makePatches = function ( path, patches, original, current ) {
    var key;
    if ( original && current && typeof current === 'object' &&
            !( current instanceof Array ) ) {
        for ( key in current ) {
            makePatches(
                path + '/' + key.replace( /~/g, '~0' ).replace( /\//g, '~1' ),
                patches,
                original[ key ],
                current[ key ]
            );
        }
        for ( key in original ) {
            if ( !( key in current ) ) {
                makePatches(
                    path + '/' +
                        key.replace( /~/g, '~0' ).replace( /\//g, '~1' ),
                    patches,
                    original[ key ],
                    null
                );
            }
        }
    } else if ( !O.isEqual( original, current ) ) {
        patches.push([ path, current || null ]);
    }
    return patches;
};

var applyPatch = function ( object, path, patch ) {
    var slash, key;
    while ( true ) {
        // Invalid patch; path does not exist
        if ( !object ) {
            return;
        }
        slash = path.indexOf( '/' );
        if ( slash > -1 ) {
            key = path.slice( 0, slash );
            path = path.slice( slash + 1 );
        }
        if ( key ) {
            key = key.replace( /~1/g, '/' ).replace( /~0/g, '~' );
        }
        if ( slash > -1 ) {
            object = object[ key ];
        } else {
            if ( patch !== null ) {
                object[ key ] = patch;
            } else {
                delete object[ key ];
            }
            break;
        }
    }
};

var proxyOverrideAttibute = function ( Type, key ) {
    return function ( value ) {
        var original = this.get( 'original' );
        var originalValue = this.getOriginalForKey( key );
        var id = this.id;
        var recurrenceOverrides, recurrenceRule;
        var overrides, keepOverride, path, patches;

        if ( value !== undefined ) {
            // Get current overrides for occurrence
            recurrenceOverrides =
                O.clone( original.get( 'recurrenceOverrides' ) ) || {};
            overrides = recurrenceOverrides[ id ] ||
                ( recurrenceOverrides[ id ] = {} );

            // Clear any previous overrides for this key
            keepOverride = false;
            for ( path in overrides ) {
                if ( path.indexOf( key ) === 0 ) {
                    delete overrides[ path ];
                } else {
                    keepOverride = true;
                }
            }
            // Set if different to parent
            if ( mayPatch[ key ] ) {
                patches = makePatches( key, [], originalValue, value );
                if ( patches.length ) {
                    keepOverride = true;
                    patches.forEach( function ( patch ) {
                        overrides[ patch[0] ] = patch[1];
                    });
                }
            } else if ( !O.isEqual( originalValue, value ) ) {
                keepOverride = true;
                overrides[ key ] = value && value.toJSON ?
                    value.toJSON() : value;
            }

            // Check if we still have any overrides
            if ( !keepOverride ) {
                // Check if matches recurrence rule. If not, keep.
                recurrenceRule = original.get( 'recurrenceRule' );
                if ( recurrenceRule &&
                        recurrenceRule.matches(
                            original.get( 'start' ), this._start
                        )) {
                    delete recurrenceOverrides[ id ];
                }
            }
            if ( !Object.keys( recurrenceOverrides ).length ) {
                recurrenceOverrides = null;
            }

            // Set on original
            original.set( 'recurrenceOverrides', recurrenceOverrides );
        } else {
            overrides = this.get( 'overrides' );
            if ( key in overrides ) {
                return Type.fromJSON ?
                    Type.fromJSON( overrides[ key ] ) :
                    overrides[ key ];
            }
            value = originalValue;
            if ( value && mayPatch[ key ] ) {
                for ( path in overrides ) {
                    if ( path.indexOf( key ) === 0 ) {
                        if ( value === originalValue ) {
                            value = O.clone( originalValue );
                        }
                        applyPatch( value, path, overrides[ path ] );
                    }
                }
            }
        }
        return value;
    }.property( 'overrides', 'original.' + key );
};

var proxyAttribute = function ( _, key ) {
    return this.get( 'original' ).get( key );
}.property().nocache();

var CalendarEventOccurrence = O.Class({

    Extends: O.Object,

    constructor: CalendarEvent,

    isDragging: false,
    isOccurrence: true,

    isEditable: CalendarEvent.prototype.isEditable,
    isInvitation: CalendarEvent.prototype.isInvitation,

    overrides: O.bind( null, 'original*recurrenceOverrides',
    function ( recurrenceOverrides ) {
        var id = this.toObject.id;
        return recurrenceOverrides && recurrenceOverrides[ id ] || {};
    }),

    init: function ( original, id ) {
        this._start = Date.fromJSON( id );

        this.id = id;
        this.original = original;
        // For attachment upload only
        this.store = original.get( 'store' );
        this.storeKey = original.get( 'storeKey' ) + id;

        CalendarEventOccurrence.parent.init.call( this );
        original.on( 'highlightView', this, 'echoEvent' );
    },

    getOriginalForKey: function ( key ) {
        if ( key === 'start' ) {
            return this._start;
        }
        return this.get( 'original' ).get( key );
    },

    getDoppelganger: function ( store ) {
        var original = this.get( 'original' );
        var originalStore = original.get( 'store' );
        if ( originalStore === store ) {
            return this;
        }
        return original.getDoppelganger( store )
                       ._getOccurrenceForRecurrenceId( this.id );
    },

    clone: CalendarEvent.prototype.clone,

    destroy: function () {
        var original = this.get( 'original' );
        var recurrenceOverrides = original.get( 'recurrenceOverrides' );

        recurrenceOverrides = recurrenceOverrides ?
            O.clone( recurrenceOverrides ) : {};
        recurrenceOverrides[ this.id ] = null;
        original.set( 'recurrenceOverrides', recurrenceOverrides );

        this.unload();
    },

    unload: function () {
        this.get( 'original' ).off( 'highlightView', this, 'echoEvent' );
        CalendarEventOccurrence.parent.destroy.call( this );
    },

    is: function ( status ) {
        return this.get( 'original' ).is( status );
    },

    echoEvent: function ( event ) {
        this.fire( event.type, event );
    },

    // ---

    // May not edit calendar prop.
    calendar: proxyAttribute,
    uid: proxyAttribute,
    relatedTo: proxyAttribute,
    prodId: proxyAttribute,

    created: proxyOverrideAttibute( Date, 'created' ),
    updated: proxyOverrideAttibute( Date, 'updated' ),
    sequence: proxyOverrideAttibute( Number, 'sequence' ),

    // ---

    title: proxyOverrideAttibute( String, 'title' ),
    description: proxyOverrideAttibute( String, 'description' ),

    links: proxyOverrideAttibute( Object, 'links' ),

    isUploading: CalendarEvent.prototype.isUploading,
    files: CalendarEvent.prototype.files,
    addFile: CalendarEvent.prototype.addFile,
    removeFile: CalendarEvent.prototype.removeFile,

    // ---

    // locale: proxyOverrideAttibute( String, 'locale' ),
    // localizations: proxyOverrideAttibute( Object, 'localizations' ),

    // ---

    locations: proxyOverrideAttibute( Object, 'locations' ),
    location: CalendarEvent.prototype.location,
    startLocationTimeZone: CalendarEvent.prototype.startLocationTimeZone,
    endLocationTimeZone: CalendarEvent.prototype.endLocationTimeZone,

    // ---

    isAllDay: proxyAttribute,

    start: proxyOverrideAttibute( Date, 'start' ),
    duration: proxyOverrideAttibute( JMAP.Duration, 'duration' ),
    timeZone: proxyOverrideAttibute( O.TimeZone, 'timeZone' ),
    recurrence: proxyAttribute,
    recurrenceOverrides: null,

    getStartInTimeZone: CalendarEvent.prototype.getStartInTimeZone,
    getEndInTimeZone: CalendarEvent.prototype.getEndInTimeZone,

    utcStart: CalendarEvent.prototype.utcStart,
    utcEnd: CalendarEvent.prototype.utcEnd,

    end: CalendarEvent.prototype.end,

    removedDates: null,

    allStartDates: proxyAttribute,
    totalOccurrences: proxyAttribute,

    index: function () {
        var start = this.get( 'start' );
        var original = this.get( 'original' );
        return O.isEqual( start, original.get( 'start' ) ) ? 0 :
            original.get( 'allStartDates' ).binarySearch( this._start );
    }.property().nocache(),

    // ---

    status: proxyOverrideAttibute( String, 'status' ),
    showAsFree: proxyOverrideAttibute( Boolean, 'showAsFree' ),
    replyTo: proxyAttribute,
    participants: proxyOverrideAttibute( Object, 'participants' ),
    participantId: proxyAttribute,

    rsvp: function ( rsvp ) {
        var original = this.get( 'original' );
        var recurrenceOverrides = original.get( 'recurrenceOverrides' );
        var id = this.id;
        // If this is an exception from the organizer, RSVP to just this
        // instance, otherwise RSVP to whole series
        if ( recurrenceOverrides && recurrenceOverrides[ id ] &&
                Object.keys( recurrenceOverrides[ id ] ).some(
                function ( key ) {
                    return key !== 'alerts' && key !== 'useDefaultAlerts';
                })) {
            return CalendarEvent.prototype.rsvp.call( this, rsvp );
        }
        if ( rsvp !== undefined ) {
            original.set( 'rsvp', rsvp );
        }
        return original.get( 'rsvp' );
    }.property( 'participants', 'participantId' ),

    // ---

    useDefaultAlerts: proxyOverrideAttibute( Boolean, 'useDefaultAlerts' ),
    alerts: proxyOverrideAttibute( Object, 'alerts' )
});
O.meta( CalendarEventOccurrence.prototype ).attrs =
    O.meta( CalendarEvent.prototype ).attrs;

JMAP.CalendarEventOccurrence = CalendarEventOccurrence;

}( JMAP ) );
<|endoftext|>