<commit_before>/**
 * @name react-native-fetch-blob-fs
 * @author wkh237
 * @version 0.1.0
 * @flow
 */

import {
  NativeModules,
  DeviceEventEmitter,
  NativeAppEventEmitter,
} from 'react-native'
import RNFetchBlobSession from './class/RNFetchBlobSession'
import RNFetchBlobWriteStream from './class/RNFetchBlobWriteStream'
import RNFetchBlobReadStream from './class/RNFetchBlobReadStream'
import RNFetchBlobFile from './class/RNFetchBlobFile'
import type {
  RNFetchBlobNative,
  RNFetchBlobConfig,
  RNFetchBlobStream
} from './types'

const RNFetchBlob:RNFetchBlobNative = NativeModules.RNFetchBlob
const emitter = DeviceEventEmitter

// session table
let sessions = {}

/**
 * Get path of system directories.
 * @return {object} Map contains DocumentDir, CacheDir, DCIMDir, DownloadDir,
 * , some directory might not be supported by platform.
 */
function getSystemDirs() {
  return new Promise((resolve, reject) => {
    try {
      RNFetchBlob.getEnvironmentDirs((...dirs) => {
        let [DocumentDir, CacheDir, DCIMDir, DownloadDir] = [...dirs]
        resolve({DocumentDir, CacheDir, DCIMDir, DownloadDir})
      })
    } catch(err) {
      reject(err)
    }
  })
}

/**
 * Get a file cache session
 * @param  {string} name Stream ID
 * @return {RNFetchBlobSession}
 */
function session(name:string):RNFetchBlobSession {
  let s = sessions[name]
  if(s)
    return new RNFetchBlobSession(name)
  else {
    sessions[name] = []
    return new RNFetchBlobSession(name, [])
  }
}

function createFile(path:string, data:string, encoding: 'base64' | 'ascii' | 'utf8'):Promise {
  encoding = encoding || 'utf8'
  return new Promise((resolve, reject) => {
    let handler = (err) => {
      if(err)
      reject(err)
      else
      resolve()
    }
    if(encoding.toLowerCase() === 'ascii') {
      if(Array.isArray(data))
        RNFetchBlob.createFileASCII(path, data, handler)
      else
        reject('`data` of ASCII file must be an array contains numbers')
    }
    else {
      RNFetchBlob.createFile(path, data, encoding, handler)
    }
  })
}

/**
 * Create write stream to a file.
 * @param  {string} path Target path of file stream.
 * @param  {string} encoding Encoding of input data.
 * @param  {bool} append  A flag represent if data append to existing ones.
 * @return {Promise<WriteStream>} A promise resolves a `WriteStream` object.
 */
function writeStream(
  path : string,
  encoding : 'utf8' | 'ascii' | 'base64',
  append? : ?bool,
):Promise<RNFetchBlobWriteStream> {
  if(!path)
    throw Error('RNFetchBlob could not open file stream with empty `path`')
  encoding = encoding || 'utf8'
  append = append || false
  return new Promise((resolve, reject) => {
    RNFetchBlob.writeStream(path, encoding || 'base64', append || false, (err, streamId:string) => {
      if(err)
        reject(err)
      else
        resolve(new RNFetchBlobWriteStream(streamId, encoding))
    })
  })
}

/**
 * Create file stream from file at `path`.
 * @param  {string} path   The file path.
 * @param  {string} encoding Data encoding, should be one of `base64`, `utf8`, `ascii`
 * @param  {boolean} bufferSize Size of stream buffer.
 * @return {RNFetchBlobStream} RNFetchBlobStream stream instance.
 */
function readStream(
  path : string,
  encoding : 'utf8' | 'ascii' | 'base64',
  bufferSize? : ?number
):Promise<RNFetchBlobReadStream> {
  return Promise.resolve(new RNFetchBlobReadStream(path, encoding, bufferSize))
}

/**
 * Create a directory.
 * @param  {string} path Path of directory to be created
 * @return {Promise}
 */
function mkdir(path:string):Promise {

  return new Promise((resolve, reject) => {
    RNFetchBlob.mkdir(path, (err, res) => {
      if(err)
        reject(err)
      else
        resolve()
    })
  })

}

/**
 * Show statistic data of a path.
 * @param  {string} path Target path
 * @return {RNFetchBlobFile}
 */
function stat(path:string):Promise<RNFetchBlobFile> {

}

/**
 * Android only method, request media scanner to scan the file.
 * @param  {Array<string>} paths Paths of files to be scanned.
 * @param  {Array<string>} mimes Optional array of MIME types for each path.
 *                               If mimeType is null, then the mimeType will be
 *                               inferred from the file extension.
 * @return {Promise}
 */
function scanFile(paths:Array<string>, mimes: Array<string>):Promise {

}

function cp(path:string, dest:string):Promise<boolean> {
  return new Promise((resolve, reject) => {
    RNFetchBlob.cp(path, dest, (err, res) => {
      if(err)
        reject(err)
      else
        resolve(res)
    })
  })
}

function mv(path:string, dest:string):Promise<boolean> {
  return new Promise((resolve, reject) => {
    RNFetchBlob.mv(path, dest, (err, res) => {
      if(err)
        reject(err)
      else
        resolve(res)
    })
  })
}

function ls(path:string):Promise<Array<String>> {
  return new Promise((resolve, reject) => {
    RNFetchBlob.ls(path, (err, res) => {
      if(err)
        reject(err)
      else
        resolve(res)
    })
  })
}

/**
 * Remove file at path.
 * @param  {string}   path:string Path of target file.
 * @return {Promise}
 */
function unlink(path:string):Promise {
  return new Promise((resolve, reject) => {
    RNFetchBlob.unlink(path, (err) => {
      if(err)
        reject(err)
      else
        resolve()
    })
  })
}

/**
 * Check if file exists and if it is a folder.
 * @param  {string} path Path to check
 * @return {Promise<bool, bool>}
 */
function exists(path:string):Promise<bool, bool> {

  return new Promise((resolve, reject) => {
    try {
      RNFetchBlob.exists(path, (exist) => {
        resolve(exist)
      })
    } catch(err) {
      reject(err)
    }
  })

}

function isDir(path:string):Promise<bool, bool> {

  return new Promise((resolve, reject) => {
    try {
      RNFetchBlob.exists(path, (exist, isDir) => {
        resolve(isDir)
      })
    } catch(err) {
      reject(err)
    }
  })

}

export default {
  RNFetchBlobSession,
  unlink,
  mkdir,
  session,
  ls,
  readStream,
  getSystemDirs,
  mv,
  cp,
  writeStream,
  exists,
  createFile,
  isDir
}
<commit_msg>Add system dirs to Android native<commit_after>/**
 * @name react-native-fetch-blob-fs
 * @author wkh237
 * @version 0.1.0
 * @flow
 */

import {
  NativeModules,
  DeviceEventEmitter,
  NativeAppEventEmitter,
} from 'react-native'
import RNFetchBlobSession from './class/RNFetchBlobSession'
import RNFetchBlobWriteStream from './class/RNFetchBlobWriteStream'
import RNFetchBlobReadStream from './class/RNFetchBlobReadStream'
import RNFetchBlobFile from './class/RNFetchBlobFile'
import type {
  RNFetchBlobNative,
  RNFetchBlobConfig,
  RNFetchBlobStream
} from './types'

const RNFetchBlob:RNFetchBlobNative = NativeModules.RNFetchBlob
const emitter = DeviceEventEmitter

// session table
let sessions = {}

/**
 * Get path of system directories.
 * @return {object} Map contains DocumentDir, CacheDir, DCIMDir, DownloadDir,
 * , some directory might not be supported by platform.
 */
function getSystemDirs() {
  return new Promise((resolve, reject) => {
    try {
      RNFetchBlob.getEnvironmentDirs((...dirs) => {
        let [
          DocumentDir,
          CacheDir,
          // Android only
          DCIMDir,
          DownloadDir,
          PictureDir,
          MusicDir,
          MovieDir,
          RingToneDir] = [...dirs]
        resolve({
          DocumentDir,
          CacheDir,
          DCIMDir,
          DownloadDir,
          PictureDir,
          MusicDir,
          MovieDir,
          RingToneDir
        })
      })
    } catch(err) {
      reject(err)
    }
  })
}

/**
 * Get a file cache session
 * @param  {string} name Stream ID
 * @return {RNFetchBlobSession}
 */
function session(name:string):RNFetchBlobSession {
  let s = sessions[name]
  if(s)
    return new RNFetchBlobSession(name)
  else {
    sessions[name] = []
    return new RNFetchBlobSession(name, [])
  }
}

function createFile(path:string, data:string, encoding: 'base64' | 'ascii' | 'utf8'):Promise {
  encoding = encoding || 'utf8'
  return new Promise((resolve, reject) => {
    let handler = (err) => {
      if(err)
      reject(err)
      else
      resolve()
    }
    if(encoding.toLowerCase() === 'ascii') {
      if(Array.isArray(data))
        RNFetchBlob.createFileASCII(path, data, handler)
      else
        reject('`data` of ASCII file must be an array contains numbers')
    }
    else {
      RNFetchBlob.createFile(path, data, encoding, handler)
    }
  })
}

/**
 * Create write stream to a file.
 * @param  {string} path Target path of file stream.
 * @param  {string} encoding Encoding of input data.
 * @param  {bool} append  A flag represent if data append to existing ones.
 * @return {Promise<WriteStream>} A promise resolves a `WriteStream` object.
 */
function writeStream(
  path : string,
  encoding : 'utf8' | 'ascii' | 'base64',
  append? : ?bool,
):Promise<RNFetchBlobWriteStream> {
  if(!path)
    throw Error('RNFetchBlob could not open file stream with empty `path`')
  encoding = encoding || 'utf8'
  append = append || false
  return new Promise((resolve, reject) => {
    RNFetchBlob.writeStream(path, encoding || 'base64', append || false, (err, streamId:string) => {
      if(err)
        reject(err)
      else
        resolve(new RNFetchBlobWriteStream(streamId, encoding))
    })
  })
}

/**
 * Create file stream from file at `path`.
 * @param  {string} path   The file path.
 * @param  {string} encoding Data encoding, should be one of `base64`, `utf8`, `ascii`
 * @param  {boolean} bufferSize Size of stream buffer.
 * @return {RNFetchBlobStream} RNFetchBlobStream stream instance.
 */
function readStream(
  path : string,
  encoding : 'utf8' | 'ascii' | 'base64',
  bufferSize? : ?number
):Promise<RNFetchBlobReadStream> {
  return Promise.resolve(new RNFetchBlobReadStream(path, encoding, bufferSize))
}

/**
 * Create a directory.
 * @param  {string} path Path of directory to be created
 * @return {Promise}
 */
function mkdir(path:string):Promise {

  return new Promise((resolve, reject) => {
    RNFetchBlob.mkdir(path, (err, res) => {
      if(err)
        reject(err)
      else
        resolve()
    })
  })

}

