<commit_before>'use strict';

const fs = require('fs');
const md5 = require('md5');
const path = require('path');
const request = require('supertest');
const server = require('./server');

const fileDir = server.fileDir;
const tempDir = server.tempDir;
const uploadDir = server.uploadDir;
const clearUploadsDir = server.clearUploadsDir;

const mockFiles = ['car.png', 'tree.png', 'basketball.png'];

const mockUser = {
  firstName: 'Joe',
  lastName: 'Schmo',
  email: 'joe@mailinator.com'
};

// Reset response body.uploadDir/uploadPath for testing.
const resetBodyUploadData = (res) => {
  res.body.uploadDir = '';
  res.body.uploadPath = '';
};

const genUploadResult = (fileName, filePath) => {
  const fileStat = fs.statSync(filePath);
  const fileBuffer = fs.readFileSync(filePath);
  return {
    name: fileName,
    md5: md5(fileBuffer),
    size: fileStat.size,
    uploadDir: '',
    uploadPath: ''
  };
};

describe('Test Directory Cleaning Method', function() {
  it('emptied "uploads" directory', function(done) {
    clearUploadsDir();
    const filesFound = fs.readdirSync(uploadDir).length;
    done(filesFound ? `Directory not empty. Found ${filesFound} files.` : null);
  });
});