/**
 * Show statistic data of a path.
 * @param  {string} path Target path
 * @return {RNFetchBlobFile}
 */
function stat(path:string):Promise<RNFetchBlobFile> {

}

/**
 * Android only method, request media scanner to scan the file.
 * @param  {Array<string>} paths Paths of files to be scanned.
 * @param  {Array<string>} mimes Optional array of MIME types for each path.
 *                               If mimeType is null, then the mimeType will be
 *                               inferred from the file extension.
 * @return {Promise}
 */
function scanFile(paths:Array<string>, mimes: Array<string>):Promise {

}

function cp(path:string, dest:string):Promise<boolean> {
  return new Promise((resolve, reject) => {
    RNFetchBlob.cp(path, dest, (err, res) => {
      if(err)
        reject(err)
      else
        resolve(res)
    })
  })
}

function mv(path:string, dest:string):Promise<boolean> {
  return new Promise((resolve, reject) => {
    RNFetchBlob.mv(path, dest, (err, res) => {
      if(err)
        reject(err)
      else
        resolve(res)
    })
  })
}

function lstat(path:string):Promise<Array<RNFetchBlobFile>> {

}

function ls(path:string):Promise<Array<String>> {
  return new Promise((resolve, reject) => {
    RNFetchBlob.ls(path, (err, res) => {
      if(err)
        reject(err)
      else
        resolve(res)
    })
  })
}

/**
 * Remove file at path.
 * @param  {string}   path:string Path of target file.
 * @return {Promise}
 */
function unlink(path:string):Promise {
  return new Promise((resolve, reject) => {
    RNFetchBlob.unlink(path, (err) => {
      if(err)
        reject(err)
      else
        resolve()
    })
  })
}

/**
 * Check if file exists and if it is a folder.
 * @param  {string} path Path to check
 * @return {Promise<bool, bool>}
 */
function exists(path:string):Promise<bool, bool> {

  return new Promise((resolve, reject) => {
    try {
      RNFetchBlob.exists(path, (exist) => {
        resolve(exist)
      })
    } catch(err) {
      reject(err)
    }
  })

}

function isDir(path:string):Promise<bool, bool> {

  return new Promise((resolve, reject) => {
    try {
      RNFetchBlob.exists(path, (exist, isDir) => {
        resolve(isDir)
      })
    } catch(err) {
      reject(err)
    }
  })

}

export default {
  RNFetchBlobSession,
  unlink,
  mkdir,
  session,
  ls,
  readStream,
  getSystemDirs,
  mv,
  cp,
  writeStream,
  exists,
  createFile,
  isDir,
  stat,
  lstat,
  scanFile
}
<|endoftext|>


<commit_before>// This is the default configuration for the dev mode of the web console.
// A generated version of this config is created at run-time when running
// the web console from the openshift binary.
//
// To change configuration for local development, copy this file to
// assets/app/config.local.js and edit the copy.
window.OPENSHIFT_CONFIG = {
  apis: {
    hostPort: "localhost:8443",
    prefix: "/apis"
  },
  api: {
    openshift: {
      hostPort: "localhost:8443",
      prefix: "/oapi"
    },
    k8s: {
      hostPort: "localhost:8443",
      prefix: "/api"
    }
  },
  auth: {
    oauth_authorize_uri: "https://localhost:8443/oauth/authorize",
    oauth_redirect_base: "https://localhost:9000/dev-console",
    oauth_client_id: "openshift-web-console",
    logout_uri: ""
  },
  loggingURL: "",
  metricsURL: ""
};

window.OPENSHIFT_VERSION = {
  openshift: "dev-mode",
  kubernetes: "dev-mode"
};
<commit_msg>Updated config.js to include additionalServers block<commit_after>// This is the default configuration for the dev mode of the web console.
// A generated version of this config is created at run-time when running
// the web console from the openshift binary.
//
// To change configuration for local development, copy this file to
// assets/app/config.local.js and edit the copy.
window.OPENSHIFT_CONFIG = {
  apis: {
    hostPort: "localhost:8443",
    prefix: "/apis"
  },
  api: {
    openshift: {
      hostPort: "localhost:8443",
      prefix: "/oapi"
    },
    k8s: {
      hostPort: "localhost:8443",
      prefix: "/api"
    }
  },
  additionalServers: [{
    protocol: "https",
    hostPort: "apiserver-svc-cat.10.0.0.25.xip.io:6443",
    prefix: "/apis"
  }],
  auth: {
    oauth_authorize_uri: "https://localhost:8443/oauth/authorize",
    oauth_redirect_base: "https://localhost:9000/dev-console",
    oauth_client_id: "openshift-web-console",
    logout_uri: ""
  },
  loggingURL: "",
  metricsURL: ""
};

window.OPENSHIFT_VERSION = {
  openshift: "dev-mode",
  kubernetes: "dev-mode"
};
<|endoftext|>


<commit_before>describe('security', function() {

  var $rootScope, $http, $httpBackend, status, userInfo;

  angular.module('test',[]).constant('I18N.MESSAGES', messages = {});
  beforeEach(module('security', 'test', 'security/login/form.tpl.html'));
  beforeEach(inject(function(_$rootScope_, _$httpBackend_, _$http_) {
    $rootScope = _$rootScope_;
    $httpBackend = _$httpBackend_;
    $http = _$http_;

    userInfo = { id: '1234567890', email: 'jo@bloggs.com', firstName: 'Jo', lastName: 'Bloggs'};
    $httpBackend.when('GET', '/current-user').respond(200, { user: userInfo });
  }));

  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });

  var service, queue;
  beforeEach(inject(function($injector) {
    service = $injector.get('security');
    queue = $injector.get('securityRetryQueue');
  }));

  describe('showLogin', function() {
    it("should open the dialog", function() {
      service.showLogin();
      $rootScope.$digest();
      expect(angular.element('.login-form').length).toBeGreaterThan(0);
    });
  });

  describe('login', function() {
    it('sends a http request to login the specified user', function() {
      $httpBackend.when('POST', '/login').respond(200, { user: userInfo });
      $httpBackend.expect('POST', '/login');
      service.login('email', 'password');
      $httpBackend.flush();
      expect(service.currentUser).toBe(userInfo);
    });
    it('calls queue.retry on a successful login', function() {
      $httpBackend.when('POST', '/login').respond(200, { user: userInfo });
      spyOn(queue, 'retryAll');
      service.showLogin();
      service.login('email', 'password');
      $httpBackend.flush();
      $rootScope.$digest();
      expect(queue.retryAll).toHaveBeenCalled();
      expect(service.currentUser).toBe(userInfo);
    });
    it('does not call queue.retryAll after a login failure', function() {
      $httpBackend.when('POST', '/login').respond(200, { user: null });
      spyOn(queue, 'retryAll');
      expect(queue.retryAll).not.toHaveBeenCalled();
      service.login('email', 'password');
      $httpBackend.flush();
      expect(queue.retryAll).not.toHaveBeenCalled();
    });
    it('returns true to success handlers if the user authenticated', function() {
      $httpBackend.when('POST', '/login').respond(200, { user: userInfo });
      service.login('email', 'password').then(function(loggedIn) {
        expect(loggedIn).toBe(true);
      });
      $httpBackend.flush();
    });
    it('returns true to success handlers if the user was not authenticated', function() {
      $httpBackend.when('POST', '/login').respond(200, { user: undefined });
      service.login('email', 'password').then(function(loggedIn) {
        expect(loggedIn).toBe(false);
      });
      $httpBackend.flush();
    });
  });

  describe('logout', function() {
    beforeEach(function() {
      $httpBackend.when('POST', '/logout').respond(200, {});
    });

    it('sends a http post to clear the current logged in user', function() {
      $httpBackend.expect('POST', '/logout');
      service.logout();
      $httpBackend.flush();
    });

    it('redirects to / by default', function() {
      inject(function($location) {
        spyOn($location, 'path');
        service.logout();
        $httpBackend.flush();
        expect($location.path).toHaveBeenCalledWith('/');
      });
    });

    it('redirects to the path specified in the first parameter', function() {
      inject(function($location) {
        spyOn($location, 'path');
        service.logout('/other/path');
        $httpBackend.flush();
        expect($location.path).toHaveBeenCalledWith('/other/path');
      });
    });
  });

  describe("currentUser", function() {

    it("should be unauthenticated to begin with", function() {
      expect(service.isAuthenticated()).toBe(false);
      expect(service.isAdmin()).toBe(false);
      expect(service.currentUser).toBe(null);
    });
    it("should be authenticated if we update with user info", function() {
      var userInfo = {};
      service.currentUser = userInfo;
      expect(service.isAuthenticated()).toBe(true);
      expect(service.isAdmin()).toBe(false);
      expect(service.currentUser).toBe(userInfo);
    });
    it("should be admin if we update with admin user info", function() {
      var userInfo = { admin: true };
      service.currentUser = userInfo;
      expect(service.isAuthenticated()).toBe(true);
      expect(service.isAdmin()).toBe(true);
      expect(service.currentUser).toBe(userInfo);
    });

    it("should not be authenticated or admin if we clear the user", function() {
      var userInfo = { admin: true };
      service.currentUser = userInfo;
      expect(service.isAuthenticated()).toBe(true);
      expect(service.isAdmin()).toBe(true);
      expect(service.currentUser).toBe(userInfo);

      service.currentUser = null;
      expect(service.isAuthenticated()).toBe(false);
      expect(service.isAdmin()).toBe(false);
      expect(service.currentUser).toBe(null);
    });
  });

  describe('requestCurrentUser', function() {
    it('makes a GET request to current-user url', function() {
      expect(service.isAuthenticated()).toBe(false);
      $httpBackend.expect('GET', '/current-user');
      service.requestCurrentUser().then(function(data) {
        resolved = true;
        expect(service.isAuthenticated()).toBe(true);
        expect(service.currentUser).toBe(userInfo);
      });
      $httpBackend.flush();
      expect(resolved).toBe(true);
    });
    it('returns the current user immediately if they are already authenticated', function() {
      userInfo = {};
      service.currentUser = userInfo;
      expect(service.isAuthenticated()).toBe(true);
      service.requestCurrentUser().then(function(data) {
        resolved = true;
        expect(service.currentUser).toBe(userInfo);
      });
      expect(resolved).toBe(true);
    });
  });

});<commit_msg>Fixed typo in unauthenticated handling spec in security.spec.js.<commit_after>describe('security', function() {

  var $rootScope, $http, $httpBackend, status, userInfo;

  angular.module('test',[]).constant('I18N.MESSAGES', messages = {});
  beforeEach(module('security', 'test', 'security/login/form.tpl.html'));
  beforeEach(inject(function(_$rootScope_, _$httpBackend_, _$http_) {
    $rootScope = _$rootScope_;
    $httpBackend = _$httpBackend_;
    $http = _$http_;

    userInfo = { id: '1234567890', email: 'jo@bloggs.com', firstName: 'Jo', lastName: 'Bloggs'};
    $httpBackend.when('GET', '/current-user').respond(200, { user: userInfo });
  }));

  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });

  var service, queue;
  beforeEach(inject(function($injector) {
    service = $injector.get('security');
    queue = $injector.get('securityRetryQueue');
  }));

  describe('showLogin', function() {
    it("should open the dialog", function() {
      service.showLogin();
      $rootScope.$digest();
      expect(angular.element('.login-form').length).toBeGreaterThan(0);
    });
  });

  describe('login', function() {
    it('sends a http request to login the specified user', function() {
      $httpBackend.when('POST', '/login').respond(200, { user: userInfo });
      $httpBackend.expect('POST', '/login');
      service.login('email', 'password');
      $httpBackend.flush();
      expect(service.currentUser).toBe(userInfo);
    });
    it('calls queue.retry on a successful login', function() {
      $httpBackend.when('POST', '/login').respond(200, { user: userInfo });
      spyOn(queue, 'retryAll');
      service.showLogin();
      service.login('email', 'password');
      $httpBackend.flush();
      $rootScope.$digest();
      expect(queue.retryAll).toHaveBeenCalled();
      expect(service.currentUser).toBe(userInfo);
    });
    it('does not call queue.retryAll after a login failure', function() {
      $httpBackend.when('POST', '/login').respond(200, { user: null });
      spyOn(queue, 'retryAll');
      expect(queue.retryAll).not.toHaveBeenCalled();
      service.login('email', 'password');
      $httpBackend.flush();
      expect(queue.retryAll).not.toHaveBeenCalled();
    });
    it('returns true to success handlers if the user authenticated', function() {
      $httpBackend.when('POST', '/login').respond(200, { user: userInfo });
      service.login('email', 'password').then(function(loggedIn) {
        expect(loggedIn).toBe(true);
      });
      $httpBackend.flush();
    });
    it('returns false to success handlers if the user was not authenticated', function() {
      $httpBackend.when('POST', '/login').respond(200, { user: undefined });
      service.login('email', 'password').then(function(loggedIn) {
        expect(loggedIn).toBe(false);
      });
      $httpBackend.flush();
    });
  });

  describe('logout', function() {
    beforeEach(function() {
      $httpBackend.when('POST', '/logout').respond(200, {});
    });

    it('sends a http post to clear the current logged in user', function() {
      $httpBackend.expect('POST', '/logout');
      service.logout();
      $httpBackend.flush();
    });

    it('redirects to / by default', function() {
      inject(function($location) {
        spyOn($location, 'path');
        service.logout();
        $httpBackend.flush();
        expect($location.path).toHaveBeenCalledWith('/');
      });
    });

    it('redirects to the path specified in the first parameter', function() {
      inject(function($location) {
        spyOn($location, 'path');
        service.logout('/other/path');
        $httpBackend.flush();
        expect($location.path).toHaveBeenCalledWith('/other/path');
      });
    });
  });

  describe("currentUser", function() {

    it("should be unauthenticated to begin with", function() {
      expect(service.isAuthenticated()).toBe(false);
      expect(service.isAdmin()).toBe(false);
      expect(service.currentUser).toBe(null);
    });
    it("should be authenticated if we update with user info", function() {
      var userInfo = {};
      service.currentUser = userInfo;
      expect(service.isAuthenticated()).toBe(true);
      expect(service.isAdmin()).toBe(false);
      expect(service.currentUser).toBe(userInfo);
    });
    it("should be admin if we update with admin user info", function() {
      var userInfo = { admin: true };
      service.currentUser = userInfo;
      expect(service.isAuthenticated()).toBe(true);
      expect(service.isAdmin()).toBe(true);
      expect(service.currentUser).toBe(userInfo);
    });

    it("should not be authenticated or admin if we clear the user", function() {
      var userInfo = { admin: true };
      service.currentUser = userInfo;
      expect(service.isAuthenticated()).toBe(true);
      expect(service.isAdmin()).toBe(true);
      expect(service.currentUser).toBe(userInfo);

      service.currentUser = null;
      expect(service.isAuthenticated()).toBe(false);
      expect(service.isAdmin()).toBe(false);
      expect(service.currentUser).toBe(null);
    });
  });

  describe('requestCurrentUser', function() {
    it('makes a GET request to current-user url', function() {
      expect(service.isAuthenticated()).toBe(false);
      $httpBackend.expect('GET', '/current-user');
      service.requestCurrentUser().then(function(data) {
        resolved = true;
        expect(service.isAuthenticated()).toBe(true);
        expect(service.currentUser).toBe(userInfo);
      });
      $httpBackend.flush();
      expect(resolved).toBe(true);
    });
    it('returns the current user immediately if they are already authenticated', function() {
      userInfo = {};
      service.currentUser = userInfo;
      expect(service.isAuthenticated()).toBe(true);
      service.requestCurrentUser().then(function(data) {
        resolved = true;
        expect(service.currentUser).toBe(userInfo);
      });
      expect(resolved).toBe(true);
    });
  });

});<|endoftext|>


<commit_before>import React from 'react';
import ClipboardJS from 'clipboard';
import 'balloon-css/balloon.css';

export default class CopyButton extends React.PureComponent {
  constructor(props) {
    super(props);
    this.copyBtnRef = React.createRef();
    this.clipboardRef = React.createRef();
  }

  static defaultProps = {
    content: '',
  };
  state = {
    tooltipAttrs: {},
  };

  componentDidMount() {
    this.clipboardRef.current = new ClipboardJS(this.copyBtnRef.current, {
      text: () => this.props.content,
    });
    this.clipboardRef.current.on('success', () => {
      const self = this;
      this.setState({
        tooltipAttrs: {
          'data-balloon': '複製成功！',
          'data-balloon-visible': '',
          'data-balloon-pos': 'up',
        }});

      setTimeout(function() {
        self.setState({ tooltipAttrs: {} });
      }, 1000);
    });
  }

  render() {
    return (
      <button
        ref={this.copyBtnRef}
        key="copy"
        onClick={() => {}}
        className="btn-copy"
        { ...this.state.tooltipAttrs }
      >
        複製到剪貼簿
        <style jsx>{`
          .btn-copy {
            margin-left: 10px;
          }
        `}</style>
      </button>
    );
  }
}
<commit_msg>Modify whitespaces according to ESLint, remove unused key and onClick<commit_after>import React from 'react';
import ClipboardJS from 'clipboard';
import 'balloon-css/balloon.css';

export default class CopyButton extends React.PureComponent {
  constructor(props) {
    super(props);
    this.copyBtnRef = React.createRef();
    this.clipboardRef = React.createRef();
  }

  static defaultProps = {
    content: '',
  };
  state = {
    tooltipAttrs: {},
  };

  componentDidMount() {
    this.clipboardRef.current = new ClipboardJS(this.copyBtnRef.current, {
      text: () => this.props.content,
    });
    this.clipboardRef.current.on('success', () => {
      const self = this;
      this.setState({
        tooltipAttrs: {
          'data-balloon': '複製成功！',
          'data-balloon-visible': '',
          'data-balloon-pos': 'up',
        },
      });

      setTimeout(function() {
        self.setState({ tooltipAttrs: {} });
      }, 1000);
    });
  }

  render() {
    const { tooltipAttrs } = this.state;
    return (
      <button
        ref={this.copyBtnRef}
        className="btn-copy"
        {...tooltipAttrs}
      >
        複製到剪貼簿
        <style jsx>{`
          .btn-copy {
            margin-left: 10px;
          }
        `}</style>
      </button>
    );
  }
}
<|endoftext|>