describe('Test Single File Upload', function() {
  const app = server.setup();

  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    const result = genUploadResult(fileName, filePath);

    it(`upload ${fileName} with POST`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });

    it(`upload ${fileName} with PUT`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });

  it('fail when no files were attached', function(done) {
    request(app)
      .post('/upload/single')
      .expect(400)
      .end(done);
  });

  it('fail when using GET', function(done) {
    request(app)
      .get('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });

  it('fail when using HEAD', function(done) {
    request(app)
      .head('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });
});

describe('Test Single File Upload w/ .mv()', function() {
  const app = server.setup();

  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    const result = genUploadResult(fileName, filePath);

    it(`upload ${fileName} with POST w/ .mv()`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });

    it(`upload ${fileName} with PUT w/ .mv()`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });
});

describe('Test Single File Upload with useTempFiles option.', function() {
  const app = server.setup({ useTempFiles: true, tempFileDir: tempDir });

  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    const result = genUploadResult(fileName, filePath);

    it(`upload ${fileName} with POST`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });

    it(`upload ${fileName} with PUT`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });

  it('fail when no files were attached', function(done) {
    request(app)
      .post('/upload/single')
      .expect(400)
      .end(done);
  });

  it('fail when using GET', function(done) {
    request(app)
      .get('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });

  it('fail when using HEAD', function(done) {
    request(app)
      .head('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });
});

describe('Test Single File Upload with useTempFiles option and empty tempFileDir.', function() {
  const app = server.setup({ useTempFiles: true, tempFileDir: '' });

  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    const result = genUploadResult(fileName, filePath);

    it(`upload ${fileName} with POST`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });
});

describe('Test Single File Upload w/ .mv() Promise', function() {
  const app = server.setup();

  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    const result = genUploadResult(fileName, filePath);

    it(`upload ${fileName} with POST w/ .mv() Promise`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single/promise')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });

    it(`upload ${fileName} with PUT w/ .mv() Promise`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single/promise')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });

  it('fail when no files were attached', function(done) {
    request(app)
      .post('/upload/single')
      .expect(400)
      .end(done);
  });

  it('fail when using GET', function(done) {
    request(app)
      .get('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });

  it('fail when using HEAD', function(done) {
    request(app)
      .head('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });
});

describe('Test Single File Upload w/ .mv() Promise and useTempFiles set to true', function() {
  const app = server.setup({ useTempFiles: true, tempFileDir: tempDir });

  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    const result = genUploadResult(fileName, filePath);

    it(`upload ${fileName} with POST w/ .mv() Promise`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single/promise')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });

    it(`upload ${fileName} with PUT w/ .mv() Promise`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single/promise')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });

  it('fail when no files were attached', function(done) {
    request(app)
      .post('/upload/single')
      .expect(400)
      .end(done);
  });

  it('fail when using GET', function(done) {
    request(app)
      .get('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });

  it('fail when using HEAD', function(done) {
    request(app)
      .head('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });
});

describe('Test Multi-File Upload', function() {
  const app = server.setup();

  it('upload multiple files with POST', function(done) {
    clearUploadsDir();
    const req = request(app).post('/upload/multiple');
    let expectedResult = [];
    let expectedResultSorted = [];
    let uploadedFilesPath = [];
    mockFiles.forEach((fileName, index) => {
      let filePath = path.join(fileDir, fileName);
      let fileStat = fs.statSync(filePath);
      uploadedFilesPath.push(path.join(uploadDir, fileName));
      expectedResult.push({
        name: fileName,
        md5: md5(fs.readFileSync(filePath)),
        size: fileStat.size,
        uploadDir: '',
        uploadPath: ''
      });
      req.attach(`testFile${index+1}`, filePath);
    });

    req
      .expect((res) => {
        res.body.forEach(fileInfo => {
          fileInfo.uploadDir = '';
          fileInfo.uploadPath = '';
          let index = mockFiles.indexOf(fileInfo.name);
          expectedResultSorted.push(expectedResult[index]);
        });
      })
      .expect(200, expectedResultSorted)
      .end((err) => {
        if (err) return done(err);
        fs.stat(uploadedFilesPath[0], (err) => {
          if (err) return done(err);
          fs.stat(uploadedFilesPath[1], function(err) {
            if (err) return done(err);
            fs.stat(uploadedFilesPath[2], done);
          });
        });
      });
  });
});

describe('Test File Array Upload', function() {
  const app = server.setup();

  it('upload array of files with POST', function(done) {
    clearUploadsDir();
    const req = request(app).post('/upload/array');
    let expectedResult = [];
    let expectedResultSorted = [];
    let uploadedFilesPath = [];
    mockFiles.forEach((fileName) => {
      let filePath = path.join(fileDir, fileName);
      let fileStat = fs.statSync(filePath);
      uploadedFilesPath.push(path.join(uploadDir, fileName));
      expectedResult.push({
        name:fileName,
        md5: md5(fs.readFileSync(filePath)),
        size: fileStat.size,
        uploadDir: '',
        uploadPath: ''
      });
      req.attach('testFiles', filePath);
    });

    req
      .expect((res)=>{
        res.body.forEach(fileInfo => {
          fileInfo.uploadDir = '';
          fileInfo.uploadPath = '';
          let index = mockFiles.indexOf(fileInfo.name);
          expectedResultSorted.push(expectedResult[index]);
        });
      })
      .expect(200, expectedResultSorted)
      .end((err) => {
        if (err) return done(err);
        uploadedFilesPath.forEach((uploadedFilePath) => {
          fs.statSync(uploadedFilePath);
        });
        done();
      });
  });
});

describe('Test Upload With Fields', function() {
  const app = server.setup();
  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    // Expected results
    const result = genUploadResult(fileName, filePath);
    result.firstName = mockUser.firstName;
    result.lastName = mockUser.lastName;
    result.email = mockUser.email;

    it(`upload ${fileName} and submit fields at the same time with POST`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single/withfields')
        .attach('testFile', filePath)
        .field('firstName', mockUser.firstName)
        .field('lastName', mockUser.lastName)
        .field('email', mockUser.email)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });

    it(`upload ${fileName} and submit fields at the same time with PUT`, function(done) {
      clearUploadsDir();
      request(app)
        .put('/upload/single/withfields')
        .attach('testFile', filePath)
        .field('firstName', mockUser.firstName)
        .field('lastName', mockUser.lastName)
        .field('email', mockUser.email)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });
});
<commit_msg>Update multipartUploads.spec.js<commit_after>'use strict';

const fs = require('fs');
const md5 = require('md5');
const path = require('path');
const request = require('supertest');
const server = require('./server');

const fileDir = server.fileDir;
const tempDir = server.tempDir;
const uploadDir = server.uploadDir;
const clearUploadsDir = server.clearUploadsDir;

const mockFiles = ['car.png', 'tree.png', 'basketball.png'];

const mockUser = {
  firstName: 'Joe',
  lastName: 'Schmo',
  email: 'joe@mailinator.com'
};

// Reset response body.uploadDir/uploadPath for testing.
const resetBodyUploadData = (res) => {
  res.body.uploadDir = '';
  res.body.uploadPath = '';
};

const genUploadResult = (fileName, filePath) => {
  const fileStat = fs.statSync(filePath);
  const fileBuffer = fs.readFileSync(filePath);
  return {
    name: fileName,
    md5: md5(fileBuffer),
    size: fileStat.size,
    uploadDir: '',
    uploadPath: ''
  };
};

describe('Test Directory Cleaning Method', function() {
  it('emptied "uploads" directory', function(done) {
    clearUploadsDir();
    const filesFound = fs.readdirSync(uploadDir).length;
    done(filesFound ? `Directory not empty. Found ${filesFound} files.` : null);
  });
});

describe('Test Single File Upload', function() {
  const app = server.setup();

  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    const result = genUploadResult(fileName, filePath);

    it(`upload ${fileName} with POST`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });

    it(`upload ${fileName} with PUT`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });

  it('fail when no files were attached', function(done) {
    request(app)
      .post('/upload/single')
      .expect(400)
      .end(done);
  });

  it('fail when using GET', function(done) {
    request(app)
      .get('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });

  it('fail when using HEAD', function(done) {
    request(app)
      .head('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });
});

describe('Test Single File Upload w/ .mv()', function() {
  const app = server.setup();

  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    const result = genUploadResult(fileName, filePath);

    it(`upload ${fileName} with POST w/ .mv()`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });

    it(`upload ${fileName} with PUT w/ .mv()`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });
});

describe('Test Single File Upload with useTempFiles option.', function() {
  const app = server.setup({ useTempFiles: true, tempFileDir: tempDir });

  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    const result = genUploadResult(fileName, filePath);

    it(`upload ${fileName} with POST`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });

    it(`upload ${fileName} with PUT`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });

  it('fail when no files were attached', function(done) {
    request(app)
      .post('/upload/single')
      .expect(400)
      .end(done);
  });

  it('fail when using GET', function(done) {
    request(app)
      .get('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });

  it('fail when using HEAD', function(done) {
    request(app)
      .head('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });
});

describe('Test Single File Upload with useTempFiles option and empty tempFileDir.', function() {
  const app = server.setup({ useTempFiles: true, tempFileDir: '' });

  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    const result = genUploadResult(fileName, filePath);

    it(`upload ${fileName} with POST`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });
});

describe('Test Single File Upload w/ .mv() Promise', function() {
  const app = server.setup();

  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    const result = genUploadResult(fileName, filePath);

    it(`upload ${fileName} with POST w/ .mv() Promise`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single/promise')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });

    it(`upload ${fileName} with PUT w/ .mv() Promise`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single/promise')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });

  it('fail when no files were attached', function(done) {
    request(app)
      .post('/upload/single')
      .expect(400)
      .end(done);
  });

  it('fail when using GET', function(done) {
    request(app)
      .get('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });

  it('fail when using HEAD', function(done) {
    request(app)
      .head('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });
});

describe('Test Single File Upload w/ .mv() Promise and useTempFiles set to true', function() {
  const app = server.setup({ useTempFiles: true, tempFileDir: tempDir });

  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    const result = genUploadResult(fileName, filePath);

    it(`upload ${fileName} with POST w/ .mv() Promise`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single/promise')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });

    it(`upload ${fileName} with PUT w/ .mv() Promise`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single/promise')
        .attach('testFile', filePath)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });

  it('fail when no files were attached', function(done) {
    request(app)
      .post('/upload/single')
      .expect(400)
      .end(done);
  });

  it('fail when using GET', function(done) {
    request(app)
      .get('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });

  it('fail when using HEAD', function(done) {
    request(app)
      .head('/upload/single')
      .attach('testFile', path.join(fileDir, mockFiles[0]))
      .expect(400)
      .end(done);
  });
});

describe('Test Multi-File Upload', function() {
  const app = server.setup();

  it('upload multiple files with POST', function(done) {
    clearUploadsDir();
    const req = request(app).post('/upload/multiple');
    let expectedResult = [];
    let expectedResultSorted = [];
    let uploadedFilesPath = [];
    mockFiles.forEach((fileName, index) => {
      let filePath = path.join(fileDir, fileName);
      let fileStat = fs.statSync(filePath);
      uploadedFilesPath.push(path.join(uploadDir, fileName));
      expectedResult.push({
        name: fileName,
        md5: md5(fs.readFileSync(filePath)),
        size: fileStat.size,
        uploadDir: '',
        uploadPath: ''
      });
      req.attach(`testFile${index+1}`, filePath);
    });

    req
      .expect((res) => {
        res.body.forEach(fileInfo => {
          fileInfo.uploadDir = '';
          fileInfo.uploadPath = '';
          let index = mockFiles.indexOf(fileInfo.name);
          expectedResultSorted.push(expectedResult[index]);
        });
      })
      .expect(200, expectedResultSorted)
      .end((err) => {
        if (err) return done(err);
        fs.stat(uploadedFilesPath[0], (err) => {
          if (err) return done(err);
          fs.stat(uploadedFilesPath[1], function(err) {
            if (err) return done(err);
            fs.stat(uploadedFilesPath[2], done);
          });
        });
      });
  });
});

describe('Test File Array Upload', function() {
  const app = server.setup();

  it('upload array of files with POST', function(done) {
    clearUploadsDir();
    const req = request(app).post('/upload/array');
    let expectedResult = [];
    let expectedResultSorted = [];
    let uploadedFilesPath = [];
    mockFiles.forEach((fileName) => {
      let filePath = path.join(fileDir, fileName);
      let fileStat = fs.statSync(filePath);
      uploadedFilesPath.push(path.join(uploadDir, fileName));
      expectedResult.push({
        name:fileName,
        md5: md5(fs.readFileSync(filePath)),
        size: fileStat.size,
        uploadDir: '',
        uploadPath: ''
      });
      req.attach('testFiles', filePath);
    });

    req
      .expect((res)=>{
        res.body.forEach(fileInfo => {
          fileInfo.uploadDir = '';
          fileInfo.uploadPath = '';
          let index = mockFiles.indexOf(fileInfo.name);
          expectedResultSorted.push(expectedResult[index]);
        });
      })
      .expect(200, expectedResultSorted)
      .end((err) => {
        if (err) return done(err);
        uploadedFilesPath.forEach((uploadedFilePath) => {
          fs.statSync(uploadedFilePath);
        });
        done();
      });
  });
});

describe('Test Upload With Fields', function() {
  const app = server.setup();
  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);
    const uploadedFilePath = path.join(uploadDir, fileName);
    // Expected results
    const result = genUploadResult(fileName, filePath);
    result.firstName = mockUser.firstName;
    result.lastName = mockUser.lastName;
    result.email = mockUser.email;

    it(`upload ${fileName} and submit fields at the same time with POST`, function(done) {
      clearUploadsDir();
      request(app)
        .post('/upload/single/withfields')
        .attach('testFile', filePath)
        .field('firstName', mockUser.firstName)
        .field('lastName', mockUser.lastName)
        .field('email', mockUser.email)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });

    it(`upload ${fileName} and submit fields at the same time with PUT`, function(done) {
      clearUploadsDir();
      request(app)
        .put('/upload/single/withfields')
        .attach('testFile', filePath)
        .field('firstName', mockUser.firstName)
        .field('lastName', mockUser.lastName)
        .field('email', mockUser.email)
        .expect(resetBodyUploadData)
        .expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
    });
  });
});

describe('Test Aborting/Canceling during upload', function() {
  this.timeout(4000); // Set timeout for async tests.
  const uploadTimeout = 1000;

  const app = server.setup({
    useTempFiles: true,
    tempFileDir: tempDir,
    debug: true,
    uploadTimeout
  });

  clearTempDir();
  clearUploadsDir();
  mockFiles.forEach((fileName) => {
    const filePath = path.join(fileDir, fileName);

    it(`Delete temp file if ${fileName} upload was aborted`, (done) => {
      const req = request(app)
        .post('/upload/single')
        .attach('testFile', filePath)
        .on('progress', (e) => {
          const progress = (e.loaded * 100) / e.total;
          // Aborting request, use req.req since it is original superagent request.
          if (progress > 50) req.req.abort();
        })
        .end((err) => {
          if (!err) return done(`Connection hasn't been aborted!`);
          if (err.code !== 'ECONNRESET') return done(err);
          // err.code === 'ECONNRESET' that means upload has been aborted.
          // Checking temp directory after upload timeout.
          setTimeout(() => {
            fs.readdir(tempDir, (err, files) => {
              if (err) return done(err);
              return files.length ? done(`Temporary directory contains files!`) : done();
            });
          }, uploadTimeout * 2);
        });
    });
  });
});
<|endoftext|>


<commit_before>import React from 'react';
import { Button, Grid, Row, Col, FormGroup, FormControl, ControlLabel, ListGroup, ListGroupItem, Glyphicon, HelpBlock } from 'react-bootstrap';
import Utility from '../../../../shared/util/Utility';

import * as Lessons from '../../../../shared/reducers/Lessons';
import * as Security from '../../../../shared/reducers/Security';

export const Reducers = [Lessons, Security];

export class selectScreen extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleLanguageSelection = this.handleLanguageSelection.bind(this);
    this.handleStarredClick = this.handleStarredClick.bind(this);
    this.handleSpacedRepetition = this.handleSpacedRepetition.bind(this);

    this.onKeys = this.onKeys.bind(this);

  }

  componentWillMount() {
    this.props.fetchLessons(this.props.params.type)
      .catch(() => this.props.verifyUserLoggedIn());

    this.props.fetchUserStarredLessons()
      .catch(() => this.props.verifyUserLoggedIn());

    this.props.fetchaddressedQuestionsInLessons()
      .catch(() => this.props.verifyUserLoggedIn());

    if (this.props.params.type === 'kanji') {
      this.props.setQuestionLanguage('reading');
    }
  }

  componentDidMount() {
    window.addEventListener('keydown', this.onKeys);
  }

  // Triggers when we change between play types but remain in "selection" page
  componentWillReceiveProps(nextProps) {
    if (this.props.params.type !== nextProps.params.type) {
      this.props.fetchLessons(nextProps.params.type)
        .catch(() => this.props.verifyUserLoggedIn());
    }
  }

  componentWillUnmount() {
    window.removeEventListener('keydown', this.onKeys);
  }

  onKeys(event) {
    if (event.keyCode === 13) {
      this.handleSubmit(event);
    }
  }

  getPageHeader() {
    switch (this.props.params.type) {
      case 'quiz':
        return
Quiz
;
      case 'guess':
        return
Gissa ordet
;
      case 'translate':
        return
Översätt ordet
;
      case 'flashcards':
        return
Bildkort
;
      case 'kanji':
        return
Skriv Kanji
;
      case 'grammar':
        return
Böj verb
;
      default:
        throw new Error('No play type specified');
    }
  }

  getPageDescription() {
    switch (this.props.params.type) {
      case 'quiz':
        return (Sätt dina kunskaper om Japan på prov genom att välja en av 4 svarsalternativ);
      case 'guess':
        return Välj mellan 4 svarsalternativ för den korrekta översättningen.;
      case 'translate':
        return Översätt det visade ordet i fritext.;
      case 'flashcards':
        return (Träna dig själv genom att använda kort,
        med frågan på ena sidan och rätta svaret på den andra.);
      case 'kanji':
        return (Försök rita kanji-tecken med korrekta drag och i rätt ordning.);
      case 'grammar':
        return Böj det visade ordet i fritext på angiven verbform.;
      default:
        throw new Error('No play type specified');
    }
  }

  handleLanguageSelection(event) {
    switch (event.target.name) {
      case 'selectedLesson':
        this.props.setSelectedLesson(event.target.value);
        break;
      case 'questionType':
        this.props.setQuestionLanguage(event.target.value);
        break;
      case 'answerType':
        this.props.setAnswerLanguage(event.target.value);
        break;
      default:
        break;
    }
  }

  isLessonStartable() {
    if (this.props.spacedRepetition) {
      if (this.props.selectedLesson.name && this.props.addressedQuestionsInLessons) {
        return this.props.addressedQuestionsInLessons[this.props.selectedLesson.name].retention
        + this.props.addressedQuestionsInLessons[this.props.selectedLesson.name].unanswered >= 4;
      }
    }
    return true;
  }

  getButtonText() {
    if (this.isLessonStartable()) {
      return 'Starta';
    }
    return 'Ej startbar';
  }

  handleSubmit(event) {
    event.preventDefault();
    try {
      this.props.Lesson(this.props.params.type)
          .then(() => {
            this.props.setPageByName(`/play/${this.props.params.type}`);
          });
    } catch (err) {
      this.props.verifyUserLoggedIn();
    }
  }

  handleSpacedRepetition(event) {
    this.props.toggleSpacedRepetition();
  }

  handleStarredClick(lesson) {
    return this.props.starredLessons.map(userLesson => userLesson.lesson.name).includes(lesson.name) ?
      this.props.removeStarredLesson(lesson.name) :
      this.props.addStarredLesson(lesson.name);
  }

  render() {
    const options = this.props.lessons.map(lesson =>
      <Row key={lesson.name}>
        <Col
          xs={this.props.params.type === 'quiz' ? 12 : 10}
          md={this.props.params.type === 'quiz' ? 12 : 11}
          lg={this.props.params.type === 'quiz' ? 12 : 11}>
          <ListGroupItem
            key={lesson.name}
            onClick={() => this.props.setSelectedLesson(lesson)}
            value={lesson.name}
            header={lesson.name}
            bsStyle={lesson.name === this.props.selectedLesson.name ? 'info' : null}
          />
        </Col>
        {this.props.params.type === 'quiz' ?
          null
          :
          <Col xs={2} md={1} lg={1}>
            <Button
              bsStyle={this.props.starredLessons.map(userLesson => userLesson.lesson.name).includes(lesson.name) ? 'warning' : null}
              onClick={() => this.handleStarredClick(lesson)}
            >
              <Glyphicon glyph="star" />
            </Button>
          </Col>
        }
      </Row>);

    const answerLanguages = [];
    let questionLanguages = [];
    answerLanguages.push(<option key={'reading'} value={'reading'}>Japanska</option>);
    answerLanguages.push(<option key={'swedish'} value={'swedish'}>Svenska</option>);
    /* devcode: start */
    answerLanguages.push(<option key={'english'} value={'english'}>Engelska</option>);
    /* devcode: end */

    if (this.props.params.type === 'kanji') {
      questionLanguages = answerLanguages.shift();
    } else {
      questionLanguages = answerLanguages;
    }

    let languageSelection;
    if (this.props.params.type === 'quiz' || this.props.params.type === 'grammar') {
      languageSelection =
;
    } else {
      languageSelection = (
        <FormGroup>
          <Row>
            <Col xs={12} sm={6}>
              <HelpBlock>Frågespråk</HelpBlock>
              <FormControl
                componentClass="select"
                name="questionType"
                id="questionLanguageSelection"
                onChange={this.handleLanguageSelection}
                value={this.props.questionType}
                disabled={this.props.params.type === 'kanji'}
              >
                {questionLanguages}
              </FormControl>
            </Col>
            <Col xs={12} sm={6}>
              <HelpBlock>Svarspråk</HelpBlock>
              <FormControl
                componentClass="select"
                name="answerType"
                id="answerLanguageSelection"
                onChange={this.handleLanguageSelection}
                value={this.props.answerType}
              >
                {answerLanguages}
              </FormControl>

            </Col>
          </Row>
        </FormGroup>);
    }
    return (
      <Grid className="text-center">
        <Col xs={11} lg={8} lgOffset={2}>
          <form href="#" onSubmit={this.handleSubmit}>
            <ControlLabel>{this.getPageHeader()}</ControlLabel>

            <FormGroup>
              <ControlLabel>{this.getPageDescription()}</ControlLabel>
            </FormGroup>

            <FormGroup>
              <HelpBlock>Välj ordsamlingar i listan nedan</HelpBlock>
              <ListGroup>
                {options}
              </ListGroup>
              {languageSelection}
            </FormGroup>
            <FormGroup>
              <FormControl
                type="hidden"
                onKeyPress={this.handleKeyPress}
              />
              <Button type="submit" bsStyle="primary" disabled={!this.isLessonStartable()}>{this.getButtonText()}</Button>
              <ControlLabel> Spaced Repetition: <input name="spacedRepetition" type="checkbox" defaultChecked={this.props.spacedRepetition} onClick={this.handleSpacedRepetition} /></ControlLabel>
            </FormGroup>

          </form>
        </Col>
      </Grid>
    );
  }
}

selectScreen.defaultProps = Utility.reduxEnabledDefaultProps({

}, Reducers);

selectScreen.propTypes = Utility.reduxEnabledPropTypes({

}, Reducers);

export default Utility.superConnect(this, Reducers)(selectScreen);
<commit_msg>now shows how many questions are available<commit_after>import React from 'react';
import { Button, Grid, Row, Col, FormGroup, FormControl, ControlLabel, ListGroup, ListGroupItem, Glyphicon, HelpBlock } from 'react-bootstrap';
import Utility from '../../../../shared/util/Utility';

import * as Lessons from '../../../../shared/reducers/Lessons';
import * as Security from '../../../../shared/reducers/Security';

export const Reducers = [Lessons, Security];

export class selectScreen extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleLanguageSelection = this.handleLanguageSelection.bind(this);
    this.handleStarredClick = this.handleStarredClick.bind(this);
    this.handleSpacedRepetition = this.handleSpacedRepetition.bind(this);

    this.onKeys = this.onKeys.bind(this);

  }

  componentWillMount() {
    this.props.fetchLessons(this.props.params.type)
      .catch(() => this.props.verifyUserLoggedIn());

    this.props.fetchUserStarredLessons()
      .catch(() => this.props.verifyUserLoggedIn());

    this.props.fetchaddressedQuestionsInLessons()
      .catch(() => this.props.verifyUserLoggedIn());

    if (this.props.params.type === 'kanji') {
      this.props.setQuestionLanguage('reading');
    }
  }

  componentDidMount() {
    window.addEventListener('keydown', this.onKeys);
  }

  // Triggers when we change between play types but remain in "selection" page
  componentWillReceiveProps(nextProps) {
    if (this.props.params.type !== nextProps.params.type) {
      this.props.fetchLessons(nextProps.params.type)
        .catch(() => this.props.verifyUserLoggedIn());
    }
  }

  componentWillUnmount() {
    window.removeEventListener('keydown', this.onKeys);
  }

  onKeys(event) {
    if (event.keyCode === 13) {
      this.handleSubmit(event);
    }
  }

  getPageHeader() {
    switch (this.props.params.type) {
      case 'quiz':
        return
Quiz
;
      case 'guess':
        return
Gissa ordet
;
      case 'translate':
        return
Översätt ordet
;
      case 'flashcards':
        return
Bildkort
;
      case 'kanji':
        return
Skriv Kanji
;
      case 'grammar':
        return
Böj verb
;
      default:
        throw new Error('No play type specified');
    }
  }

  getPageDescription() {
    switch (this.props.params.type) {
      case 'quiz':
        return (Sätt dina kunskaper om Japan på prov genom att välja en av 4 svarsalternativ);
      case 'guess':
        return Välj mellan 4 svarsalternativ för den korrekta översättningen.;
      case 'translate':
        return Översätt det visade ordet i fritext.;
      case 'flashcards':
        return (Träna dig själv genom att använda kort,
        med frågan på ena sidan och rätta svaret på den andra.);
      case 'kanji':
        return (Försök rita kanji-tecken med korrekta drag och i rätt ordning.);
      case 'grammar':
        return Böj det visade ordet i fritext på angiven verbform.;
      default:
        throw new Error('No play type specified');
    }
  }

  handleLanguageSelection(event) {
    switch (event.target.name) {
      case 'selectedLesson':
        this.props.setSelectedLesson(event.target.value);
        break;
      case 'questionType':
        this.props.setQuestionLanguage(event.target.value);
        break;
      case 'answerType':
        this.props.setAnswerLanguage(event.target.value);
        break;
      default:
        break;
    }
  }

  isLessonStartable() {
    if (this.props.spacedRepetition) {
      if (this.props.selectedLesson.name && this.props.addressedQuestionsInLessons) {
        return this.props.addressedQuestionsInLessons[this.props.selectedLesson.name].retention
        + this.props.addressedQuestionsInLessons[this.props.selectedLesson.name].unanswered >= 4;
      }
    }
    return true;
  }

  getButtonText() {
    if (this.isLessonStartable()) {
      return 'Starta';
    }
    return 'Ej startbar';
  }

  handleSubmit(event) {
    event.preventDefault();
    try {
      this.props.Lesson(this.props.params.type)
          .then(() => {
            this.props.setPageByName(`/play/${this.props.params.type}`);
          });
    } catch (err) {
      this.props.verifyUserLoggedIn();
    }
  }

  handleSpacedRepetition(event) {
    this.props.toggleSpacedRepetition();
  }

  handleStarredClick(lesson) {
    return this.props.starredLessons.map(userLesson => userLesson.lesson.name).includes(lesson.name) ?
      this.props.removeStarredLesson(lesson.name) :
      this.props.addStarredLesson(lesson.name);
  }

  getNumberOfQuestions(lesson) {
    if (this.props.spacedRepetition && this.props.addressedQuestionsInLessons) {
      return this.props.addressedQuestionsInLessons[lesson.name].retention +
      this.props.addressedQuestionsInLessons[lesson.name].unanswered + 0;
    } else if (this.props.addressedQuestionsInLessons) {
      return this.props.addressedQuestionsInLessons[lesson.name].all;
    }

    return lesson.name;

  }

  render() {
    const options = this.props.lessons.map(lesson =>
      <Row key={lesson.name}>
        <Col
          xs={this.props.params.type === 'quiz' ? 12 : 10}
          md={this.props.params.type === 'quiz' ? 12 : 11}
          lg={this.props.params.type === 'quiz' ? 12 : 11}>
          <ListGroupItem
            key={lesson.name}
            onClick={() => this.props.setSelectedLesson(lesson)}
            value={lesson.name}
            header={`${lesson.name} - ${this.getNumberOfQuestions(lesson)} frågor ${this.props.spacedRepetition ? 'kvar' : ''}`}
            bsStyle={lesson.name === this.props.selectedLesson.name ? 'info' : null}
          />
        </Col>
        {this.props.params.type === 'quiz' ?
          null
          :
          <Col xs={2} md={1} lg={1}>
            <Button
              bsStyle={this.props.starredLessons.map(userLesson => userLesson.lesson.name).includes(lesson.name) ? 'warning' : null}
              onClick={() => this.handleStarredClick(lesson)}
            >
              <Glyphicon glyph="star" />
            </Button>
          </Col>
        }
      </Row>);

    const answerLanguages = [];
    let questionLanguages = [];
    answerLanguages.push(<option key={'reading'} value={'reading'}>Japanska</option>);
    answerLanguages.push(<option key={'swedish'} value={'swedish'}>Svenska</option>);
    /* devcode: start */
    answerLanguages.push(<option key={'english'} value={'english'}>Engelska</option>);
    /* devcode: end */

    if (this.props.params.type === 'kanji') {
      questionLanguages = answerLanguages.shift();
    } else {
      questionLanguages = answerLanguages;
    }

    let languageSelection;
    if (this.props.params.type === 'quiz' || this.props.params.type === 'grammar') {
      languageSelection =
;
    } else {
      languageSelection = (
        <FormGroup>
          <Row>
            <Col xs={12} sm={6}>
              <HelpBlock>Frågespråk</HelpBlock>
              <FormControl
                componentClass="select"
                name="questionType"
                id="questionLanguageSelection"
                onChange={this.handleLanguageSelection}
                value={this.props.questionType}
                disabled={this.props.params.type === 'kanji'}
              >
                {questionLanguages}
              </FormControl>
            </Col>
            <Col xs={12} sm={6}>
              <HelpBlock>Svarspråk</HelpBlock>
              <FormControl
                componentClass="select"
                name="answerType"
                id="answerLanguageSelection"
                onChange={this.handleLanguageSelection}
                value={this.props.answerType}
              >
                {answerLanguages}
              </FormControl>

            </Col>
          </Row>
        </FormGroup>);
    }
    return (
      <Grid className="text-center">
        <Col xs={11} lg={8} lgOffset={2}>
          <form href="#" onSubmit={this.handleSubmit}>
            <ControlLabel>{this.getPageHeader()}</ControlLabel>

            <FormGroup>
              <ControlLabel>{this.getPageDescription()}</ControlLabel>
            </FormGroup>

            <FormGroup>
              <HelpBlock>Välj ordsamlingar i listan nedan</HelpBlock>
              <ListGroup>
                {options}
              </ListGroup>
              {languageSelection}
            </FormGroup>
            <FormGroup>
              <FormControl
                type="hidden"
                onKeyPress={this.handleKeyPress}
              />
              <Button type="submit" bsStyle="primary" disabled={!this.isLessonStartable()}>{this.getButtonText()}</Button>
              <ControlLabel> Spaced Repetition: <input name="spacedRepetition" type="checkbox" defaultChecked={this.props.spacedRepetition} onClick={this.handleSpacedRepetition} /></ControlLabel>
            </FormGroup>

          </form>
        </Col>
      </Grid>
    );
  }
}

selectScreen.defaultProps = Utility.reduxEnabledDefaultProps({

}, Reducers);

selectScreen.propTypes = Utility.reduxEnabledPropTypes({

}, Reducers);

export default Utility.superConnect(this, Reducers)(selectScreen);
<|endoftext|>


<commit_before>
import logger from './utils/logger';
import { join } from 'path';
import { requestByName, getNames } from './utils/socketsHelper';
import sliceFile from 'slice-file';
import globby from 'globby';
import ensureSelected from './utils/ensureSelected';
import workspace from './utils/workspace';

const log = async (options) => {
	workspace.set(options);

	const { name, line, category, follow } = options;

	const appName = await ensureSelected({
		value: name,
		message: 'Please select the target app.',
		errorMessage: 'No process is running.',
		getChoices: getNames,
	});

	const info = await requestByName(appName, 'info');
	if (!info) {
		throw new Error(`"${appName}" is NOT found.`);
	}

	const { logsDir } = info;

	let appCategory = await ensureSelected({
		value: category,
		message: 'Please select a log file.',
		errorMessage: 'Log file NOT found.',
		getChoices: () => globby('*.log', { cwd: logsDir }),
	});

	if (!appCategory.endsWith('.log')) { appCategory += '.log'; }

	const logFile = join(logsDir, appCategory);
	const sf = sliceFile(logFile);
	const mode = follow ? 'follow' : 'slice';

	sf.on('error', (err) => {
		if (err.code !== 'ENOENT') { throw err; }
		logger.warn('Log file NOT found.');
	});
	sf[mode](-line).pipe(process.stdout);
};

export default log;
<commit_msg>fixed log bug<commit_after>
import logger from './utils/logger';
import { join } from 'path';
import { requestByName, getNames } from './utils/socketsHelper';
import sliceFile from 'slice-file';
import globby from 'globby';
import ensureSelected from './utils/ensureSelected';
import workspace from './utils/workspace';

const log = async (options) => {
	workspace.set(options);

	const { name, line, category, follow } = options;

	const appName = await ensureSelected({
		value: name,
		message: 'Please select the target app.',
		errorMessage: 'No process is running.',
		getChoices: getNames,
	});

	const info = await requestByName(appName, 'info');
	if (!info) {
		throw new Error(`"${appName}" is NOT found.`);
	}

	const { logsDir } = info.data;

	let appCategory = await ensureSelected({
		value: category,
		message: 'Please select a log file.',
		errorMessage: 'Log file NOT found.',
		getChoices: () => globby('*.log', { cwd: logsDir }),
	});

	if (!appCategory.endsWith('.log')) { appCategory += '.log'; }

	const logFile = join(logsDir, appCategory);
	const sf = sliceFile(logFile);
	const mode = follow ? 'follow' : 'slice';

	sf.on('error', (err) => {
		if (err.code !== 'ENOENT') { throw err; }
		logger.warn('Log file NOT found.');
	});
	sf[mode](-line).pipe(process.stdout);
};

export default log;
<|endoftext|>


<commit_before>import React from 'react';
import { storiesOf } from '@storybook/react';
import centered from '@storybook/addon-centered';
import { List } from './ui';
import defaultStyles from '../src/styles';
import { AwesomeButtonSocial } from '../src/index';

storiesOf('AwesomeButtonShare', module)
  .addDecorator(centered)
  .add('Icons', () => (
    <List>
      <AwesomeButtonSocial
        size="icon"
        type="facebook"
        cssModule={defaultStyles}
        url="https://facebook.com/caferati.me"
      />
      <AwesomeButtonSocial
        size="icon"
        type="pinterest"
        cssModule={defaultStyles}
        url="https://facebook.com/caferati.me"
      />
      <AwesomeButtonSocial
        size="icon"
        type="twitter"
        cssModule={defaultStyles}
        url="https://facebook.com/caferati.me"
      />
      <AwesomeButtonSocial
        size="icon"
        type="linkedin"
        cssModule={defaultStyles}
        url="https://facebook.com/caferati.me"
      />
    </List>
  ))
  .add('Facebook', () => (
    <AwesomeButtonSocial
      type="facebook"
      cssModule={defaultStyles}
      url="https://caferati.me"
    >
      Facebook
    </AwesomeButtonSocial>
  ))
  .add('Pinterest', () => (
    <AwesomeButtonSocial
      type="pinterest"
      cssModule={defaultStyles}
      url="https://caferati.me"
    >
      Pinterest
    </AwesomeButtonSocial>
  ))
  .add('Linkedin', () => (
    <AwesomeButtonSocial
      type="linkedin"
      cssModule={defaultStyles}
      url="https://caferati.me"
    >
      Linkedin
    </AwesomeButtonSocial>
  ))
  .add('Google Plus', () => (
    <AwesomeButtonSocial
      type="gplus"
      cssModule={defaultStyles}
      url="https://caferati.me"
    >
      Google Plus
    </AwesomeButtonSocial>
  ))
  .add('Reddit', () => (
    <AwesomeButtonSocial
      type="reddit"
      cssModule={defaultStyles}
      url="https://caferati.me"
    >
      Reddit
    </AwesomeButtonSocial>
  ))
  .add('Messenger', () => (
    <AwesomeButtonSocial
      type="messenger"
      cssModule={defaultStyles}
      user="caferati.me"
    >
      Messenger
    </AwesomeButtonSocial>
  ))
  .add('Whatsapp', () => (
    <AwesomeButtonSocial
      type="whatsapp"
      cssModule={defaultStyles}
      phone="447392921580"
    >
      Whatsapp
    </AwesomeButtonSocial>
  ))
  .add('Github', () => (
    <AwesomeButtonSocial
      type="github"
      cssModule={defaultStyles}
      target="_blank"
      href="https://github.com/rcaferati"
    >
      Github
    </AwesomeButtonSocial>
  ))
  .add('Youtube', () => (
    <AwesomeButtonSocial
      type="youtube"
      cssModule={defaultStyles}
      target="_blank"
      href="https://youtube.com/"
    >
      Github
    </AwesomeButtonSocial>
  ))
  .add('Instagram', () => (
    <AwesomeButtonSocial
      type="instagram"
      cssModule={defaultStyles}
      target="_blank"
      href="https://instagram.com/rcaferati"
    >
      Instagram
    </AwesomeButtonSocial>
  ))
  .add('Twitter', () => (
    <AwesomeButtonSocial
      type="twitter"
      cssModule={defaultStyles}
      url="https://caferati.me"
    >
      Twitter
    </AwesomeButtonSocial>
  ));
<commit_msg>fix story theme title<commit_after>import React from 'react';
import { storiesOf } from '@storybook/react';
import centered from '@storybook/addon-centered';
import { List } from './ui';
import defaultStyles from '../src/styles';
import { AwesomeButtonSocial } from '../src/index';

storiesOf('AwesomeButtonShare', module)
  .addDecorator(centered)
  .add('Icons', () => (
    <List>
      <AwesomeButtonSocial
        size="icon"
        type="facebook"
        cssModule={defaultStyles}
        url="https://facebook.com/caferati.me"
      />
      <AwesomeButtonSocial
        size="icon"
        type="pinterest"
        cssModule={defaultStyles}
        url="https://facebook.com/caferati.me"
      />
      <AwesomeButtonSocial
        size="icon"
        type="twitter"
        cssModule={defaultStyles}
        url="https://facebook.com/caferati.me"
      />
      <AwesomeButtonSocial
        size="icon"
        type="linkedin"
        cssModule={defaultStyles}
        url="https://facebook.com/caferati.me"
      />
    </List>
  ))
  .add('Facebook', () => (
    <AwesomeButtonSocial
      type="facebook"
      cssModule={defaultStyles}
      url="https://caferati.me"
    >
      Facebook
    </AwesomeButtonSocial>
  ))
  .add('Pinterest', () => (
    <AwesomeButtonSocial
      type="pinterest"
      cssModule={defaultStyles}
      url="https://caferati.me"
    >
      Pinterest
    </AwesomeButtonSocial>
  ))
  .add('Linkedin', () => (
    <AwesomeButtonSocial
      type="linkedin"
      cssModule={defaultStyles}
      url="https://caferati.me"
    >
      Linkedin
    </AwesomeButtonSocial>
  ))
  .add('Google Plus', () => (
    <AwesomeButtonSocial
      type="gplus"
      cssModule={defaultStyles}
      url="https://caferati.me"
    >
      Google Plus
    </AwesomeButtonSocial>
  ))
  .add('Reddit', () => (
    <AwesomeButtonSocial
      type="reddit"
      cssModule={defaultStyles}
      url="https://caferati.me"
    >
      Reddit
    </AwesomeButtonSocial>
  ))
  .add('Messenger', () => (
    <AwesomeButtonSocial
      type="messenger"
      cssModule={defaultStyles}
      user="caferati.me"
    >
      Messenger
    </AwesomeButtonSocial>
  ))
  .add('Whatsapp', () => (
    <AwesomeButtonSocial
      type="whatsapp"
      cssModule={defaultStyles}
      phone="447392921580"
    >
      Whatsapp
    </AwesomeButtonSocial>
  ))
  .add('Github', () => (
    <AwesomeButtonSocial
      type="github"
      cssModule={defaultStyles}
      target="_blank"
      href="https://github.com/rcaferati"
    >
      Github
    </AwesomeButtonSocial>
  ))
  .add('Youtube', () => (
    <AwesomeButtonSocial
      type="youtube"
      cssModule={defaultStyles}
      target="_blank"
      href="https://youtube.com/"
    >
      Youtube
    </AwesomeButtonSocial>
  ))
  .add('Instagram', () => (
    <AwesomeButtonSocial
      type="instagram"
      cssModule={defaultStyles}
      target="_blank"
      href="https://instagram.com/rcaferati"
    >
      Instagram
    </AwesomeButtonSocial>
  ))
  .add('Twitter', () => (
    <AwesomeButtonSocial
      type="twitter"
      cssModule={defaultStyles}
      url="https://caferati.me"
    >
      Twitter
    </AwesomeButtonSocial>
  ));
<|endoftext|>


<commit_before>function log() {
    if (window.html2canvas.logging && window.console && window.console.log) {
        window.console.log.apply(window.console, [(Date.now() - window.html2canvas.start) + "ms", "html2canvas:"].concat([].slice.call(arguments, 0)));
    }
}
<commit_msg>Fix logging in IE9<commit_after>function log() {
    if (window.html2canvas.logging && window.console && window.console.log) {
        Function.prototype.bind.call(window.console.log, (window.console)).apply(window.console, [(Date.now() - window.html2canvas.start) + "ms", "html2canvas:"].concat([].slice.call(arguments, 0)));
    }
}
<|endoftext|>


<commit_before>import chalk from 'chalk';

let _bundleProgressBar;

let _printNewLineBeforeNextLog = false;
let _isLastLineNewLine = false;
function _updateIsLastLineNewLine(args) {
  if (args.length === 0) {
    _isLastLineNewLine = true;
  } else {
    let lastArg = args[args.length - 1];
    if (typeof lastArg === 'string' && (lastArg === '' || lastArg.match(/[\r\n]$/))) {
      _isLastLineNewLine = true;
    } else {
      _isLastLineNewLine = false;
    }
  }
}

function _maybePrintNewLine() {
  if (_printNewLineBeforeNextLog) {
    _printNewLineBeforeNextLog = false;
    console.log();
  }
}

function consoleLog(...args) {
  _maybePrintNewLine();
  _updateIsLastLineNewLine(args);

  console.log(...args);
}

function consoleWarn(...args) {
  _maybePrintNewLine();
  _updateIsLastLineNewLine(args);

  console.warn(...args);
}

function consoleError(...args) {
  _maybePrintNewLine();
  _updateIsLastLineNewLine(args);

  console.error(...args);
}

function respectProgressBars(commitLogs) {
  if (_bundleProgressBar) {
    _bundleProgressBar.terminate();
    _bundleProgressBar.lastDraw = '';
    commitLogs();
    _bundleProgressBar.render();
  } else {
    commitLogs();
  }
}

function getPrefix(chalkColor) {
  return chalkColor('[') + chalk.gray('exp') + chalkColor(']');
}

function withPrefixAndTextColor(args, chalkColor = chalk.gray) {
  return [getPrefix(chalkColor), ...args.map(arg => chalkColor(arg))];
}

function withPrefix(args, chalkColor = chalk.gray) {
  return [getPrefix(chalkColor), ...args];
}

function log(...args) {
  if (log.config.raw) {
    return;
  }

  respectProgressBars(() => {
    consoleLog(...withPrefix(args));
  });
}

log.nested = function(message) {
  respectProgressBars(() => {
    consoleLog(message);
  });
};

log.newLine = function newLine() {
  respectProgressBars(() => {
    consoleLog();
  });
};

log.addNewLineIfNone = function addNewLineIfNone() {
  if (!_isLastLineNewLine && !_printNewLineBeforeNextLog) {
    log.newLine();
  }
};

log.printNewLineBeforeNextLog = function printNewLineBeforeNextLog() {
  _printNewLineBeforeNextLog = true;
};

log.setBundleProgressBar = function setBundleProgressBar(bar) {
  _bundleProgressBar = bar;
};

log.error = function error(...args) {
  if (log.config.raw) {
    return;
  }

  respectProgressBars(() => {
    consoleError(...withPrefixAndTextColor(args, chalk.red));
  });
};

log.nestedError = function(message) {
  respectProgressBars(() => {
    consoleError(chalk.red(message));
  });
};

log.warn = function warn(...args) {
  if (log.config.raw) {
    return;
  }

  respectProgressBars(() => {
    consoleWarn(...withPrefixAndTextColor(args, chalk.yellow));
  });
};

log.nestedWarn = function(message) {
  respectProgressBars(() => {
    consoleWarn(chalk.yellow(message));
  });
};

log.gray = function(...args) {
  if (log.config.raw) {
    return;
  }

  respectProgressBars(() => {
    consoleLog(...withPrefixAndTextColor(args));
  });
};

log.raw = function(...args) {
  if (!log.config.raw) {
    return;
  }

  respectProgressBars(() => {
    consoleLog(...args);
  });
};

log.chalk = chalk;

log.config = {
  raw: false,
};

export default log;
<commit_msg>Add timestamps to log prefix<commit_after>import chalk from 'chalk';

const maxTimestampLength = new Date('12-31-1970 23:59:59').toLocaleTimeString().length;

let _bundleProgressBar;

let _printNewLineBeforeNextLog = false;
let _isLastLineNewLine = false;
function _updateIsLastLineNewLine(args) {
  if (args.length === 0) {
    _isLastLineNewLine = true;
  } else {
    let lastArg = args[args.length - 1];
    if (typeof lastArg === 'string' && (lastArg === '' || lastArg.match(/[\r\n]$/))) {
      _isLastLineNewLine = true;
    } else {
      _isLastLineNewLine = false;
    }
  }
}

function _maybePrintNewLine() {
  if (_printNewLineBeforeNextLog) {
    _printNewLineBeforeNextLog = false;
    console.log();
  }
}

function consoleLog(...args) {
  _maybePrintNewLine();
  _updateIsLastLineNewLine(args);

  console.log(...args);
}

function consoleWarn(...args) {
  _maybePrintNewLine();
  _updateIsLastLineNewLine(args);

  console.warn(...args);
}

function consoleError(...args) {
  _maybePrintNewLine();
  _updateIsLastLineNewLine(args);

  console.error(...args);
}

function respectProgressBars(commitLogs) {
  if (_bundleProgressBar) {
    _bundleProgressBar.terminate();
    _bundleProgressBar.lastDraw = '';
    commitLogs();
    _bundleProgressBar.render();
  } else {
    commitLogs();
  }
}

function getPrefix(chalkColor) {
  const timestamp = new Date().toLocaleTimeString().padStart(maxTimestampLength);
  const leftBracket = chalkColor('[');
  const rightBracket = chalkColor(']');
  return (
    leftBracket +
    chalk.gray('exp') +
    rightBracket +
    ' ' +
    leftBracket +
    chalk.gray(timestamp) +
    rightBracket
  );
}

function withPrefixAndTextColor(args, chalkColor = chalk.gray) {
  return [getPrefix(chalkColor), ...args.map(arg => chalkColor(arg))];
}

function withPrefix(args, chalkColor = chalk.gray) {
  return [getPrefix(chalkColor), ...args];
}

function log(...args) {
  if (log.config.raw) {
    return;
  }

  respectProgressBars(() => {
    consoleLog(...withPrefix(args));
  });
}

log.nested = function(message) {
  respectProgressBars(() => {
    consoleLog(message);
  });
};

log.newLine = function newLine() {
  respectProgressBars(() => {
    consoleLog();
  });
};

log.addNewLineIfNone = function addNewLineIfNone() {
  if (!_isLastLineNewLine && !_printNewLineBeforeNextLog) {
    log.newLine();
  }
};

log.printNewLineBeforeNextLog = function printNewLineBeforeNextLog() {
  _printNewLineBeforeNextLog = true;
};

log.setBundleProgressBar = function setBundleProgressBar(bar) {
  _bundleProgressBar = bar;
};

log.error = function error(...args) {
  if (log.config.raw) {
    return;
  }

  respectProgressBars(() => {
    consoleError(...withPrefixAndTextColor(args, chalk.red));
  });
};

log.nestedError = function(message) {
  respectProgressBars(() => {
    consoleError(chalk.red(message));
  });
};

log.warn = function warn(...args) {
  if (log.config.raw) {
    return;
  }

  respectProgressBars(() => {
    consoleWarn(...withPrefixAndTextColor(args, chalk.yellow));
  });
};

log.nestedWarn = function(message) {
  respectProgressBars(() => {
    consoleWarn(chalk.yellow(message));
  });
};

log.gray = function(...args) {
  if (log.config.raw) {
    return;
  }

  respectProgressBars(() => {
    consoleLog(...withPrefixAndTextColor(args));
  });
};

log.raw = function(...args) {
  if (!log.config.raw) {
    return;
  }

  respectProgressBars(() => {
    consoleLog(...args);
  });
};

log.chalk = chalk;

log.config = {
  raw: false,
};

export default log;
<|endoftext|>


<commit_before>(function( window, document, undefined ) {
  'use strict';

  var PI2 = 2 * Math.PI;

  var canvas, context;

  // Formations coordinates array.
  var formations = [];
  var formation = [];

  var config = {
    // Unit count.
    count: 10,
    spacing: {
      rank: 10,
      file: 20
    }
  };

  /*
    Three states for drawing a formation:

             <--  1. RANK  -->       ^
      ^      [] [] [] [] [] []       |
      |      [] [] [] [] [] []       |
    2. FILE  [] [] [] [] [] []       |
      |      [] [] [] [] [] []       |
      v      [] [] [] [] [] []  3. DIRECTION

      A rank is horizontal and a file is vertical. In the above diagram,
      the formation is 5 ranks deep and 6 files wide.
   */

  var State = {
    RANK: 0,
    FILE: 1,
    DIRECTION: 2
  };

  var state = State.RANK;

  var mouse = {
    x: 0,
    y: 0,

    // Initial points.
    xi: 0,
    yi: 0,

    down: false
  };

  function Formation( x0, y0, x1, y1, x2, y2 ) {
    this.x0 = x0;
    this.y0 = y0;
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;

    // First edge (width).
    var dx0 = x1 - x0,
        dy0 = y1 - y0;

    this.angle = Math.atan2( -dy0, dx0 );
    this.width = Math.sqrt( dx0 * dx0 + dy0 * dy0 );

    var dx1 = x2 - x1,
        dy1 = y2 - y1;

    var cos, sin;
    var rx, ry;
    if ( this.angle ) {
      cos = Math.cos( this.angle );
      sin = Math.sin( this.angle );

      rx = cos * dx1 - sin * dy1;
      ry = sin * dx1 + cos * dy1;

      dx1 = rx;
      dy1 = ry;
    }

    this.height = dy1;

    Object.freeze( this );
  }

  Formation.prototype.toWorld = function( x, y ) {
    var cos, sin;
    var rx, ry;

    if ( this.angle ) {
      cos = Math.cos( -this.angle );
      sin = Math.sin( -this.angle );

      rx = cos * x - sin * y;
      ry = sin * x + cos * y;

      x = rx;
      y = ry;
    }

    return {
      x: x + this.x,
      y: y + this.y
    };
  };

  Formation.prototype.toLocal = function( x, y ) {
    x -= this.x;
    y -= this.y;

    var cos, sin;
    var rx, ry;

    if ( this.angle ) {
      cos = Math.cos( this.angle );
      sin = Math.sin( this.angle );

      rx = cos * x - sin * y;
      ry = sin * x + cos * y;

      x = rx;
      y = ry;
    }

    return {
      x: x,
      y: y
    };
  };

  function drawRectFromPoints( ctx, x0, y0, x1, y1, x2, y2 ) {
    // First edge (width).
    var dx0 = x1 - x0,
        dy0 = y1 - y0;

    var angle = Math.atan2( -dy0, dx0 );
    var width = Math.sqrt( dx0 * dx0 + dy0 * dy0 );

    // Second edge (height).
    var dx1 = x2 - x1,
        dy1 = y2 - y1;

    var cos, sin;
    var rx, ry;
    if ( angle ) {
      cos = Math.cos( angle );
      sin = Math.sin( angle );

      rx = cos * dx1 - sin * dy1;
      ry = sin * dx1 + cos * dy1;

      dx1 = rx;
      dy1 = ry;
    }

    ctx.save();

    ctx.translate( x0, y0 );
    ctx.rotate( -angle );

    ctx.beginPath();
    ctx.rect( 0, 0, width, dy1 );

    ctx.restore();
  }

  function draw( ctx ) {
    ctx.clearRect( 0, 0, ctx.canvas.width, ctx.canvas.height );

    ctx.lineWidth = 1;
    ctx.strokeStyle = '#fff';
    ctx.fillStyle = '#fff';
    ctx.font = '16pt "Helvetica Neue", Helvetica, Arial, sans-serif';

    // Mouse.
    ctx.beginPath();
    ctx.arc( mouse.x, mouse.y, 10, 0, PI2 );
    ctx.stroke();

    // Formations.
    formations.forEach(function( formation ) {
      var x0 = formation[0][0],
          y0 = formation[0][1],
          x1 = formation[1][0],
          y1 = formation[1][1],
          x2 = formation[2][0],
          y2 = formation[2][1];

      drawRectFromPoints( ctx, x0, y0, x1, y1, x2, y2 );
      ctx.stroke();
    });

    var x0, y0,
        x1, y1,
        x2, y2;
    if ( formation.length ) {
      x0 = formation[0][0];
      y0 = formation[0][1];
      x1 = formation[1][0];
      y1 = formation[1][1];

      if ( formation.length > 2 ) {
        x2 = formation[2][0];
        y2 = formation[2][1];
      }

      var dx = x1 - x0,
          dy = y1 - y0;

      var angle = Math.atan2( -dy, dx );
      ctx.fillText( Math.round( angle * 180 / Math.PI ), 300, 40 );
    }

    if ( mouse.down && state === State.RANK ) {
      ctx.beginPath();
      ctx.moveTo( mouse.xi, mouse.yi );
      ctx.lineTo( mouse.x, mouse.y );
      ctx.stroke();
    } else if ( state === State.FILE ) {
      drawRectFromPoints( ctx, x0, y0, x1, y1, mouse.x, mouse.y );
      ctx.stroke();
    } else if ( state === State.DIRECTION ) {
      drawRectFromPoints( ctx, x0, y0, x1, y1, x2, y2 );
      ctx.moveTo( x0, y0 );
      ctx.lineTo( mouse.x, mouse.y );
      ctx.moveTo( x1, y1 );
      ctx.lineTo( mouse.x, mouse.y );
      ctx.stroke();
    }
    ctx.fillText( 'state: ' + state, 32, 32 );
    ctx.fillText( config.count, 32, 72 );
  }

  (function init() {
    canvas  = document.createElement( 'canvas' );
    context = canvas.getContext( '2d' );

    document.body.appendChild( canvas );

    canvas.width  = window.innerWidth;
    canvas.height = window.innerHeight;

    function mousePosition( event ) {
      mouse.x = event.pageX - canvas.offsetLeft;
      mouse.y = event.pageY - canvas.offsetTop;
    }

    window.addEventListener( 'mousedown', function( event ) {
      mousePosition( event );
      mouse.xi = mouse.x;
      mouse.yi = mouse.y;

      mouse.down = true;

      if ( state === State.DIRECTION ) {
        formations.push( formation );
        formation = [];
        state = State.RANK;
      }
    });

    window.addEventListener( 'mousemove', function( event ) {
      mousePosition( event );
      draw( context );
    });

    window.addEventListener( 'mouseup', function() {
      mousePosition( event );
      mouse.down = false;

      if ( state === State.RANK ) {
        var dx = mouse.x - mouse.xi,
            dy = mouse.y - mouse.yi;

        if ( !dx && !dy ) {
          return;
        }

        formation = [
          [ mouse.xi, mouse.yi ],
          [ mouse.x, mouse.y ]
        ];

        state = State.FILE;
      } else if ( state === State.FILE ) {
        formation[2] = [ mouse.x, mouse.y ];
        state = State.DIRECTION;
      }
    });

    document.addEventListener( 'keydown', function( event ) {
      // Up arrow.
      if ( event.which === 38 ) {
        config.count++;
      }

      // Down arrow.
      if ( event.which === 40 ) {
        config.count = Math.max( config.count - 1, 0 );
      }

      // ESC.
      // Reset everything.
      if ( event.which === 27 ) {
        formation = [];
        state = State.RANK;
      }

      draw( context );
    });

    draw( context );
  }) ();
}) ( window, document );
<commit_msg>strategy[maneuvers]: Simplify Formation constructor.<commit_after>(function( window, document, undefined ) {
  'use strict';

  var PI2 = 2 * Math.PI;

  var canvas, context;

  // Formations coordinates array.
  var formations = [];
  var formation = [];

  var config = {
    // Unit count.
    count: 10,
    spacing: {
      rank: 10,
      file: 20
    }
  };

  /*
    Three states for drawing a formation:

             <--  1. RANK  -->       ^
      ^      [] [] [] [] [] []       |
      |      [] [] [] [] [] []       |
    2. FILE  [] [] [] [] [] []       |
      |      [] [] [] [] [] []       |
      v      [] [] [] [] [] []  3. DIRECTION

      A rank is horizontal and a file is vertical. In the above diagram,
      the formation is 5 ranks deep and 6 files wide.
   */

  var State = {
    RANK: 0,
    FILE: 1,
    DIRECTION: 2
  };

  var state = State.RANK;

  var mouse = {
    x: 0,
    y: 0,

    // Initial points.
    xi: 0,
    yi: 0,

    down: false
  };

  function Formation( x0, y0, x1, y1, x2, y2 ) {
    this.x0 = x0;
    this.y0 = y0;
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;

    // First edge (width).
    var dx = x1 - x0,
        dy = y1 - y0;

    this.angle = Math.atan2( -dy, dx );
    this.width = Math.sqrt( dx * dx + dy * dy );

    // Second edge (height).
    var point = this.toLocal( x2 - x1, y2 - y1 );
    this.height = point.y;

    Object.freeze( this );
  }

  Formation.prototype.toWorld = function( x, y ) {
    var cos, sin;
    var rx, ry;

    if ( this.angle ) {
      cos = Math.cos( -this.angle );
      sin = Math.sin( -this.angle );

      rx = cos * x - sin * y;
      ry = sin * x + cos * y;

      x = rx;
      y = ry;
    }

    return {
      x: x + this.x0,
      y: y + this.y0
    };
  };

  Formation.prototype.toLocal = function( x, y ) {
    x -= this.x0;
    y -= this.y0;

    var cos, sin;
    var rx, ry;

    if ( this.angle ) {
      cos = Math.cos( this.angle );
      sin = Math.sin( this.angle );

      rx = cos * x - sin * y;
      ry = sin * x + cos * y;

      x = rx;
      y = ry;
    }

    return {
      x: x,
      y: y
    };
  };

  function drawRectFromPoints( ctx, x0, y0, x1, y1, x2, y2 ) {
    // First edge (width).
    var dx0 = x1 - x0,
        dy0 = y1 - y0;

    var angle = Math.atan2( -dy0, dx0 );
    var width = Math.sqrt( dx0 * dx0 + dy0 * dy0 );

    // Second edge (height).
    var dx1 = x2 - x1,
        dy1 = y2 - y1;

    var cos, sin;
    var rx, ry;
    if ( angle ) {
      cos = Math.cos( angle );
      sin = Math.sin( angle );

      rx = cos * dx1 - sin * dy1;
      ry = sin * dx1 + cos * dy1;

      dx1 = rx;
      dy1 = ry;
    }

    ctx.save();

    ctx.translate( x0, y0 );
    ctx.rotate( -angle );

    ctx.beginPath();
    ctx.rect( 0, 0, width, dy1 );

    ctx.restore();
  }

  function draw( ctx ) {
    ctx.clearRect( 0, 0, ctx.canvas.width, ctx.canvas.height );

    ctx.lineWidth = 1;
    ctx.strokeStyle = '#fff';
    ctx.fillStyle = '#fff';
    ctx.font = '16pt "Helvetica Neue", Helvetica, Arial, sans-serif';

    // Mouse.
    ctx.beginPath();
    ctx.arc( mouse.x, mouse.y, 10, 0, PI2 );
    ctx.stroke();

    // Formations.
    formations.forEach(function( formation ) {
      var x0 = formation[0][0],
          y0 = formation[0][1],
          x1 = formation[1][0],
          y1 = formation[1][1],
          x2 = formation[2][0],
          y2 = formation[2][1];

      drawRectFromPoints( ctx, x0, y0, x1, y1, x2, y2 );
      ctx.stroke();
    });

    var x0, y0,
        x1, y1,
        x2, y2;
    if ( formation.length ) {
      x0 = formation[0][0];
      y0 = formation[0][1];
      x1 = formation[1][0];
      y1 = formation[1][1];

      if ( formation.length > 2 ) {
        x2 = formation[2][0];
        y2 = formation[2][1];
      }

      var dx = x1 - x0,
          dy = y1 - y0;

      var angle = Math.atan2( -dy, dx );
      ctx.fillText( Math.round( angle * 180 / Math.PI ), 300, 40 );
    }

    if ( mouse.down && state === State.RANK ) {
      ctx.beginPath();
      ctx.moveTo( mouse.xi, mouse.yi );
      ctx.lineTo( mouse.x, mouse.y );
      ctx.stroke();
    } else if ( state === State.FILE ) {
      drawRectFromPoints( ctx, x0, y0, x1, y1, mouse.x, mouse.y );
      ctx.stroke();
    } else if ( state === State.DIRECTION ) {
      drawRectFromPoints( ctx, x0, y0, x1, y1, x2, y2 );
      ctx.moveTo( x0, y0 );
      ctx.lineTo( mouse.x, mouse.y );
      ctx.moveTo( x1, y1 );
      ctx.lineTo( mouse.x, mouse.y );
      ctx.stroke();
    }
    ctx.fillText( 'state: ' + state, 32, 32 );
    ctx.fillText( config.count, 32, 72 );
  }

  (function init() {
    canvas  = document.createElement( 'canvas' );
    context = canvas.getContext( '2d' );

    document.body.appendChild( canvas );

    canvas.width  = window.innerWidth;
    canvas.height = window.innerHeight;

    function mousePosition( event ) {
      mouse.x = event.pageX - canvas.offsetLeft;
      mouse.y = event.pageY - canvas.offsetTop;
    }

    window.addEventListener( 'mousedown', function( event ) {
      mousePosition( event );
      mouse.xi = mouse.x;
      mouse.yi = mouse.y;

      mouse.down = true;

      if ( state === State.DIRECTION ) {
        formations.push( formation );
        formation = [];
        state = State.RANK;
      }
    });

    window.addEventListener( 'mousemove', function( event ) {
      mousePosition( event );
      draw( context );
    });

    window.addEventListener( 'mouseup', function() {
      mousePosition( event );
      mouse.down = false;

      if ( state === State.RANK ) {
        var dx = mouse.x - mouse.xi,
            dy = mouse.y - mouse.yi;

        if ( !dx && !dy ) {
          return;
        }

        formation = [
          [ mouse.xi, mouse.yi ],
          [ mouse.x, mouse.y ]
        ];

        state = State.FILE;
      } else if ( state === State.FILE ) {
        formation[2] = [ mouse.x, mouse.y ];
        state = State.DIRECTION;
      }
    });

    document.addEventListener( 'keydown', function( event ) {
      // Up arrow.
      if ( event.which === 38 ) {
        config.count++;
      }

      // Down arrow.
      if ( event.which === 40 ) {
        config.count = Math.max( config.count - 1, 0 );
      }

      // ESC.
      // Reset everything.
      if ( event.which === 27 ) {
        formation = [];
        state = State.RANK;
      }

      draw( context );
    });

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


<commit_before>const ActionTypes = require('../../src/router/constants/ActionTypes');
const clients = require('../../src/router/reducers/clients');
const expect = require('expect');
const net = require('net');

describe('clients reducer', () => {
    it('should handle initial state', () => {
        expect(clients(undefined, {})).toEqual([]);
    });

    it('should handle ADD_CLIENT', () => {
        var client = new net.Socket();

        expect(clients([], {
            client: client,
            type: ActionTypes.ADD_CLIENT
        })).toInclude(client);
    });

    it('should handle DELETE_CLIENT', () => {
        var client = new net.Socket();

        expect(clients([client], {
            client: client,
            type: ActionTypes.DELETE_CLIENT
        })).toExclude(client);
    });
});
<commit_msg>Updated clients reducer tests<commit_after>const ActionTypes = require('../../src/router/constants/ActionTypes');
const clients = require('../../src/router/reducers/clients');
const expect = require('expect');
const net = require('net');

describe('clients reducer', () => {
    it('should handle initial state', () => {
        var clientsBefore = undefined;
        var clientsAfter = clients(clientsBefore, {});

        expect(clientsAfter).toEqual([]);
    });

    it('should handle ADD_CLIENT', () => {
        var client = new net.Socket();

        var clientsBefore = [];
        var clientsAfter = clients(clientsBefore, {
            client: client,
            type: ActionTypes.ADD_CLIENT
        });

        expect(clientsAfter).toInclude(client);
    });

    it('should handle DELETE_CLIENT', () => {
        var client = new net.Socket();

        var clientsBefore = [client];
        var clientsAfter = clients(clientsBefore, {
            client: client,
            type: ActionTypes.DELETE_CLIENT
        });

        expect(clientsAfter).toExclude(client);
    });
});
<|endoftext|>


<commit_before>'use strict';

var RuleTester = require('eslint').RuleTester,
    rules = require('../../').rules,
    es6RuleTester = new RuleTester({
        parserOptions: { ecmaVersion: 6 }
    }),
    expectedErrorMessage = 'Do not pass arrow functions to it()',
    es2017RuleTester = new RuleTester({
        parserOptions: { ecmaVersion: 2017 }
    }),
    errors = [ { message: expectedErrorMessage, column: 1, line: 1 } ];

es6RuleTester.run('no-mocha-arrows', rules['no-mocha-arrows'], {

    valid: [
        'it()',
        'it(function() { assert(something, false); })',
        'it("should be false", function() { assert(something, false); })',
         // In this example, `it` is not a global.
        'function it () {}; it(() => { console.log("okay") })',
        'it.only()',
        'it(function(done) { assert(something, false); done(); })',
        'it(function*() { assert(something, false) })'
    ],

    invalid: [
        {
            code: 'it(() => { assert(something, false); })',
            errors: errors,
            output: 'it(function () { assert(something, false); })'
        },
        {
            code: 'it(() => { assert(something, false); })',
            globals: [ 'it' ],
            errors: errors,
            output: 'it(function () { assert(something, false); })'
        },
        {
            code: 'it(() => assert(something, false))',
            errors: errors,
            output: 'it(function () { return assert(something, false); })'
        },
        {
            code: 'it("should be false", () => { assert(something, false); })',
            errors: errors,
            output: 'it("should be false", function () { assert(something, false); })'
        },
        {
            code: 'it.only(() => { assert(something, false); })',
            errors: [ { message: 'Do not pass arrow functions to it.only()', column: 1, line: 1 } ],
            output: 'it.only(function () { assert(something, false); })'
        },
        {
            code: 'it((done) => { assert(something, false); })',
            errors: errors,
            output: 'it(function (done) { assert(something, false); })'
        },
        {
            code: 'it("should be false", () => {\n assert(something, false);\n})',
            errors: errors,
            output: 'it("should be false", function () {\n assert(something, false);\n})'
        }
    ]

});

es2017RuleTester.run('no-mocha-arrows', rules['no-mocha-arrows'], {

    valid: [
        'it(async function () { assert(something, false) })'
    ],

    invalid: [
        {
            code: 'it(async () => { assert(something, false) })',
            errors: errors,
            output: 'it(async function () { assert(something, false) })'
        },
        {
            code: 'it(async () => assert(something, false))',
            errors: errors,
            output: 'it(async function () { return assert(something, false); })'
        },
        {
            code: 'it(async() => assert(something, false))',
            errors: errors,
            output: 'it(async function() { return assert(something, false); })'
        }
    ]

});
<commit_msg>Use one test runner for all test cases<commit_after>'use strict';

var RuleTester = require('eslint').RuleTester,
    rules = require('../../').rules,
    ruleTester = new RuleTester({
        parserOptions: { ecmaVersion: 2017 }
    }),
    expectedErrorMessage = 'Do not pass arrow functions to it()',
    errors = [ { message: expectedErrorMessage, column: 1, line: 1 } ];

ruleTester.run('no-mocha-arrows', rules['no-mocha-arrows'], {

    valid: [
        'it()',
        'it(function() { assert(something, false); })',
        'it("should be false", function() { assert(something, false); })',
         // In this example, `it` is not a global.
        'function it () {}; it(() => { console.log("okay") })',
        'it.only()',
        'it(function(done) { assert(something, false); done(); })',
        'it(function*() { assert(something, false) })',
        'it(async function () { assert(something, false) })'
    ],

    invalid: [
        {
            code: 'it(() => { assert(something, false); })',
            errors: errors,
            output: 'it(function () { assert(something, false); })'
        },
        {
            code: 'it(() => { assert(something, false); })',
            globals: [ 'it' ],
            errors: errors,
            output: 'it(function () { assert(something, false); })'
        },
        {
            code: 'it(() => assert(something, false))',
            errors: errors,
            output: 'it(function () { return assert(something, false); })'
        },
        {
            code: 'it("should be false", () => { assert(something, false); })',
            errors: errors,
            output: 'it("should be false", function () { assert(something, false); })'
        },
        {
            code: 'it.only(() => { assert(something, false); })',
            errors: [ { message: 'Do not pass arrow functions to it.only()', column: 1, line: 1 } ],
            output: 'it.only(function () { assert(something, false); })'
        },
        {
            code: 'it((done) => { assert(something, false); })',
            errors: errors,
            output: 'it(function (done) { assert(something, false); })'
        },
        {
            code: 'it("should be false", () => {\n assert(something, false);\n})',
            errors: errors,
            output: 'it("should be false", function () {\n assert(something, false);\n})'
        },
        {
            code: 'it(async () => { assert(something, false) })',
            errors: errors,
            output: 'it(async function () { assert(something, false) })'
        },
        {
            code: 'it(async () => assert(something, false))',
            errors: errors,
            output: 'it(async function () { return assert(something, false); })'
        },
        {
            code: 'it(async() => assert(something, false))',
            errors: errors,
            output: 'it(async function() { return assert(something, false); })'
        }
    ]

});
<|endoftext|>


<commit_before>
var createClass = require('../functions/createClass');
var convertValueType = require('../functions/convertValueType');
var noop = require('../functions/noop');
var Binder = require('../Binder');
var View = require('../View');
var insertBefore = require('../functions/nodeMan').insertBefore;
var removeChild = require('../functions/nodeMan').removeChild;

var createInsertBinder = function(negate, force){

	return createClass(
	{
		extend: Binder
	},
	/** @lends InsertBinder.prototype */
	{
		/**
		 * One-way data binder (model to DOM) for inserting/removing element from DOM.
		 *
		 * @constructs
		 * @augments Binder
		 * @param {Object} options Options objectt
		 */
		constructor: function(options)
		{
			Binder.call(this, options);
		},

		init: function()
		{
			this.equalsTo = true;

			if(this.options.params[0])
			{
				if(this.options.parsers.length === 0) this.equalsTo = convertValueType(this.options.params[0]);
				else this.equalsTo = this.parse(this.options.params[0]);
			}
			else this.options.params[0] = this.equalsTo;

			this.negate = this.options.params[1] === 'ne' || negate;

			this.forceRerender = force || this.options.params[2] === 'force' || this.options.params[1] === 'force';

			this.isInserted = true;

			if(this.forceRerender)
			{
				this.isRun = false;
				this.isRendered = true;

				this.renderSubviews = this.view.renderSubviews;
				this.runSubviews = this.view.runSubviews;
				this.destroySubviews = this.view.destroySubviews;

				this.view.renderSubviews = noop;
				this.view.runSubviews = noop;
				this.view.destroySubviews = noop;
			}

			Binder.prototype.init.call(this);
		},

		destroy: function()
		{
			if(this.forceRerender)
			{
				this.view.renderSubviews = this.renderSubviews;
				this.view.runSubviews = this.runSubviews;
				this.view.destroySubviews = this.destroySubviews;
			}
			if(!this.isInserted && this.anchor)
			{
				var parentNode = this.anchor.parentNode;

				if(parentNode)
				{
					parentNode.replaceChild(this.$element[0], this.anchor);
				}
				this.isInserted = true;
			}
			this.anchor = null;

			Binder.prototype.destroy.call(this);
		},

		refresh: function()
		{
			var parentNode;
			if(!this.anchor)
			{
				this.anchor = this.view.env.document.createTextNode('');
				this.$element[0].parentNode.insertBefore(this.anchor, this.$element[0]);
			}

			var nodeInsert = insertBefore;
			var nodeRemove = removeChild;

			if(this.animate)
			{
				nodeInsert = this.view.scope[this.animate]['insert'];
				nodeRemove = this.view.scope[this.animate]['remove'];
			}

			if(this.matchValue())
			{
				if(!this.isInserted)
				{
					parentNode = this.anchor.parentNode;

					if(parentNode)
					{
						nodeInsert(parentNode, this.anchor, this.$element[0]);
						// parentNode.replaceChild(this.$element[0], this.anchor);
					}
					this.isInserted = true;
				}
				if(this.forceRerender)
				{
					if(!this.isRendered)
					{
						this.renderSubviews.call(this.view);
						this.isRendered = true;
					}
					if(!this.isRun)
					{
						this.runSubviews.call(this.view);
						this.isRun = true;
					}
				}
			}
			else
			{
				if(this.isInserted)
				{
					parentNode = this.$element[0].parentNode;

					if(parentNode)
					{
						nodeRemove(parentNode, this.$element[0], this.f(function()
						{
							if(this.forceRerender && this.isRendered)
							{
								this.destroySubviews.call(this.view);
								this.isRendered = false;
								this.isRun = false;
							}
							this.isInserted = false;
						}));
						this.isInserted = false;

						// parentNode.removeChild(this.$element[0]);
						// parentNode.replaceChild(this.anchor, this.$element[0]);
					}
				}
				else if(this.forceRerender && this.isRendered)
				{
					this.destroySubviews.call(this.view);
					this.isRendered = false;
					this.isRun = false;
				}
			}
		},

		matchValue: function()
		{
			if(this.options.params.length > 0)
			{
				if(this.negate) return this.value !== this.equalsTo;
				else return this.value === this.equalsTo;
			}
			else return this.value;
		}
	});

};

// InsertBinder = createInsertBinder(false, false);
var IfBinder = createInsertBinder(false, true);
var IfNotBinder = createInsertBinder(true, true);

// BindingView.registerBinder('insert', InsertBinder);
View.registerBinder('if', IfBinder);
View.registerBinder('ifnot', IfNotBinder);

module.exports = {
	IfBinder: IfBinder,
	IfNotBinder: IfNotBinder
};

<commit_msg>feat(InsertBinder): allow use of @model.value notation in if/ifnot binder for dynamic value setting<commit_after>
var createClass = require('../functions/createClass');
var convertValueType = require('../functions/convertValueType');
var noop = require('../functions/noop');
var Binder = require('../Binder');
var View = require('../View');
var insertBefore = require('../functions/nodeMan').insertBefore;
var removeChild = require('../functions/nodeMan').removeChild;
var Cursor = require('../Cursor');

var createInsertBinder = function(negate, force){

	return createClass(
	{
		extend: Binder
	},
	/** @lends InsertBinder.prototype */
	{
		/**
		 * One-way data binder (model to DOM) for inserting/removing element from DOM.
		 *
		 * @constructs
		 * @augments Binder
		 * @param {Object} options Options objectt
		 */
		constructor: function(options)
		{
			Binder.call(this, options);
			this.equalsTo = undefined;
			this.valueCursor = undefined;
		},

		init: function()
		{
			this.equalsTo = true;
			this.valueCursor = undefined;

			if(this.options.params[0])
			{
				this.equalsTo = this.convertBindingValue(this.options.params[0]);
				if(this.equalsTo instanceof Cursor)
				{
					this.valueCursor = this.equalsTo;
					this.equalsTo = this.valueCursor.get();
				}
				if(this.equalsTo == null) this.equalsTo = null;
			}

			// if(this.options.params[0])
			// {
			// 	if(this.options.parsers.length === 0) this.equalsTo = convertValueType(this.options.params[0]);
			// 	else this.equalsTo = this.parse(this.options.params[0]);
			// }
			// else this.options.params[0] = this.equalsTo;

			this.negate = this.options.params[1] === 'ne' || negate;

			this.forceRerender = force || this.options.params[2] === 'force' || this.options.params[1] === 'force';

			this.isInserted = true;

			if(this.forceRerender)
			{
				this.isRun = false;
				this.isRendered = true;

				this.renderSubviews = this.view.renderSubviews;
				this.runSubviews = this.view.runSubviews;
				this.destroySubviews = this.view.destroySubviews;

				this.view.renderSubviews = noop;
				this.view.runSubviews = noop;
				this.view.destroySubviews = noop;
			}

			Binder.prototype.init.call(this);
		},

		destroy: function()
		{
			if(this.forceRerender)
			{
				this.view.renderSubviews = this.renderSubviews;
				this.view.runSubviews = this.runSubviews;
				this.view.destroySubviews = this.destroySubviews;
			}
			if(!this.isInserted && this.anchor)
			{
				var parentNode = this.anchor.parentNode;

				if(parentNode)
				{
					parentNode.replaceChild(this.$element[0], this.anchor);
				}
				this.isInserted = true;
			}
			this.anchor = null;

			Binder.prototype.destroy.call(this);
		},

		refresh: function()
		{
			var parentNode;
			if(!this.anchor)
			{
				this.anchor = this.view.env.document.createTextNode('');
				this.$element[0].parentNode.insertBefore(this.anchor, this.$element[0]);
			}

			var nodeInsert = insertBefore;
			var nodeRemove = removeChild;

			if(this.animate)
			{
				nodeInsert = this.view.scope[this.animate]['insert'];
				nodeRemove = this.view.scope[this.animate]['remove'];
			}

			if(this.matchValue())
			{
				if(!this.isInserted)
				{
					parentNode = this.anchor.parentNode;

					if(parentNode)
					{
						nodeInsert(parentNode, this.anchor, this.$element[0]);
						// parentNode.replaceChild(this.$element[0], this.anchor);
					}
					this.isInserted = true;
				}
				if(this.forceRerender)
				{
					if(!this.isRendered)
					{
						this.renderSubviews.call(this.view);
						this.isRendered = true;
					}
					if(!this.isRun)
					{
						this.runSubviews.call(this.view);
						this.isRun = true;
					}
				}
			}
			else
			{
				if(this.isInserted)
				{
					parentNode = this.$element[0].parentNode;

					if(parentNode)
					{
						nodeRemove(parentNode, this.$element[0], this.f(function()
						{
							if(this.forceRerender && this.isRendered)
							{
								this.destroySubviews.call(this.view);
								this.isRendered = false;
								this.isRun = false;
							}
							this.isInserted = false;
						}));
						this.isInserted = false;

						// parentNode.removeChild(this.$element[0]);
						// parentNode.replaceChild(this.anchor, this.$element[0]);
					}
				}
				else if(this.forceRerender && this.isRendered)
				{
					this.destroySubviews.call(this.view);
					this.isRendered = false;
					this.isRun = false;
				}
			}
		},

		matchValue: function()
		{
			if(this.options.params.length > 0)
			{
				if(this.valueCursor)
				{
					this.equalsTo = this.valueCursor.get();
					if(this.equalsTo == null) this.equalsTo = null;
				}
				var value = this.value;
				if(value == null) value = null;
				if(this.negate) return value !== this.equalsTo;
				else return value === this.equalsTo;
			}
			else return this.value;
		}
	});

};

// InsertBinder = createInsertBinder(false, false);
var IfBinder = createInsertBinder(false, true);
var IfNotBinder = createInsertBinder(true, true);

// BindingView.registerBinder('insert', InsertBinder);
View.registerBinder('if', IfBinder);
View.registerBinder('ifnot', IfNotBinder);

module.exports = {
	IfBinder: IfBinder,
	IfNotBinder: IfNotBinder
};

<|endoftext|>


<commit_before>var assert = require('assert');
var exec = require('child_process').exec;
var configUtils = require('./utils/config');
var testUtils = require('./utils/test');

describe('An retina array of image positions, dimensions, and names', function () {
  testUtils.setInfo(configUtils.retinaMultipleSprites);

  describe.only('processed by `spritesheet-templates` into retina SCSS (Maps)', function () {
    testUtils.runTemplater({format: 'scss_maps_retina'});
    testUtils.assertOutputMatches(__dirname + '/expected_files/scss_maps_retina.scss');

    testUtils.generateCssFile('\n' + [
      '@include retina-sprites($retina-groups);'
    ].join('\n'));

    describe.skip('processed by `sass --scss` (ruby) into CSS', function () {
      // Process the SCSS
      testUtils.processCss(function processScss (cb) {
        exec('sass --scss ' + this.tmp.path, function (err, css, stderr) {
          // Assert no errors during conversion
          assert.strictEqual(stderr, '');
          assert.notEqual(css, '');
          cb(err, css);
        });
      });

      // Assert agains the generated CSS
      testUtils.assertValidCss();
    });
  });
});
<commit_msg>Fixed up our tests<commit_after>var assert = require('assert');
var exec = require('child_process').exec;
var configUtils = require('./utils/config');
var testUtils = require('./utils/test');

describe('An retina array of image positions, dimensions, and names', function () {
  testUtils.setInfo(configUtils.retinaMultipleSprites);

  describe('processed by `spritesheet-templates` into retina SCSS (Maps)', function () {
    testUtils.runTemplater({format: 'scss_maps_retina'});
    testUtils.assertOutputMatches(__dirname + '/expected_files/scss_maps_retina.scss');

    testUtils.generateCssFile('\n' + [
      '@include retina-sprites($retina-groups);'
    ].join('\n'));

    describe('processed by `sass --scss` (ruby) into CSS', function () {
      // Process the SCSS
      testUtils.processCss(function processScss (cb) {
        exec('sass --scss ' + this.tmp.path, function (err, css, stderr) {
          // Assert no errors during conversion
          assert.strictEqual(stderr, '');
          assert.notEqual(css, '');
          // DEV: Repair vendor specific validation issues
          css = css.replace(/\(-webkit-min-device-pixel-ratio: 2\),/g, '');
          cb(err, css);
        });
      });

      // Assert agains the generated CSS
      testUtils.assertValidCss();
    });
  });
});
<|endoftext|>


<commit_before>var common = require('../common');
var assert = require('assert');

(function testAddingKeyToDevelopmentEnvironments() {
  var airbrake = require(common.dir.root).createClient(common.key, 'dev');
  airbrake.developmentEnvironments.push('dev');
  airbrake.notify(new Error('this should not be posted to airbrake'), function(err, url) {
    assert.equal(err, undefined);
    assert.equal(url, undefined);
  });
})();

(function testDevelopmentEnviroment() {
  var airbrake = require(common.dir.root).createClient(common.key, 'development');
  // this should be posted to airbrake simply because we didn't add 'development' to
  // airbrake.developmentEnvironments. The decision to default to an empty array here
  // was to ensure that the previous expected behavior would continue (in the odd chance
  // someone was expecting airbrake notifications in development).
  airbrake.notify(new Error('this should be posted to airbrake'), function(err, url) {
    assert.equal(err, undefined);
    assert.ok(/^http:\/\//.test(url));
  });
})();

(function testProductionEnviroment() {
  var airbrake = require(common.dir.root).createClient(common.key, 'production');
  airbrake.notify(new Error('this should be posted to airbrake'), function(err, url) {
    assert.equal(err, undefined);
    assert.ok(/^http:\/\//.test(url));
  });
})();<commit_msg>Fixed test broken by decision made in 17bec51d50c0d2076dcbd8360eb3aab7943fec97<commit_after>var common = require('../common');
var assert = require('assert');

(function testAddingKeyToDevelopmentEnvironments() {
  var airbrake = require(common.dir.root).createClient(common.key, 'dev');
  airbrake.developmentEnvironments.push('dev');
  airbrake.notify(new Error('this should not be posted to airbrake'), function(err, url) {
    assert.equal(err, undefined);
    assert.equal(url, undefined);
  });
})();

(function testDevelopmentEnviroment() {
  var airbrake = require(common.dir.root).createClient(common.key, 'dev');
  // this should be posted to airbrake simply because we didn't add 'dev' to
  // airbrake.developmentEnvironments.
  airbrake.notify(new Error('this should be posted to airbrake'), function(err, url) {
    assert.equal(err, undefined);
    assert.ok(/^http:\/\//.test(url));
  });
})();

(function testProductionEnviroment() {
  var airbrake = require(common.dir.root).createClient(common.key, 'production');
  airbrake.notify(new Error('this should be posted to airbrake'), function(err, url) {
    assert.equal(err, undefined);
    assert.ok(/^http:\/\//.test(url));
  });
})();<|endoftext|>