<commit_before>var Editor = Class.create(Renderer, {

  initialize: function($super, staticCanvas, dynamicCanvas, bufferCanvas, imageCanvas) {
    $super(staticCanvas, dynamicCanvas, bufferCanvas);

    this.imageCanvas = imageCanvas;

    this.baseToolbox = new Toolbox();
    this.baseToolbox.parent = this;
    this.baseToolbox.x = this.field.x + this.field.width + 3 * Brick.SIZE;
    this.baseToolbox.y = this.field.y;

    this.specialToolbox = new Toolbox();
    this.specialToolbox.parent = this;
    this.specialToolbox.x = this.baseToolbox.x + this.baseToolbox.width + Brick.SIZE;
    this.specialToolbox.y = this.baseToolbox.y;

    this.setSize();

    this.addEventListening();
    this.addBricksToToolboxes();

    this.dragElement = this.hoverElement = this.selectElement = null;

    this.initializeHTMLInterface();

    // this.baseToolbox.onClick(1.5 * Brick.SIZE, 3.5 * Brick.SIZE);
  },

  destroy: function($super) {
    $super();

    $('runButton').stopObserving();
    $('clearButton').stopObserving();
    $('publishButton').stopObserving();

    this.eventEngine.removeListener("click", this.onClick);
    this.eventEngine.removeListener("mouseMove", this.onMouseMove);

    this.eventEngine.removeListener("startDrag", this.onStartDrag);
    this.eventEngine.removeListener("stopDrag", this.onStopDrag);
  },

  setSize: function() {

    var width = this.specialToolbox.x + this.specialToolbox.width + 3,
        height = this.field.y + this.field.height + Brick.SIZE;

    this.width = this.staticCanvas.width = this.dynamicCanvas.width = this.bufferCanvas.width = width;
    this.height = this.staticCanvas.height = this.dynamicCanvas.height = this.bufferCanvas.height = height;

  },

  addEventListening: function() {

    this.eventEngine = new EventEngine();

    this.eventEngine.addListener("click", this.onClick, this);
    this.eventEngine.addListener("mouseMove", this.onMouseMove, this);

    this.eventEngine.addListener("startDrag", this.onStartDrag, this);
    this.eventEngine.addListener("stopDrag", this.onStopDrag, this);

  },

  addBricksToToolboxes: function() {

    var baseBricks = [Brick, Ramp, Kicker, Curve, Line],
      i;

    for (i = 0; i < baseBricks.length; i++) {
      this.baseToolbox.addBrick(baseBricks[i]);
    }

    var that = this;

    var request = new Ajax.Request('/unlocks', {
      method: 'get',
      requestHeaders: {Accept: 'application/json'},

      onSuccess: function(transport) {
        for (i = 5; i < transport.responseJSON.unlocks.length; i++) {
          that.specialToolbox.addBrick(eval(transport.responseJSON.unlocks[i]));
        }
      },

      onFailure: function(transport) {
        console.log("AjaxError on loading unlocks!");
      }
    });
  },

  initializeHTMLInterface: function($super) {
    var myScope = this;

    $('runButton').observe('click', function(event) {
      myScope.field.startBox2D();
    });

    $('clearButton').observe('click', function(event) {
      myScope.field.clearTrack(true);
    });

    $('publishButton').observe('click', function(event) {
      if ($('publishButton').hasClassName('activePublish') && myScope.field.validTrack) {

        myScope.publishTrack();
        $('publishButtonWarning').style.visibility = "hidden";

      } else {

        $('publishButtonWarning').style.visibility = "visible";

      }
    });
  },

  drawStatics: function() {

    if (this.field.renderNew ||
      this.baseToolbox.renderNew || this.specialToolbox.renderNew) {

        this.clearCanvas(this.staticCanvas);

        this.staticContext.save();

          this.staticContext.translate(0.5, 0.5);

          this.field.drawStatics(this.staticContext);

          this.baseToolbox.drawStatics(this.staticContext);
          this.specialToolbox.drawStatics(this.staticContext);

          // this.staticImageData = this.staticContext.getImageData(0, 0, this.staticCanvas.width, this.staticCanvas.height);

        this.staticContext.restore();
    }
  },

  drawDynamics: function() {

    this.dynamicContext.save();

      this.dynamicContext.clearRectangles();

      this.dynamicContext.translate(0.5, 0.5);

      this.field.drawDynamics(this.dynamicContext);

      this.baseToolbox.drawDynamics(this.dynamicContext);
      this.specialToolbox.drawDynamics(this.dynamicContext);

      if (this.hoverElement) {

        this.dynamicContext.save();

          this.dynamicContext.fillStyle = "#333333";
          this.dynamicContext.globalAlpha = 0.15;

          this.hoverElement.draw(this.dynamicContext);

        this.dynamicContext.restore();

      }

      if (this.selectElement) {

        this.dynamicContext.save();

          this.dynamicContext.fillStyle = "#800000";
          this.dynamicContext.globalAlpha = 0.3;

          this.selectElement.draw(this.dynamicContext);

        this.dynamicContext.restore();

      }

      if (this.field.debugMode) {

        this.field.draw(this.dynamicContext);

      }

      if (this.dragElement) {

        this.dynamicContext.drawShadows = true;

        this.dragElement.drawGlobal(this.dynamicContext);

        this.dynamicContext.drawShadows = false;

      }

    this.dynamicContext.restore();
  },

  onClick: function(event) {

    if (this.field.hitTest(event.mouseX, event.mouseY)) {

      if (!this.field.intervalID) {

        this.field.onClick(event.mouseX - this.field.x, event.mouseY - this.field.y);

      }

      this.field.resetTrack();

    } else if (this.baseToolbox.hitTest(event.mouseX, event.mouseY)) {

      this.baseToolbox.onClick(event.mouseX - this.baseToolbox.x, event.mouseY - this.baseToolbox.y);

    } else if (this.specialToolbox.hitTest(event.mouseX, event.mouseY)) {

      this.specialToolbox.onClick(event.mouseX - this.specialToolbox.x, event.mouseY - this.specialToolbox.y);

    }
  },

  onMouseMove: function(event) {

    this.hoverElement = null;

    if (this.field.hitTest(event.mouseX, event.mouseY)) {

      this.hoverElement = this.getCellBox(this.field, event.mouseX, event.mouseY);

    } else if (this.baseToolbox.hitTest(event.mouseX, event.mouseY)) {

      this.hoverElement = this.getCellBox(this.baseToolbox, event.mouseX, event.mouseY);

    } else if (this.specialToolbox.hitTest(event.mouseX, event.mouseY)) {

      this.hoverElement = this.getCellBox(this.specialToolbox, event.mouseX, event.mouseY);

    }
  },

  getCellBox: function(grid, mouseX, mouseY) {
    return grid.getCellBox(
      grid.getCell(
        mouseX - grid.x,
        mouseY - grid.y
      )
    );
  },

  onStartDrag: function(event) {

    this.field.resetTrack();

    if (this.field.hitTest(event.mouseX, event.mouseY)) {

      this.field.resetTrack();
      this.field.onStartDrag(event.mouseX - this.field.x, event.mouseY - this.field.y);

    } else if (this.baseToolbox.hitTest(event.mouseX, event.mouseY)) {

      this.baseToolbox.onStartDrag(event.mouseX - this.baseToolbox.x, event.mouseY - this.baseToolbox.y);

    } else if (this.specialToolbox.hitTest(event.mouseX, event.mouseY)) {

      this.specialToolbox.onStartDrag(event.mouseX - this.specialToolbox.x, event.mouseY - this.specialToolbox.y);

    }
  },

  onDrag: function(event) {

    if (this.dragElement && event.mouseX && event.mouseY) {

      this.dragElement.x = parseInt(event.mouseX - Brick.SIZE / 2, 10);
      this.dragElement.y = parseInt(event.mouseY - Brick.SIZE / 2, 10);

    }
  },

  dragBrick: function(brick) {

    var point = {x: this.eventEngine.latestEvent.mouseX, y: this.eventEngine.latestEvent.mouseY};

    brick.x = point.x - Brick.BIG_SIZE / 2;
    brick.y = point.y - Brick.BIG_SIZE / 2;

    this.dragElement = brick;

    this.eventEngine.addListener("drag", this.onDrag, this);
  },

  startDragBricking: function() {

    this.eventEngine.addListener("drag", this.onDragBricking, this);

  },

  onDragBricking: function(event) {

    if (this.field.hitTest(event.mouseX, event.mouseY)) {

      this.field.onDrag(event.mouseX - this.field.x, event.mouseY - this.field.y);

    }

  },

  onStopDrag: function(event) {

    if (this.dragElement) {

      this.field.onStopDrag(event, this.dragElement);

      this.dragElement = null;

    }

    this.eventEngine.removeListener("drag", this.onDragBricking);
    this.eventEngine.removeListener("drag", this.onDrag);
  },

  publishTrack: function() {

    if (this.field.validTrack) {

      contentLoader.parseResponse({responseJSON: {mode: "load"}});

      var parameters = {},
          length = this.field.trackLength;

      parameters['track[json]'] = Object.toJSON(this.field.getTrack());
      parameters['track[length]'] = length;
      parameters['track[imagedata]'] = this.field.getTrackImage(this.imageCanvas);
      parameters['track[username]'] = $('userName').value;
      parameters['track[trackname]'] = $('trackName').value;

      var request = new Ajax.Request('/tracks', {
        method: 'post',
        parameters: parameters,
        requestHeaders: {Accept: 'application/json'},

        onSuccess: function(transport) {
          contentLoader.parseResponse(transport, true);
        },

        onFailure: function(transport) {
          contentLoader.parseResponse(transport, false);
        }
      });
    }
  }

});<commit_msg>editor getting unlocks for preview<commit_after>var Editor = Class.create(Renderer, {

  initialize: function($super, staticCanvas, dynamicCanvas, bufferCanvas, imageCanvas) {
    $super(staticCanvas, dynamicCanvas, bufferCanvas);

    this.imageCanvas = imageCanvas;

    this.baseToolbox = new Toolbox();
    this.baseToolbox.parent = this;
    this.baseToolbox.x = this.field.x + this.field.width + 3 * Brick.SIZE;
    this.baseToolbox.y = this.field.y;

    this.specialToolbox = new Toolbox();
    this.specialToolbox.parent = this;
    this.specialToolbox.x = this.baseToolbox.x + this.baseToolbox.width + Brick.SIZE;
    this.specialToolbox.y = this.baseToolbox.y;

    this.setSize();

    this.addEventListening();
    this.addBricksToToolboxes();

    this.dragElement = this.hoverElement = this.selectElement = null;

    this.initializeHTMLInterface();

    // this.baseToolbox.onClick(1.5 * Brick.SIZE, 3.5 * Brick.SIZE);
  },

  destroy: function($super) {
    $super();

    $('runButton').stopObserving();
    $('clearButton').stopObserving();
    $('publishButton').stopObserving();

    this.eventEngine.removeListener("click", this.onClick);
    this.eventEngine.removeListener("mouseMove", this.onMouseMove);

    this.eventEngine.removeListener("startDrag", this.onStartDrag);
    this.eventEngine.removeListener("stopDrag", this.onStopDrag);
  },

  setSize: function() {

    var width = this.specialToolbox.x + this.specialToolbox.width + 3,
        height = this.field.y + this.field.height + Brick.SIZE;

    this.width = this.staticCanvas.width = this.dynamicCanvas.width = this.bufferCanvas.width = width;
    this.height = this.staticCanvas.height = this.dynamicCanvas.height = this.bufferCanvas.height = height;

  },

  addEventListening: function() {

    this.eventEngine = new EventEngine();

    this.eventEngine.addListener("click", this.onClick, this);
    this.eventEngine.addListener("mouseMove", this.onMouseMove, this);

    this.eventEngine.addListener("startDrag", this.onStartDrag, this);
    this.eventEngine.addListener("stopDrag", this.onStopDrag, this);

  },

  addBricksToToolboxes: function() {

    var baseBricks = [Brick, Ramp, Kicker, Curve, Line],
      i;

    for (i = 0; i < baseBricks.length; i++) {
      this.baseToolbox.addBrick(baseBricks[i]);
    }

    var that = this;

    var request = new Ajax.Request('/unlocks', {
      method: 'get',
      requestHeaders: {Accept: 'application/json'},

      onSuccess: function(transport) {

        for (i = 5; i < transport.responseJSON.unlocks.length; i++) {
          that.specialToolbox.addBrick(eval(transport.responseJSON.unlocks[i]));
        }

        if (transport.responseJSON.locks) {
          that.specialToolbox.addPreviewBrick(eval(transport.responseJSON.locks[0]))
        }
      },

      onFailure: function(transport) {
        console.log("AjaxError on loading unlocks!");
      }
    });
  },

  initializeHTMLInterface: function($super) {
    var myScope = this;

    $('runButton').observe('click', function(event) {
      myScope.field.startBox2D();
    });

    $('clearButton').observe('click', function(event) {
      myScope.field.clearTrack(true);
    });

    $('publishButton').observe('click', function(event) {
      if ($('publishButton').hasClassName('activePublish') && myScope.field.validTrack) {

        myScope.publishTrack();
        $('publishButtonWarning').style.visibility = "hidden";

      } else {

        $('publishButtonWarning').style.visibility = "visible";

      }
    });
  },

  drawStatics: function() {

    if (this.field.renderNew ||
      this.baseToolbox.renderNew || this.specialToolbox.renderNew) {

        this.clearCanvas(this.staticCanvas);

        this.staticContext.save();

          this.staticContext.translate(0.5, 0.5);

          this.field.drawStatics(this.staticContext);

          this.baseToolbox.drawStatics(this.staticContext);
          this.specialToolbox.drawStatics(this.staticContext);

          // this.staticImageData = this.staticContext.getImageData(0, 0, this.staticCanvas.width, this.staticCanvas.height);

        this.staticContext.restore();
    }
  },

  drawDynamics: function() {

    this.dynamicContext.save();

      this.dynamicContext.clearRectangles();

      this.dynamicContext.translate(0.5, 0.5);

      this.field.drawDynamics(this.dynamicContext);

      this.baseToolbox.drawDynamics(this.dynamicContext);
      this.specialToolbox.drawDynamics(this.dynamicContext);

      if (this.hoverElement) {

        this.dynamicContext.save();

          this.dynamicContext.fillStyle = "#333333";
          this.dynamicContext.globalAlpha = 0.15;

          this.hoverElement.draw(this.dynamicContext);

        this.dynamicContext.restore();

      }

      if (this.selectElement) {

        this.dynamicContext.save();

          this.dynamicContext.fillStyle = "#800000";
          this.dynamicContext.globalAlpha = 0.3;

          this.selectElement.draw(this.dynamicContext);

        this.dynamicContext.restore();

      }

      if (this.field.debugMode) {

        this.field.draw(this.dynamicContext);

      }

      if (this.dragElement) {

        this.dynamicContext.drawShadows = true;

        this.dragElement.drawGlobal(this.dynamicContext);

        this.dynamicContext.drawShadows = false;

      }

    this.dynamicContext.restore();
  },

  onClick: function(event) {

    if (this.field.hitTest(event.mouseX, event.mouseY)) {

      if (!this.field.intervalID) {

        this.field.onClick(event.mouseX - this.field.x, event.mouseY - this.field.y);

      }

      this.field.resetTrack();

    } else if (this.baseToolbox.hitTest(event.mouseX, event.mouseY)) {

      this.baseToolbox.onClick(event.mouseX - this.baseToolbox.x, event.mouseY - this.baseToolbox.y);

    } else if (this.specialToolbox.hitTest(event.mouseX, event.mouseY)) {

      this.specialToolbox.onClick(event.mouseX - this.specialToolbox.x, event.mouseY - this.specialToolbox.y);

    }
  },

  onMouseMove: function(event) {

    this.hoverElement = null;

    if (this.field.hitTest(event.mouseX, event.mouseY)) {

      this.hoverElement = this.getCellBox(this.field, event.mouseX, event.mouseY);

    } else if (this.baseToolbox.hitTest(event.mouseX, event.mouseY)) {

      this.hoverElement = this.getCellBox(this.baseToolbox, event.mouseX, event.mouseY);

    } else if (this.specialToolbox.hitTest(event.mouseX, event.mouseY)) {

      this.hoverElement = this.getCellBox(this.specialToolbox, event.mouseX, event.mouseY);

    }
  },

  getCellBox: function(grid, mouseX, mouseY) {
    return grid.getCellBox(
      grid.getCell(
        mouseX - grid.x,
        mouseY - grid.y
      )
    );
  },

  onStartDrag: function(event) {

    this.field.resetTrack();

    if (this.field.hitTest(event.mouseX, event.mouseY)) {

      this.field.resetTrack();
      this.field.onStartDrag(event.mouseX - this.field.x, event.mouseY - this.field.y);

    } else if (this.baseToolbox.hitTest(event.mouseX, event.mouseY)) {

      this.baseToolbox.onStartDrag(event.mouseX - this.baseToolbox.x, event.mouseY - this.baseToolbox.y);

    } else if (this.specialToolbox.hitTest(event.mouseX, event.mouseY)) {

      this.specialToolbox.onStartDrag(event.mouseX - this.specialToolbox.x, event.mouseY - this.specialToolbox.y);

    }
  },

  onDrag: function(event) {

    if (this.dragElement && event.mouseX && event.mouseY) {

      this.dragElement.x = parseInt(event.mouseX - Brick.SIZE / 2, 10);
      this.dragElement.y = parseInt(event.mouseY - Brick.SIZE / 2, 10);

    }
  },

  dragBrick: function(brick) {

    var point = {x: this.eventEngine.latestEvent.mouseX, y: this.eventEngine.latestEvent.mouseY};

    brick.x = point.x - Brick.BIG_SIZE / 2;
    brick.y = point.y - Brick.BIG_SIZE / 2;

    this.dragElement = brick;

    this.eventEngine.addListener("drag", this.onDrag, this);
  },

  startDragBricking: function() {

    this.eventEngine.addListener("drag", this.onDragBricking, this);

  },

  onDragBricking: function(event) {

    if (this.field.hitTest(event.mouseX, event.mouseY)) {

      this.field.onDrag(event.mouseX - this.field.x, event.mouseY - this.field.y);

    }

  },

  onStopDrag: function(event) {

    if (this.dragElement) {

      this.field.onStopDrag(event, this.dragElement);

      this.dragElement = null;

    }

    this.eventEngine.removeListener("drag", this.onDragBricking);
    this.eventEngine.removeListener("drag", this.onDrag);
  },

  publishTrack: function() {

    if (this.field.validTrack) {

      contentLoader.parseResponse({responseJSON: {mode: "load"}});

      var parameters = {},
          length = this.field.trackLength;

      parameters['track[json]'] = Object.toJSON(this.field.getTrack());
      parameters['track[length]'] = length;
      parameters['track[imagedata]'] = this.field.getTrackImage(this.imageCanvas);
      parameters['track[username]'] = $('userName').value;
      parameters['track[trackname]'] = $('trackName').value;

      var request = new Ajax.Request('/tracks', {
        method: 'post',
        parameters: parameters,
        requestHeaders: {Accept: 'application/json'},

        onSuccess: function(transport) {
          contentLoader.parseResponse(transport, true);
        },

        onFailure: function(transport) {
          contentLoader.parseResponse(transport, false);
        }
      });
    }
  }

});<|endoftext|>


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

/**
 * @fileoverview Definitions for ECMAScript 5.
 * @see http://www.ecma-international.org/publications/files/drafts/tc39-2009-025.pdf
 * @externs
 */

/**
 * @param {Object} selfObj Specifies the object to which |this| should point
 *     when the function is run. If the value is null or undefined, it will
 *     default to the global object.
 * @param {...*} var_args Additional arguments that are partially
 *     applied to fn.
 * @return {!Function} A partially-applied form of the Function on which
 *     bind() was invoked as a method.
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
 */
Function.prototype.bind = function(selfObj, var_args) {};

/**
 * @return {string}
 * @nosideeffects
 * @see http://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/Trim
 */
String.prototype.trim = function() {};

/**
 * @return {string}
 * @nosideeffects
 * @see http://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/TrimLeft
 */
String.prototype.trimLeft = function() {};

/**
 * @return {string}
 * @nosideeffects
 * @see http://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/TrimRight
 */
String.prototype.trimRight = function() {};

/**
 * A object property descriptor used by Object.create, Object.defineProperty,
 * Object.defineProperties, Object.getOwnPropertyDescriptor.
 *
 * Note: not a real constructor.
 * @constructor
 */
var ObjectPropertyDescriptor = function(){};

/** @type {*} */
ObjectPropertyDescriptor.prototype.value;

/** @type {(function():?)||undefined} */
ObjectPropertyDescriptor.prototype.get;

/** @type {(function(?):void)||undefined} */
ObjectPropertyDescriptor.prototype.set;

/** @type {boolean|undefined} */
ObjectPropertyDescriptor.prototype.writable;

/** @type {boolean|undefined} */
ObjectPropertyDescriptor.prototype.enumerable;

/** @type {boolean|undefined} */
ObjectPropertyDescriptor.prototype.configurable;

/**
 * @param {Object} proto
 * @param {Object=} opt_properties  A map of ObjectPropertyDescriptors.
 * @return {!Object}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create
 */
Object.create = function(proto, opt_properties) {};

/**
 * @param {!Object} obj
 * @param {string} prop
 * @param {!Object} descriptor A ObjectPropertyDescriptor.
 * @return {!Object}
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty
 */
Object.defineProperty = function(obj, prop, descriptor) {};

/**
 * @param {!Object} obj
 * @param {!Object} props A map of ObjectPropertyDescriptors.
 * @return {!Object}
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperties
 */
Object.defineProperties = function(obj, props) {};

/**
 * @param {!Object} obj
 * @param {string} prop
 * @return {Object.<ObjectPropertyDescriptor>}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor
 */
Object.getOwnPropertyDescriptor = function(obj, prop) {};

/**
 * @param {!Object} obj
 * @return {Array.<string>}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys
 */
Object.keys = function(obj) {};

/**
 * @param {!Object} obj
 * @return {Array.<string>}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames
 */
Object.getOwnPropertyNames = function(obj) {};

/**
 * @param {!Object} obj
 * @return {Object}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/GetPrototypeOf
 */
Object.getPrototypeOf = function(obj) {};

/**
 * @param {!T} obj
 * @return {!T}
 * @template T
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/preventExtensions
 */
Object.preventExtensions = function(obj) {};

/**
 * @param {!T} obj
 * @return {!T}
 * @template T
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/seal
 */
Object.seal = function(obj) {};

/**
 * @param {!T} obj
 * @return {!T}
 * @template T
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/freeze
 */
Object.freeze = function(obj) {};

/**
 * @param {!Object} obj
 * @return {boolean}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/isExtensible
 */
Object.isExtensible = function(obj) {};

/**
 * @param {!Object} obj
 * @return {boolean}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/isSealed
 */
Object.isSealed = function(obj) {};

/**
 * @param {!Object} obj
 * @return {boolean}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/isFrozen
 */
Object.isFrozen = function(obj) {};

/**
 * As per ECMAScript 5, 15.12.3.
 * @param {string=} opt_key The JSON key for this object.
 * @return {*} The serializable representation of this object. Note that this
 *     need not be a string. See http://goo.gl/PEUvs.
 */
Object.prototype.toJSON = function(opt_key) {};

/**
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/toISOString
 * @return {string}
 */
Date.prototype.toISOString = function() {};

/**
 * @param {*=} opt_ignoredKey
 * @return {string}
 * @override
 */
Date.prototype.toJSON = function(opt_ignoredKey) {};
<commit_msg><commit_after>/*
 * Copyright 2009 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Definitions for ECMAScript 5.
 * @see http://www.ecma-international.org/publications/files/drafts/tc39-2009-025.pdf
 * @externs
 */

/**
 * @param {Object} selfObj Specifies the object to which |this| should point
 *     when the function is run. If the value is null or undefined, it will
 *     default to the global object.
 * @param {...*} var_args Additional arguments that are partially
 *     applied to fn.
 * @return {!Function} A partially-applied form of the Function on which
 *     bind() was invoked as a method.
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
 */
Function.prototype.bind = function(selfObj, var_args) {};

/**
 * @return {string}
 * @nosideeffects
 * @see http://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/Trim
 */
String.prototype.trim = function() {};

/**
 * @return {string}
 * @nosideeffects
 * @see http://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/TrimLeft
 */
String.prototype.trimLeft = function() {};

/**
 * @return {string}
 * @nosideeffects
 * @see http://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/TrimRight
 */
String.prototype.trimRight = function() {};

/**
 * A object property descriptor used by Object.create, Object.defineProperty,
 * Object.defineProperties, Object.getOwnPropertyDescriptor.
 *
 * Note: not a real constructor.
 * @constructor
 */
var ObjectPropertyDescriptor = function(){};

/** @type {*} */
ObjectPropertyDescriptor.prototype.value;

/** @type {(function():?)||undefined} */
ObjectPropertyDescriptor.prototype.get;

/** @type {(function(?):void)||undefined} */
ObjectPropertyDescriptor.prototype.set;

/** @type {boolean|undefined} */
ObjectPropertyDescriptor.prototype.writable;

/** @type {boolean|undefined} */
ObjectPropertyDescriptor.prototype.enumerable;

/** @type {boolean|undefined} */
ObjectPropertyDescriptor.prototype.configurable;

/**
 * @param {Object} proto
 * @param {Object=} opt_properties  A map of ObjectPropertyDescriptors.
 * @return {!Object}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create
 */
Object.create = function(proto, opt_properties) {};

/**
 * @param {!Object} obj
 * @param {string} prop
 * @param {!Object} descriptor A ObjectPropertyDescriptor.
 * @return {!Object}
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty
 */
Object.defineProperty = function(obj, prop, descriptor) {};

/**
 * @param {!Object} obj
 * @param {!Object} props A map of ObjectPropertyDescriptors.
 * @return {!Object}
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperties
 */
Object.defineProperties = function(obj, props) {};

/**
 * @param {!Object} obj
 * @param {string} prop
 * @return {Object.<ObjectPropertyDescriptor>}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor
 */
Object.getOwnPropertyDescriptor = function(obj, prop) {};

/**
 * @param {!Object} obj
 * @return {Array.<string>}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys
 */
Object.keys = function(obj) {};

/**
 * @param {!Object} obj
 * @return {Array.<string>}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames
 */
Object.getOwnPropertyNames = function(obj) {};

/**
 * @param {!Object} obj
 * @return {Object}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/GetPrototypeOf
 */
Object.getPrototypeOf = function(obj) {};

/**
 * @param {!Object} obj
 * @return {void}
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/preventExtensions
 */
Object.preventExtensions = function(obj) {};

/**
 * @param {!Object} obj
 * @return {void}
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/seal
 */
Object.seal = function(obj) {};

/**
 * @param {!Object} obj
 * @return {void}
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/freeze
 */
Object.freeze = function(obj) {};

/**
 * @param {!Object} obj
 * @return {boolean}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/isExtensible
 */
Object.isExtensible = function(obj) {};

/**
 * @param {!Object} obj
 * @return {boolean}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/isSealed
 */
Object.isSealed = function(obj) {};

/**
 * @param {!Object} obj
 * @return {boolean}
 * @nosideeffects
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/isFrozen
 */
Object.isFrozen = function(obj) {};

/**
 * As per ECMAScript 5, 15.12.3.
 * @param {string=} opt_key The JSON key for this object.
 * @return {*} The serializable representation of this object. Note that this
 *     need not be a string. See http://goo.gl/PEUvs.
 */
Object.prototype.toJSON = function(opt_key) {};

/**
 * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/toISOString
 * @return {string}
 */
Date.prototype.toISOString = function() {};

/**
 * @param {*=} opt_ignoredKey
 * @return {string}
 * @override
 */
Date.prototype.toJSON = function(opt_ignoredKey) {};
<|endoftext|>


<commit_before>var fs = require('fs')
	, path = require('path')
	, mkdirp = require('mkdirp')
	, rimraf = require('rimraf');

// Node 0.8.0 api change
var existsSync = exports.existsSync = fs.existsSync || path.existsSync;
var exists = exports.exists = fs.exists || path.exists;

// starts with '.' or '~', ends with '~'
exports.re_hidden = /^[\.~]|~$/;

/**
 * Check that a 'filepath' is likely a child of a given directory
 * Applies to nested directories
 * Only makes String comparison. Does not check for existance
 * @param {String} dir
 * @param {String} filepath
 * @returns {Boolean}
 */
exports.indir = function(dir, filepath) {
	dir = path.resolve(dir);
	filepath = path.resolve(filepath);
	if (filepath.indexOf(dir) != -1) {
		if (path.relative(dir, filepath).indexOf('..') != -1) {
			return false;
		} else {
			return true;
		}
	} else {
		return false;
	}
};

/**
 * Read and store the contents of a directory, ignoring files of type specified
 * @param {String} dir
 * @param {Regex} include
 * @param {Regex} ignore
 * @param {Function} fn(err, files, directories)
 */
var readdir = exports.readdir = function(dir, include, ignore, fn) {
	var _files = []
		, _directories = []
		, _outstanding = 0
		, _readdir;
	if (!include) include = /.*/;
	if (!ignore) ignore = exports.re_hidden;

	// Inner function
	_readdir = function(dir) {
		if (existsSync(dir)) {
			_directories.push(dir);
			_outstanding++;
			return fs.readdir(dir, function(err, files) {
				_outstanding--;
				if (err) return fn(err);
				files.forEach(function(file) {
					// Skip ignored files
					if (include.test(path.basename(file)) && !ignore.test(path.basename(file))) {
						var filepath = path.resolve(dir, file);
						_outstanding++;
						return fs.stat(filepath, function(err, stats) {
							_outstanding--;
							if (err) {
								// Exit if proper error, otherwise skip
								if (err.code === 'ENOENT') return;
								else return fn(err);
							} else {
								// Recurse child directory
								if (stats.isDirectory()) {
									return _readdir(filepath);
								} else {
									// Store
									_files.push(filepath);
									// Return if no outstanding
									if (!_outstanding) return fn(null, _files, _directories);
								}
							}
						});
					}
				});
				// Return if no outstanding
				if (!_outstanding) return fn(null, _files, _directories);
			});
		// Return if no outstanding
		} else if (!_outstanding) return fn(null, _files, _directories);
	};
	return _readdir(dir);
};

/**
 * Recursively create directory path specified by 'filepath'
 * @param {String} filepath
 * @param {Function} fn(err)
 */
var mkdir = exports.mkdir = function(filepath, fn) {
	// Resolve directory name if passed a file
	var dir = path.extname(filepath)
		? path.dirname(filepath)
		: filepath;
	if (!existsSync(dir)) {
		mkdirp(dir, function(err) {
			if (err) return fn(err);
			else return fn();
		});
	} else {
		return fn();
	}
};

/**
 * Move file or directory 'source' to 'destination'
 * @param {String} source
 * @param {String} destination
 * @param {Boolean} force
 * @param {Function} fn(err, filepath)
 */
var mv = exports.mv = function(source, destination, force, fn) {
	if (force == null) force = false;
	mkdir(destination, function(err) {
		if (err) {
			return fn(err);
		} else {
			var filepath = path.resolve(destination, path.basename(source));
			if (!force && existsSync(filepath)) {
				return fn(null, filepath);
			} else {
				rm(filepath, function(err) {
					// Ignore rm errors
					fs.rename(source, filepath, function(err) {
						if (err) return fn(err);
						else return fn(null, filepath);
					});
				});
			}
		}
	});
};

/**
 * Copy file or directory 'source' to 'destination'
 * Copies contents of 'source' if directory and ends in trailing '/'
 * @param {String} source
 * @param {String} destination
 * @param {Boolean} force
 * @param {Function} fn(err, filepath)
 */
var cp = exports.cp = function(source, destination, force, fn) {
	var _base = ''
		, _filepath = ''
		, _first = true
		, _outstanding = 0
		, _cp;
	if (force == null) force = false;
	// Inner function
	_cp = function(source, destination) {
		_outstanding++;
		fs.stat(source, function(err, stats) {
			var isDestFile;
			_outstanding--;
			// Exit if proper error, otherwise skip
			if (err) {
				if (err.code === 'ENOENT') return;
				else return fn(err);
			} else {
				isDestFile = path.extname(destination).length;
				// File
				if (stats.isFile()) {
					// Handle file or directory as destination
					var destDir = isDestFile ? path.dirname(destination) : destination
						, destName = isDestFile ? path.basename(destination) : path.basename(source)
						, filepath = path.resolve(destDir, destName);
					// Write file if it doesn't already exist
					if (!force && existsSync(filepath)) {
						if (!_outstanding) return fn(null, _filepath);
					} else {
						rm(filepath, function(err) {
							// Ignore rm errors
							var file;
							_outstanding++;
							// Return the new path for the first source
							if (_first) {
								_filepath = filepath;
								_first = false;
							}
							// Pipe stream
							fs.createReadStream(source).pipe(file = fs.createWriteStream(filepath));
							file.on('error', function(err) { return fn(err); });
							file.on('close', function() {
								_outstanding--;
								// Return if no outstanding
								if (!_outstanding) return fn(null, _filepath);
							});
						});
					}
				// Directory
				} else {
					// Guard against invalid directory to file copy
					if (isDestFile) {
						fn(new Error('invalid destination for copy: ' + destination));
					} else {
						// Copy contents only if source ends in '/'
						var contentsOnly = _first && /\\$|\/$/.test(source)
							, dest = contentsOnly ? destination : path.resolve(destination, path.basename(source));
						// Create in destination
						_outstanding++;
						mkdir(dest, function(err) {
							_outstanding--;
							if (err) {
								return fn(err);
							} else {
								// Loop through contents
								_outstanding++;
								fs.readdir(source, function(err, files) {
									_outstanding--;
									// Exit if proper error, otherwise skip
									if (err) {
										if (err.code === 'ENOENT') return;
										else return fn(err);
									} else {
										// Return the new path for the first source
										if (_first) {
											_filepath = dest;
											_first = false;
										}
										// Loop through files and cp
										files.forEach(function(file) {
											_cp(path.resolve(source, file), dest);
										});
										// Return if no outstanding
										if (!_outstanding) return fn(null, _filepath);
									}
								});
							}
						});
					}
				}
			}
		});
		// Return if no outstanding
		if (!_outstanding) return fn(null, _filepath);
	};
	return _cp(source, destination);
};

/**
 * Recursive remove file or directory
 * Makes sure only project sources are removed
 * @param {String} source
 * @param {Function} fn(err)
 */
var rm = exports.rm = function(source, fn) {
	if (existsSync(source)) {
		if (source.indexOf(process.cwd()) != -1) {
			rimraf(source, function(err) {
				if (err) return fn(err);
				else return fn();
			});
		} else {
			fn(new Error('cannot rm source outside of project path: ' + source));
		}
	} else {
		fn(new Error('cannot rm non-existant source: ' + source));
	}
};
<commit_msg>fix for ignore file rule excluding directories<commit_after>var fs = require('fs')
	, path = require('path')
	, mkdirp = require('mkdirp')
	, rimraf = require('rimraf');

// Node 0.8.0 api change
var existsSync = exports.existsSync = fs.existsSync || path.existsSync;
var exists = exports.exists = fs.exists || path.exists;

// starts with '.' or '~', ends with '~'
exports.re_hidden = /^[\.~]|~$/;

/**
 * Check that a 'filepath' is likely a child of a given directory
 * Applies to nested directories
 * Only makes String comparison. Does not check for existance
 * @param {String} dir
 * @param {String} filepath
 * @returns {Boolean}
 */
exports.indir = function(dir, filepath) {
	dir = path.resolve(dir);
	filepath = path.resolve(filepath);
	if (filepath.indexOf(dir) != -1) {
		if (path.relative(dir, filepath).indexOf('..') != -1) {
			return false;
		} else {
			return true;
		}
	} else {
		return false;
	}
};

/**
 * Read and store the contents of a directory, ignoring files of type specified
 * @param {String} dir
 * @param {Regex} include
 * @param {Regex} ignore
 * @param {Function} fn(err, files, directories)
 */
var readdir = exports.readdir = function(dir, include, ignore, fn) {
	var _files = []
		, _directories = []
		, _outstanding = 0
		, _readdir;
	if (!include) include = /.*/;
	if (!ignore) ignore = exports.re_hidden;

	// Inner function
	_readdir = function(dir) {
		if (existsSync(dir)) {
			_directories.push(dir);
			_outstanding++;
			return fs.readdir(dir, function(err, files) {
				_outstanding--;
				if (err) return fn(err);
				files.forEach(function(file) {
					var filepath = path.resolve(dir, file);
					_outstanding++;
					return fs.stat(filepath, function(err, stats) {
						_outstanding--;
						if (err) {
							// Exit if proper error, otherwise skip
							if (err.code === 'ENOENT') return;
							else return fn(err);
						} else {
							// Recurse child directory
							if (stats.isDirectory()) {
								return _readdir(filepath);
							} else {
								// Store if not ignored
								if (include.test(path.basename(filepath)) && !ignore.test(path.basename(filepath))) {
									_files.push(filepath);
								}
								// Return if no outstanding
								if (!_outstanding) return fn(null, _files, _directories);
							}
						}
					});
				});
				// Return if no outstanding
				if (!_outstanding) return fn(null, _files, _directories);
			});
		// Return if no outstanding
		} else if (!_outstanding) return fn(null, _files, _directories);
	};
	return _readdir(dir);
};

/**
 * Recursively create directory path specified by 'filepath'
 * @param {String} filepath
 * @param {Function} fn(err)
 */
var mkdir = exports.mkdir = function(filepath, fn) {
	// Resolve directory name if passed a file
	var dir = path.extname(filepath)
		? path.dirname(filepath)
		: filepath;
	if (!existsSync(dir)) {
		mkdirp(dir, function(err) {
			if (err) return fn(err);
			else return fn();
		});
	} else {
		return fn();
	}
};

/**
 * Move file or directory 'source' to 'destination'
 * @param {String} source
 * @param {String} destination
 * @param {Boolean} force
 * @param {Function} fn(err, filepath)
 */
var mv = exports.mv = function(source, destination, force, fn) {
	if (force == null) force = false;
	mkdir(destination, function(err) {
		if (err) {
			return fn(err);
		} else {
			var filepath = path.resolve(destination, path.basename(source));
			if (!force && existsSync(filepath)) {
				return fn(null, filepath);
			} else {
				rm(filepath, function(err) {
					// Ignore rm errors
					fs.rename(source, filepath, function(err) {
						if (err) return fn(err);
						else return fn(null, filepath);
					});
				});
			}
		}
	});
};

/**
 * Copy file or directory 'source' to 'destination'
 * Copies contents of 'source' if directory and ends in trailing '/'
 * @param {String} source
 * @param {String} destination
 * @param {Boolean} force
 * @param {Function} fn(err, filepath)
 */
var cp = exports.cp = function(source, destination, force, fn) {
	var _base = ''
		, _filepath = ''
		, _first = true
		, _outstanding = 0
		, _cp;
	if (force == null) force = false;
	// Inner function
	_cp = function(source, destination) {
		_outstanding++;
		fs.stat(source, function(err, stats) {
			var isDestFile;
			_outstanding--;
			// Exit if proper error, otherwise skip
			if (err) {
				if (err.code === 'ENOENT') return;
				else return fn(err);
			} else {
				isDestFile = path.extname(destination).length;
				// File
				if (stats.isFile()) {
					// Handle file or directory as destination
					var destDir = isDestFile ? path.dirname(destination) : destination
						, destName = isDestFile ? path.basename(destination) : path.basename(source)
						, filepath = path.resolve(destDir, destName);
					// Write file if it doesn't already exist
					if (!force && existsSync(filepath)) {
						if (!_outstanding) return fn(null, _filepath);
					} else {
						rm(filepath, function(err) {
							// Ignore rm errors
							var file;
							_outstanding++;
							// Return the new path for the first source
							if (_first) {
								_filepath = filepath;
								_first = false;
							}
							// Pipe stream
							fs.createReadStream(source).pipe(file = fs.createWriteStream(filepath));
							file.on('error', function(err) { return fn(err); });
							file.on('close', function() {
								_outstanding--;
								// Return if no outstanding
								if (!_outstanding) return fn(null, _filepath);
							});
						});
					}
				// Directory
				} else {
					// Guard against invalid directory to file copy
					if (isDestFile) {
						fn(new Error('invalid destination for copy: ' + destination));
					} else {
						// Copy contents only if source ends in '/'
						var contentsOnly = _first && /\\$|\/$/.test(source)
							, dest = contentsOnly ? destination : path.resolve(destination, path.basename(source));
						// Create in destination
						_outstanding++;
						mkdir(dest, function(err) {
							_outstanding--;
							if (err) {
								return fn(err);
							} else {
								// Loop through contents
								_outstanding++;
								fs.readdir(source, function(err, files) {
									_outstanding--;
									// Exit if proper error, otherwise skip
									if (err) {
										if (err.code === 'ENOENT') return;
										else return fn(err);
									} else {
										// Return the new path for the first source
										if (_first) {
											_filepath = dest;
											_first = false;
										}
										// Loop through files and cp
										files.forEach(function(file) {
											_cp(path.resolve(source, file), dest);
										});
										// Return if no outstanding
										if (!_outstanding) return fn(null, _filepath);
									}
								});
							}
						});
					}
				}
			}
		});
		// Return if no outstanding
		if (!_outstanding) return fn(null, _filepath);
	};
	return _cp(source, destination);
};

/**
 * Recursive remove file or directory
 * Makes sure only project sources are removed
 * @param {String} source
 * @param {Function} fn(err)
 */
var rm = exports.rm = function(source, fn) {
	if (existsSync(source)) {
		if (source.indexOf(process.cwd()) != -1) {
			rimraf(source, function(err) {
				if (err) return fn(err);
				else return fn();
			});
		} else {
			fn(new Error('cannot rm source outside of project path: ' + source));
		}
	} else {
		fn(new Error('cannot rm non-existant source: ' + source));
	}
};
<|endoftext|>


<commit_before>const rssConfig = require('../../config.json')
const striptags = require('striptags')
const filterFeed = require('./filters.js')
const createEmbed = require('./embed.js')
const cleanRandoms = require('./cleanup.js')
const moment = require('moment-timezone')
const getSubscriptions = require('./subscriptions.js')

module.exports = function (channel, rssList, rssIndex, data, isTestMessage) {
  const guildTimezone = require(`../../sources/${channel.guild.id}`).timezone
  require('fs').writeFileSync('./something.txt', data.description)
  //sometimes feeds get deleted mid process
  if (rssList[rssIndex] == null) {console.log("RSS Error: Unable to translate a null source."); return null;}
  if (data.guid == null) {console.log(`RSS Error: (${channel.guild.id}, ${channel.guild.name}) => Feed GUID is null.`, data); return null;}

  var originalDate = data.pubdate;
  if (guildTimezone != null && moment.tz.zone(guildTimezone) != null) var timezone = guildTimezone;
  else var timezone = rssConfig.timezone;
  // var vanityDate = moment(originalDate).format("ddd, MMMM Do YYYY, h:mm A")
  var vanityDate = moment.tz(originalDate, timezone).format("ddd, MMMM Do YYYY, h:mm A z")

  //var dataDescrip = ""
  if (data.guid.startsWith("yt:video")) var dataDescrip = data['media:group']['media:description']['#'];
  else var dataDescrip = cleanRandoms(data.description);

  var dataSummary = cleanRandoms(data.summary);
  if (dataSummary.length > 800)  {
    dataSummary = dataSummary.slice(0, 800) + " [...]";
  }
  if (isTestMessage && dataSummary.length > 300) {
    dataSummary = dataSummary.slice(0, 300) + " [...]\n\n**(Truncated shorter summary for rsstest)**";
  }

  if (dataDescrip.length > 800) {
    dataDescrip = dataDescrip.slice(0, 800) + " [...]";
  }
  if (isTestMessage && dataDescrip.length > 300) {
    if (data.summary == data.description) dataDescrip = dataDescrip.slice(0, 600) + " [...]\n\n**(Truncated shorter description for rsstest)**";
    else dataDescrip = dataDescrip.slice(0, 300) + " [...]\n(Truncated shorter description for rsstest)";
  }

  if (data.link != null && data.link.includes("reddit")) {
    dataDescrip = dataDescrip.substr(0,dataDescrip.length-22)
            .replace("submitted by", "\n*Submitted by:*"); //truncate the useless end of reddit description
  }

  var subscriptions = getSubscriptions(channel, rssIndex, data, dataDescrip)

  function replaceKeywords(word){
    var a = word.replace(/{date}/g, vanityDate)
            .replace(/{title}/g, striptags(data.title))
            .replace(/{author}/g, data.author)
            .replace(/{summary}/g, dataSummary)
            .replace(/{image}/g, data.image.url)
            .replace(/{subscriptions}/g, subscriptions)

    if (data.link != null) var b = a.replace(/{link}/g, data.link);
    else var b = a.replace(/{link}/g, "");

    if (data.guid.startsWith("yt:video")) { //youtube feeds have the property media:group that other feeds do not have
      if (data['media:group']['media:description']['#'] != null) var c = b.replace(/{description}/g, data['media:group']['media:description']['#']);
      else var c = b.replace(/{description}/g, "");

      var d = c.replace(/{thumbnail}/g, data['media:group']['media:thumbnail']['@']['url']);
      return d;
    }
    else return b.replace(/{description}/g, dataDescrip);
  }

  //filter message
  var filterPropCount = 0;
  if (rssList[rssIndex].filters != null && typeof rssList[rssIndex].filters == "object") {
    for (var prop in rssList[rssIndex].filters)
      if (rssList[rssIndex].filters.hasOwnProperty(prop) && prop !== "roleSubscriptions") filterPropCount++;
  }

  var filterExists = false
  var filterFound = false
  if (filterPropCount !== 0) {
    filterExists = true;
    filterFound = filterFeed(rssList, rssIndex, data, dataDescrip);
  }

  //feed article only passes through if the filter found the specified content
  if (!isTestMessage && filterExists && !filterFound) {
    console.log(`RSS Delivery: (${channel.guild.id}, ${channel.guild.name}) => ${data.link} did not pass filters and was not sent:\n`, rssList[rssIndex].filters);
    return null;
  }

  if (rssList[rssIndex].message == null) var configMessage = replaceKeywords(rssConfig.defaultMessage);
  else var configMessage = replaceKeywords(rssList[rssIndex].message);

  //generate final msg
  var finalMessage = "";
  if (isTestMessage) {

    let footer = "\nBelow is the configured message to be sent for this feed:\n\n\n\n"
    finalMessage += `\`\`\`Markdown\n# Test Message\`\`\`\`\`\`Markdown\n\n[Title]: {title}\n${data.title}`;
    if (dataDescrip != null && dataDescrip !== "") finalMessage += `\n\n[Description]: {description}\n${dataDescrip}`
    if (data.description !== data.summary && dataSummary != null && dataSummary !== "") finalMessage += `\n\n[Summary]: {summary}\n${dataSummary} (Summary has been truncated for test)`
    if (vanityDate != null && vanityDate !== "") finalMessage += `\n\n[Published Date]: {date}\n${vanityDate}`
    if (data.author != null && data.author !== "") finalMessage += `\n\n[Author]: {author}\n${data.author}`
    if (data.link != null) finalMessage += `\n\n[Link]: {link}\n${data.link}`
    if (data.image.url !=  null && data.image.url !== "") finalMessage += `\n\n[Image URL]: {image}\n${data.image.url}`;
    if (subscriptions !== "") finalMessage += `\n\n[Subscriptions]: {subscriptions}\n${subscriptions.split(" ").length - 1} subscriber(s)`;
    if (filterExists) finalMessage += `\n\n[Passed Filters?]: ${filterFound}`;
    if (data.guid.startsWith("yt:video")) {
      finalMessage += `\n\n[Youtube Thumbnail]: {thumbnail}\n${data['media:group']['media:thumbnail']['@']['url']}\`\`\`` + footer + configMessage;
    }
    else finalMessage += "```" + footer + configMessage;

  }
  else finalMessage = configMessage;

  //account for final message length
  if (finalMessage.length >= 1900) {
    console.log(finalMessage);
    finalMessage = `The article titled **<${data.title}>** is greater than or equal to 1900 characters cannot be sent as a precaution. The link to the article is:\n\n${data.link}`;
    if (!isTestMessage) console.log(`RSS Delivery Warning: (${channel.guild.id}, ${channel.guild.name}) => Feed titled "${data.title}" cannot be sent to Discord because message length is >1900.`);
    else console.log(`RSS Test Delivery Warning: (${channel.guild.id}, ${channel.guild.name}) => Feed titled "${data.title}" cannot be sent to Discord because message length is >1900.`);

  }
  let finalMessageCombo = {
    textMsg: finalMessage
  }

  //check if embed is enabled
  var enabledEmbed;
  if (rssList[rssIndex].embedMessage == null || rssList[rssIndex].embedMessage.enabled == false || rssList[rssIndex].embedMessage == "" || rssList[rssIndex].embedMessage.enabled == "")
    enabledEmbed = false;
  else enabledEmbed = true;

  if (enabledEmbed !== true) {
     return finalMessageCombo;
  }
  else {

    if (rssList[rssIndex].embedMessage.properties != null)
      finalMessageCombo.embedMsg = createEmbed(channel, rssList, rssIndex, data, replaceKeywords)

    return finalMessageCombo;
  }
}
<commit_msg>uncommented vital code<commit_after>const rssConfig = require('../../config.json')
const striptags = require('striptags')
const filterFeed = require('./filters.js')
const createEmbed = require('./embed.js')
const cleanRandoms = require('./cleanup.js')
const moment = require('moment-timezone')
const getSubscriptions = require('./subscriptions.js')

module.exports = function (channel, rssList, rssIndex, data, isTestMessage) {
  const guildTimezone = require(`../../sources/${channel.guild.id}`).timezone
  require('fs').writeFileSync('./something.txt', data.description)
  //sometimes feeds get deleted mid process
  if (rssList[rssIndex] == null) {console.log("RSS Error: Unable to translate a null source."); return null;}
  if (data.guid == null) {console.log(`RSS Error: (${channel.guild.id}, ${channel.guild.name}) => Feed GUID is null.`, data); return null;}

  var originalDate = data.pubdate;
  if (guildTimezone != null && moment.tz.zone(guildTimezone) != null) var timezone = guildTimezone;
  else var timezone = rssConfig.timezone;
  var vanityDate = moment.tz(originalDate, timezone).format("ddd, MMMM Do YYYY, h:mm A z")

  var dataDescrip = ""
  if (data.guid.startsWith("yt:video")) dataDescrip = data['media:group']['media:description']['#'];
  else dataDescrip = cleanRandoms(data.description);

  var dataSummary = cleanRandoms(data.summary);
  if (dataSummary.length > 800)  {
    dataSummary = dataSummary.slice(0, 800) + " [...]";
  }
  if (isTestMessage && dataSummary.length > 300) {
    dataSummary = dataSummary.slice(0, 300) + " [...]\n\n**(Truncated shorter summary for rsstest)**";
  }

  if (dataDescrip.length > 800) {
    dataDescrip = dataDescrip.slice(0, 800) + " [...]";
  }
  if (isTestMessage && dataDescrip.length > 300) {
    if (data.summary == data.description) dataDescrip = dataDescrip.slice(0, 600) + " [...]\n\n**(Truncated shorter description for rsstest)**";
    else dataDescrip = dataDescrip.slice(0, 300) + " [...]\n(Truncated shorter description for rsstest)";
  }

  if (data.link != null && data.link.includes("reddit")) {
    dataDescrip = dataDescrip.substr(0,dataDescrip.length-22)
            .replace("submitted by", "\n*Submitted by:*"); //truncate the useless end of reddit description
  }

  var subscriptions = getSubscriptions(channel, rssIndex, data, dataDescrip)

  function replaceKeywords(word){
    var a = word.replace(/{date}/g, vanityDate)
            .replace(/{title}/g, striptags(data.title))
            .replace(/{author}/g, data.author)
            .replace(/{summary}/g, dataSummary)
            .replace(/{image}/g, data.image.url)
            .replace(/{subscriptions}/g, subscriptions)

    if (data.link != null) var b = a.replace(/{link}/g, data.link);
    else var b = a.replace(/{link}/g, "");

    if (data.guid.startsWith("yt:video")) { //youtube feeds have the property media:group that other feeds do not have
      if (data['media:group']['media:description']['#'] != null) var c = b.replace(/{description}/g, data['media:group']['media:description']['#']);
      else var c = b.replace(/{description}/g, "");

      var d = c.replace(/{thumbnail}/g, data['media:group']['media:thumbnail']['@']['url']);
      return d;
    }
    else return b.replace(/{description}/g, dataDescrip);
  }

  //filter message
  var filterPropCount = 0;
  if (rssList[rssIndex].filters != null && typeof rssList[rssIndex].filters == "object") {
    for (var prop in rssList[rssIndex].filters)
      if (rssList[rssIndex].filters.hasOwnProperty(prop) && prop !== "roleSubscriptions") filterPropCount++;
  }

  var filterExists = false
  var filterFound = false
  if (filterPropCount !== 0) {
    filterExists = true;
    filterFound = filterFeed(rssList, rssIndex, data, dataDescrip);
  }

  //feed article only passes through if the filter found the specified content
  if (!isTestMessage && filterExists && !filterFound) {
    console.log(`RSS Delivery: (${channel.guild.id}, ${channel.guild.name}) => ${data.link} did not pass filters and was not sent:\n`, rssList[rssIndex].filters);
    return null;
  }

  if (rssList[rssIndex].message == null) var configMessage = replaceKeywords(rssConfig.defaultMessage);
  else var configMessage = replaceKeywords(rssList[rssIndex].message);

  //generate final msg
  var finalMessage = "";
  if (isTestMessage) {

    let footer = "\nBelow is the configured message to be sent for this feed:\n\n\n\n"
    finalMessage += `\`\`\`Markdown\n# Test Message\`\`\`\`\`\`Markdown\n\n[Title]: {title}\n${data.title}`;
    if (dataDescrip != null && dataDescrip !== "") finalMessage += `\n\n[Description]: {description}\n${dataDescrip}`
    if (data.description !== data.summary && dataSummary != null && dataSummary !== "") finalMessage += `\n\n[Summary]: {summary}\n${dataSummary} (Summary has been truncated for test)`
    if (vanityDate != null && vanityDate !== "") finalMessage += `\n\n[Published Date]: {date}\n${vanityDate}`
    if (data.author != null && data.author !== "") finalMessage += `\n\n[Author]: {author}\n${data.author}`
    if (data.link != null) finalMessage += `\n\n[Link]: {link}\n${data.link}`
    if (data.image.url !=  null && data.image.url !== "") finalMessage += `\n\n[Image URL]: {image}\n${data.image.url}`;
    if (subscriptions !== "") finalMessage += `\n\n[Subscriptions]: {subscriptions}\n${subscriptions.split(" ").length - 1} subscriber(s)`;
    if (filterExists) finalMessage += `\n\n[Passed Filters?]: ${filterFound}`;
    if (data.guid.startsWith("yt:video")) {
      finalMessage += `\n\n[Youtube Thumbnail]: {thumbnail}\n${data['media:group']['media:thumbnail']['@']['url']}\`\`\`` + footer + configMessage;
    }
    else finalMessage += "```" + footer + configMessage;

  }
  else finalMessage = configMessage;

  //account for final message length
  if (finalMessage.length >= 1900) {
    console.log(finalMessage);
    finalMessage = `The article titled **<${data.title}>** is greater than or equal to 1900 characters cannot be sent as a precaution. The link to the article is:\n\n${data.link}`;
    if (!isTestMessage) console.log(`RSS Delivery Warning: (${channel.guild.id}, ${channel.guild.name}) => Feed titled "${data.title}" cannot be sent to Discord because message length is >1900.`);
    else console.log(`RSS Test Delivery Warning: (${channel.guild.id}, ${channel.guild.name}) => Feed titled "${data.title}" cannot be sent to Discord because message length is >1900.`);

  }
  let finalMessageCombo = {
    textMsg: finalMessage
  }

  //check if embed is enabled
  var enabledEmbed;
  if (rssList[rssIndex].embedMessage == null || rssList[rssIndex].embedMessage.enabled == false || rssList[rssIndex].embedMessage == "" || rssList[rssIndex].embedMessage.enabled == "")
    enabledEmbed = false;
  else enabledEmbed = true;

  if (enabledEmbed !== true) {
     return finalMessageCombo;
  }
  else {

    if (rssList[rssIndex].embedMessage.properties != null)
      finalMessageCombo.embedMsg = createEmbed(channel, rssList, rssIndex, data, replaceKeywords)

    return finalMessageCombo;
  }
}
<|endoftext|>