<commit_before>'use strict'

var path            = require('path');
var fs 				= require('fs');
var exec 			= require('child_process').exec;
var async 			= require("async");

var browserSync     = require('browser-sync');
var reload          = browserSync.reload;

var browserify 		= require('browserify');
var source 			= require('vinyl-source-stream');
var buffer 			= require('vinyl-buffer');
var glob 			= require('glob');

var gulp            = require('gulp');
var $ 				= require('gulp-load-plugins')({
						pattern: ['gulp-*', 'del']
					});

var pkg = require('./package.json');

var banner = ['/**',
  ' * <%= pkg.name %> - <%= pkg.description %>',
  ' * @version v<%= pkg.version %>',
  ' * @link <%= pkg.homepage %>',
  ' * @license <%= pkg.license %>',
  ' * Copyright (c) <%= new Date().getFullYear() %> Icebob',
  ' * ',
  ' * ',
  ' * Build Date: <%= new Date().toString() %>',
  ' * ',
  ' */',
  ''].join('\n');

// Browser-sync task
gulp.task('browser-sync', function() {
	browserSync({
		server: {
			baseDir: "./demo",
			routes: {
				"/src": "src",
				"/dist": "dist"
			}
		}
	});
});

gulp.task('clean:css', function() {
  if (fs.existsSync('src/css'))
  	$.del.sync('src/css/**');
});

// Sass task
gulp.task('sass', ['clean:css'], function () {

	return gulp.src('src/scss/*.scss')
		.pipe($.plumber())
		.pipe($.compass({
			project: path.join(__dirname, "src"),
			css: 'css',
			sass: 'scss',
			style: 'expanded',
			cache: false
		})
		.on('error', $.util.log));
});

// Sass task
gulp.task('sass:min', ['clean:css'], function () {

	return gulp.src('src/scss/*.scss')
		.pipe($.plumber())
		//.pipe($.rename('propertiesJS.min.css'))
		.pipe($.compass({
			project: path.join(__dirname, "src"),
			css: 'css',
			sass: 'scss',
			sourcemap: true,
			style: 'compressed',
			cache: false
		})
		.on('error', $.util.log));
});

// Sass demo task
gulp.task('sass:demo', function () {

	return gulp.src('demo/*.scss')
		.pipe($.plumber())
		.pipe($.compass({
			project: __dirname,
			css: 'demo',
			sass: 'demo',
			style: 'expanded',
			cache: false
		})
		.on('error', $.util.log));
});

// Coffescript task
gulp.task('coffee', function () {
	return gulp.src('src/coffee/**/*.coffee', {base: "./src/coffee"})
		.pipe($.plumber())
		.pipe($.coffeelint())
		.pipe($.coffeelint.reporter())
		.pipe($.coffee({bare: false }))
		.pipe(gulp.dest("src/js"));
});

// Coffescript demo task
gulp.task('coffee:demo', function () {
	return gulp.src('demo/**/*.coffee', {base: "./demo"})
		.pipe($.plumber())
		.pipe($.coffee({bare: true }))
		.pipe(gulp.dest("./demo"));
});

// Coffescript test task
gulp.task('coffee:test', function () {
	return gulp.src('test/**/*.coffee', {base: "./test"})
		.pipe($.plumber())
		.pipe($.coffeelint())
		.pipe($.coffeelint.reporter())
		.pipe($.coffee({bare: true }))
		.pipe(gulp.dest("./test"));
});

// JADE task
gulp.task('jade', function () {
	return gulp.src('demo/*.jade')
		.pipe($.plumber())
		.pipe($.jade({
			pretty: true
		}))
		.pipe(gulp.dest("./demo"));
});

/**
 * Reload all Browsers
 */
gulp.task('bs-reload', function () {
	browserSync.reload();
});

// Default task (compile, build)
gulp.task('default', ['build']);

// Develop task (compile + watch + reload)
gulp.task('dev', ['jade', 'sass', 'sass:demo', 'coffee', 'coffee:demo', 'build', 'browser-sync'], function () {
	$.watch(['dist/*.css', 'demo/*.css'], function(file) {
		reload(file.path);
	});

	$.watch('demo/*.html', function() {
		gulp.start('bs-reload');
	});
	$.watch(['dist/*.js', 'demo/*.js'], function() {
		gulp.start('bs-reload');
	});

	$.watch('demo/*.jade', function() {
		gulp.start('jade');
	});
	$.watch('src/coffee/**/*.coffee', function() {
		console.log("Coffee changed. Run build...");
		gulp.start('build');
	});
	$.watch('demo/*.coffee', function() {
		gulp.start('coffee:demo');
	});
	$.watch('src/scss/*.scss', function() {
		gulp.start('sass', function() {
			gulp.src('src/css/*.css')
				.pipe($.header(banner, { pkg : pkg } ))
				.pipe(gulp.dest("dist"));

			gulp.src('src/css/*.map')
				.pipe(gulp.dest("dist"));

		});
	});
	$.watch('demo/*.scss', function() {
		gulp.start('sass:demo');
	});

});

/**
 * Testing
 */
var testFiles = [
	'node_modules/jquery/dist/jquery.min.js',
	'libraries/**/*.*',
	'src/js/**/*.js',
	'test/**/*.spec.js'
];

// Test task with karma
gulp.task("test", ["coffee", "coffee:test"], function() {

	return gulp.src(testFiles, {read: false})
		.pipe($.karma({
			configFile: 'karma.conf.js',
			action: 'run'
		}))
		.on('error', function(err) {
			// Make sure failed tests cause gulp to exit non-zero
			throw err;
		});
});

// Test task with karma and watching (CI)
gulp.task('karma', ["sass", "coffee", "coffee:test"], function() {

	// Watch server scripts
	$.watch(["test/**/*.spec.coffee", "src/coffee/**/*.coffee"], {read: false}, function(files) {
		gulp.start(["coffee", "coffee:test"]);
	});

	// Run karma with watch

	return gulp.src(testFiles.concat(['test/*.css', 'src/css/*.css']), {read: false})
		.pipe($.plumber())
		.pipe($.karma({
			configFile: 'karma.dev.conf.js',
			action: 'watch'
		}))
		.on('error', $.util.log);
});

/**
 * Build
 */

gulp.task('build', ["sass:min", "coffee"], function () {
	console.log("Building...");

	gulp.src('src/css/*.css')
		.pipe($.header(banner, { pkg : pkg } ))
		.pipe(gulp.dest("dist"));

	gulp.src('src/css/*.map')
		.pipe(gulp.dest("dist"));

	// set up the browserify instance on a task basis
	var b = browserify({
		entries: './src/js/propertiesJS.js',
		debug: false
	});

 	return b.bundle()
		.pipe(source('propertiesJS.js'))
		.pipe(buffer())
		.pipe($.header(banner, { pkg : pkg } ))
		.pipe(gulp.dest('./dist'))
		.pipe($.sourcemaps.init({loadMaps: true}))
			// Add transformation tasks to the pipeline here.
			.pipe($.uglify())
			.on('error', $.util.log)
		.pipe($.sourcemaps.write('./'))
		.pipe($.rename('propertiesJS.min.js'))
		.pipe($.header(banner, { pkg : pkg } ))
		.pipe(gulp.dest('./dist'));
});

/**
 * Bump version
 */
function bump(type) {
  var bumpType = type || 'patch'; // major.minor.patch

  return gulp.src(['./package.json', './bower.json'])
    .pipe($.bump({ type: bumpType }))
    .pipe(gulp.dest('./'));
}

gulp.task('bump-patch', [], function () { return bump('patch') });
gulp.task('bump-minor', [], function () { return bump('minor') });
gulp.task('bump-major', [], function () { return bump('major') });

/**
 * Release to Github & npm
 */
gulp.task('release', function (done) {

    var pkg = JSON.parse(fs.readFileSync('./package.json', 'utf-8'));
    var tag = 'v' + pkg.version;
    var message = 'Release ' + tag;
    var cmds = [
        'git add .',
        'git commit -m "Release ' + tag + '"',
        'git tag ' + tag + ' -m "Release ' + tag + '"',
        'git push -u origin master',
        'git push -u origin master --tags',
        'npm publish'
    ];

    async.eachSeries(cmds, function(cmd, cb) {
    	console.log("Execute: " + cmd);
		exec(cmd, function( error, stdout, stderr)
		{
			console.log(stdout);
			if ( error != null ) {
				console.error(stderr);
				cb(error);
			}
			cb();
		});

    },  function(error) {
    	done();
    });
});<commit_msg>Release v1.5.1<commit_after>'use strict'

var path            = require('path');
var fs 				= require('fs');
var exec 			= require('child_process').exec;
var async 			= require("async");

var browserSync     = require('browser-sync');
var reload          = browserSync.reload;

var browserify 		= require('browserify');
var source 			= require('vinyl-source-stream');
var buffer 			= require('vinyl-buffer');
var glob 			= require('glob');

var gulp            = require('gulp');
var $ 				= require('gulp-load-plugins')({
						pattern: ['gulp-*', 'del']
					});

var pkg = require('./package.json');

var banner = ['/**',
  ' * <%= pkg.name %> - <%= pkg.description %>',
  ' * @version v<%= pkg.version %>',
  ' * @link <%= pkg.homepage %>',
  ' * @license <%= pkg.license %>',
  ' * Copyright (c) <%= new Date().getFullYear() %> Icebob',
  ' * ',
  ' * ',
  ' * Build Date: <%= new Date().toString() %>',
  ' * ',
  ' */',
  ''].join('\n');

// Browser-sync task
gulp.task('browser-sync', function() {
	browserSync({
		server: {
			baseDir: "./demo",
			routes: {
				"/src": "src",
				"/dist": "dist"
			}
		}
	});
});

gulp.task('clean:css', function() {
  if (fs.existsSync('src/css'))
  	$.del.sync('src/css/**');
});

// Sass task
gulp.task('sass', ['clean:css'], function () {

	return gulp.src('src/scss/*.scss')
		.pipe($.plumber())
		.pipe($.compass({
			project: path.join(__dirname, "src"),
			css: 'css',
			sass: 'scss',
			style: 'expanded',
			cache: false
		})
		.on('error', $.util.log));
});

// Sass task
gulp.task('sass:min', ['clean:css'], function () {

	return gulp.src('src/scss/*.scss')
		.pipe($.plumber())
		//.pipe($.rename('propertiesJS.min.css'))
		.pipe($.compass({
			project: path.join(__dirname, "src"),
			css: 'css',
			sass: 'scss',
			sourcemap: true,
			style: 'compressed',
			cache: false
		})
		.on('error', $.util.log));
});

// Sass demo task
gulp.task('sass:demo', function () {

	return gulp.src('demo/*.scss')
		.pipe($.plumber())
		.pipe($.compass({
			project: __dirname,
			css: 'demo',
			sass: 'demo',
			style: 'expanded',
			cache: false
		})
		.on('error', $.util.log));
});

// Coffescript task
gulp.task('coffee', function () {
	return gulp.src('src/coffee/**/*.coffee', {base: "./src/coffee"})
		.pipe($.plumber())
		.pipe($.coffeelint())
		.pipe($.coffeelint.reporter())
		.pipe($.coffee({bare: false }))
		.pipe(gulp.dest("src/js"));
});

// Coffescript demo task
gulp.task('coffee:demo', function () {
	return gulp.src('demo/**/*.coffee', {base: "./demo"})
		.pipe($.plumber())
		.pipe($.coffee({bare: true }))
		.pipe(gulp.dest("./demo"));
});

// Coffescript test task
gulp.task('coffee:test', function () {
	return gulp.src('test/**/*.coffee', {base: "./test"})
		.pipe($.plumber())
		.pipe($.coffeelint())
		.pipe($.coffeelint.reporter())
		.pipe($.coffee({bare: true }))
		.pipe(gulp.dest("./test"));
});

// JADE task
gulp.task('jade', function () {
	return gulp.src('demo/*.jade')
		.pipe($.plumber())
		.pipe($.jade({
			pretty: true
		}))
		.pipe(gulp.dest("./demo"));
});

/**
 * Reload all Browsers
 */
gulp.task('bs-reload', function () {
	browserSync.reload();
});

// Default task (compile, build)
gulp.task('default', ['build']);

// Develop task (compile + watch + reload)
gulp.task('dev', ['jade', 'sass', 'sass:demo', 'coffee', 'coffee:demo', 'build', 'browser-sync'], function () {
	$.watch(['dist/*.css', 'demo/*.css'], function(file) {
		reload(file.path);
	});

	$.watch('demo/*.html', function() {
		gulp.start('bs-reload');
	});
	$.watch(['dist/*.js', 'demo/*.js'], function() {
		gulp.start('bs-reload');
	});

	$.watch('demo/*.jade', function() {
		gulp.start('jade');
	});
	$.watch('src/coffee/**/*.coffee', function() {
		console.log("Coffee changed. Run build...");
		gulp.start('build');
	});
	$.watch('demo/*.coffee', function() {
		gulp.start('coffee:demo');
	});
	$.watch('src/scss/*.scss', function() {
		gulp.start('sass', function() {
			gulp.src('src/css/*.css')
				.pipe($.header(banner, { pkg : pkg } ))
				.pipe(gulp.dest("dist"));

			gulp.src('src/css/*.map')
				.pipe(gulp.dest("dist"));

		});
	});
	$.watch('demo/*.scss', function() {
		gulp.start('sass:demo');
	});

});

/**
 * Testing
 */
var testFiles = [
	'node_modules/jquery/dist/jquery.min.js',
	'libraries/**/*.*',
	'src/js/**/*.js',
	'test/**/*.spec.js'
];

// Test task with karma
gulp.task("test", ["coffee", "coffee:test"], function() {

	return gulp.src(testFiles, {read: false})
		.pipe($.karma({
			configFile: 'karma.conf.js',
			action: 'run'
		}))
		.on('error', function(err) {
			// Make sure failed tests cause gulp to exit non-zero
			throw err;
		});
});

// Test task with karma and watching (CI)
gulp.task('karma', ["sass", "coffee", "coffee:test"], function() {

	// Watch server scripts
	$.watch(["test/**/*.spec.coffee", "src/coffee/**/*.coffee"], {read: false}, function(files) {
		gulp.start(["coffee", "coffee:test"]);
	});

	// Run karma with watch

	return gulp.src(testFiles.concat(['test/*.css', 'src/css/*.css']), {read: false})
		.pipe($.plumber())
		.pipe($.karma({
			configFile: 'karma.dev.conf.js',
			action: 'watch'
		}))
		.on('error', $.util.log);
});

/**
 * Build
 */

gulp.task('build', ["sass:min", "coffee"], function () {
	console.log("Building...");

	gulp.src('src/css/*.css')
		.pipe($.header(banner, { pkg : pkg } ))
		.pipe(gulp.dest("dist"));

	gulp.src('src/css/*.map')
		.pipe(gulp.dest("dist"));

	// set up the browserify instance on a task basis
	var b = browserify({
		entries: './src/js/propertiesJS.js',
		debug: false
	});

 	return b.bundle()
		.pipe(source('propertiesJS.js'))
		.pipe(buffer())
		.pipe($.header(banner, { pkg : pkg } ))
		.pipe(gulp.dest('./dist'))
		.pipe($.sourcemaps.init({loadMaps: true}))
			// Add transformation tasks to the pipeline here.
			.pipe($.uglify())
			.on('error', $.util.log)
		.pipe($.sourcemaps.write('./'))
		.pipe($.rename('propertiesJS.min.js'))
		.pipe($.header(banner, { pkg : pkg } ))
		.pipe(gulp.dest('./dist'));
});

/**
 * Bump version
 */
function bump(type) {
  var bumpType = type || 'patch'; // major.minor.patch

  return gulp.src(['./package.json', './bower.json'])
    .pipe($.bump({ type: bumpType }))
    .pipe(gulp.dest('./'));
}

gulp.task('bump-patch', [], function () { return bump('patch') });
gulp.task('bump-minor', [], function () { return bump('minor') });
gulp.task('bump-major', [], function () { return bump('major') });

/**
 * Release to Github & npm
 */
gulp.task('release', function (done) {

    var pkg = JSON.parse(fs.readFileSync('./package.json', 'utf-8'));
    var tag = 'v' + pkg.version;
    var message = 'Release ' + tag;
    var cmds = [
        'git add .',
        'git commit -m "Release ' + tag + '"',
        'git tag ' + tag + ' -m "Release ' + tag + '"',
        'git push -u origin master',
        'git push -u origin master --tags',
        'npm publish'
    ];

    async.eachSeries(cmds, function(cmd, cb) {
    	console.log("Execute: " + cmd);
		exec(cmd, function( error, stdout, stderr)
		{
			console.log(stdout);
			if ( error != null ) {
				console.error(stderr);
				return cb(error);
			}
			cb();
		});

    },  function(error) {
    	done();
    });
});<|endoftext|>


<commit_before>(function () {
  "use strict";
  /**
   * Module dependencies.
   */

  var connect = require('connect')
    , fs = require('fs.extra')
    , assert = require('assert')
    , Futures = require('futures')
    , Formaline = require('formaline')
      // The DropShare Epoch -- 1320969600000 -- Fri, 11 Nov 2011 00:00:00 GMT
    , generateId = require('./gen-id').create(1320769600000)
    , storage
    , filesDir = __dirname + '/../files'
    , allowUserSpecifiedIds = false
    , app
    ;

  connect.cors = require('connect-cors');

  // Routes
  function createIds(req, res, next) {
    var i
      , sequence = Futures.sequence()
      , ids = []
      , id
      , meta
      , err
      , now = Date.now()
      ;

    if (!Array.isArray(req.body)) {
      var err = {
        "result": "error",
        "data": "Must be an array of file metadata."
      };

      res.end(JSON.stringify(err), 400);
      return;
    }

    // TODO use forEachAsync
    req.body.forEach(function (meta, i) {
      meta.timestamp = now;
      if (allowUserSpecifiedIds && meta.id) {
        id = meta.id;
      }
      else {
        id = generateId();
      }
      //Dang for loops and closures
      (function (fileId) {
        sequence.then(function (next) {
          storage.set(fileId, meta, function (err, data) {
            ids.push(fileId);
            next();
          });
        });
      })(id);
    });

    sequence.then(function (next) {
      res.writeHead(200, {'content-type': 'application/json'});
      res.write(JSON.stringify(ids));
      res.end();
      next();
    });
  }

  function handleUploadedFiles (json, res) {
    var responses = []
      , sequence = require('sequence')()
      ;

    json.files.forEach(function (fileObj) {
      (function (fileData) {
        sequence.then(function (next) {
          handleUploadedFile(fileData, function (response) {
            responses.push(response);
            next();
          });
        });
      })(fileObj);
    });

    sequence.then(function (next) {
      res.end(formatFileUploadResponses(responses));
      next();
    });
  }

  function handleUploadedFile (file, cb) {
    // Check that metadata exists for this ID
    storage.get(file.name, function (err, result) {
      var response;
      if (err !== null || result === null) {
        cb({
          "result": "error",
          "data": "No metadata for id '" + file.name + "'."
        });
        return;
      }

      // If metadata exists, then move the file and update the metadata with the new path
      var res = moveFileToStorage(file.name, file.value[0], cb({
        "result": "success",
        "data": "File " + file.name + " stored successfully."
      }));
    });
  }

  function moveFileToStorage(fileId, file) {
    var is
      , os
      , newFilePath = filesDir + '/' + file.sha1checksum
      ;

    fs.stat(file.path, function (err, stat) {
      assert.strictEqual(err, null, "tried to move a non-existent file");

      //check if file with same checksum already exists
      fs.stat(newFilePath, function (statErr, stat) {
        if (typeof stat === "undefined") {
          // File does not exist already, so move it in to place
          fs.move(file.path, newFilePath, function (movErr) {
            if (movErr) {
              console.warn('Error moving file to storage: ' + movErr.toString());
              //throw err;
            }

          });
        }
        else {
        }

        addSHA1ToMetadata(fileId, file.sha1checksum);
      });
    });
  }

  function addSHA1ToMetadata(id, checksum) {
    storage.get(id, function (err, data, isJSON) {
      assert.ok(isJSON, "Metadata is not JSON");

      data.sha1checksum = checksum;
      storage.set(id, data, function (err, res) {
        assert.deepEqual(err, null, "Error storing metadata again.");
      });
    });
  }

  function formatFileUploadResponses (responses) {
    return JSON.stringify(responses);
  }

  function receiveFiles(req, res, next) {
    var form
      , config
      ;

    config = {
        sha1sum: true
      , removeIncompleteFiles: true
      , uploadThreshold: 1024 * 1024 * 1024
      , listeners: {
            'fileprogress': function (ev, chunk) {
              // here's where we could snatch the target data
              // as it is streaming
            }

          , 'loadend': function (json, res, callback) {
              console.log('\njson is\n', json);
              try {
                callback(json, res);
              } catch ( err ) {
                console.error( 'error', err.stack );
              }
            }

          , 'error': function (err) {
              console.error('[formaline error]');
              console.error(err && err.stack || err);
              console.error(arguments);
            }

      } // end listeners
    }; // end config object

    // XXX Trickery to get around connect 1.7 vs 1.8 vs 2.x issues
    req.body = undefined;
    form = new Formaline(config);
    form.parse(req, res, handleUploadedFiles);
  }

  function checkForFileExistence(req, res, err, data) {
    if (err || data === null || typeof(data.sha1checksum) === "undefined") {
      res.writeHead(400, {'content-type': 'application/json'});
      res.write(JSON.stringify({
        "result": "error",
        "data": "No files uploaded for " + req.params.id + "."
      }));
      res.end();
      return false;
    }
    return true;
  }

  function sendFile(req, res, next) {
    storage.get(req.params.id, function (err, data) {
      if (!checkForFileExistence(req, res, err, data)) {
        return;
      }

      fs.readFile(filesDir + '/' + data.sha1checksum, function (err, fileData) {
        if (err) {
          console.warn('trying to get a file that\'s probably deleted');
          res.end(JSON.stringify({
              'error': true
            , 'result': 'error'
            , 'errors': ['No file found for ' + req.params.id + '.']
          }), 500);
          return;
        }

        res.writeHead(200, {'content-type': data.type });
        res.write(fileData);
        res.end();
      });

    });
  }

  function getMetadata(req, res, next) {
    storage.get(req.params.id, function (err, data) {
      if (err !== null || data === null) {
        res.writeHead(400, {'content-type': 'application/json'});
        res.end(JSON.stringify({
            'error': true
          , 'result': 'error'
          , 'errors': ['No metadata for ' + req.params.id + '.']
        }));
        return;
      }

      res.writeHead(200, {'content-type': 'application/json'});
      var response = {
          'success': true
        , 'result': data
        , 'error': false
        , 'errors': []
      };
      res.end(JSON.stringify(response));
    });
  }

  // Delete both the metadata and the file on the FS.
  // NOTE: this will break stuff it multiple IDs refer to the same
  // file. For example, if the same file is uploaded multiple times,
  // it will have the same sha1 hash. If one ID is DELETEd, it will
  // delete the file that other IDs refer to, and then a GET is
  // issued for a different ID that refers to the same file,
  // it will explode.

  // This could be fixed by storing a list of IDs files keyed by
  // the SHA1 hash of the file the refer to.
  function removeFile(req, res, next) {
    var id = req.params.id
      ;

    storage.get(id, function (err, data) {
      if (!checkForFileExistence(req, res, err, data)) {
        return;
      }

      function error(res, data) {
          res.writeHead(500, {'content-type': 'application/json'});
          res.write(JSON.stringify({
            "result": "error",
            "data": "Error in deleting " + data.id + "."
          }));
          res.end();
          return;
      }

      //Delete from Redis
      storage.del(id, function (err) {
        if (err) {
          error(res, data);
          return;
        }

        //Delete from fs
        fs.unlink(filesDir + '/' + data.sha1checksum, function (err) {
          if (err) {
            error(res, data);
            return;
          }

          res.writeHead(200, {'content-type': 'application/json'});
          res.write(JSON.stringify({
            "result": "success",
            "data": "Successfully deleted " + req.params.id + "."
          }));
          res.end();
        });
      });
    });
  }

  function create(options) {

    var filesDirStats
      ;

    function router(app) {
      /*
      app.get('/fs-meta', getAllFsFilesInfo);
      app.get('/fs-meta/*', getFsFileInfo);
      app.delete('/fs-meta/*', removeFile);
      app.get('/fs/*', getFsFile);
      app.post('/fs/*', createFsFile);
      app.put('/fs/*', createFsFile);
      */

      app.post('/meta/new', createIds);
      app.get('/meta/:id', getMetadata);
      app.delete('/meta/:id', removeFile);
      // deprecated
      app.delete('/files/:id', removeFile);
      app.post('/files/new', createIds);

      app.post('/files', receiveFiles);
      app.get('/files/:id/:filename?', sendFile);
    }

    function modifiedBodyParser(req, res, next) {
      var multi = connect.bodyParser.parse['multipart/form-data'];
      connect.bodyParser.parse['multipart/form-data'] = undefined;
      bP(req, res, function () {
        connect.bodyParser.parse['multipart/form-data'] = multi;
        next();
      });
    }

    options = options || {};

    // there could potentially be a race condition here at startup
    // should be negligible
    storage = require('./redis-wrapper').create(options.redis || {});

    filesDir = options.storageDir || options.files || filesDir;

    // Make sure filesDir exists and is writable
    try {
      filesDirStats = fs.statSync(filesDir);
      if (!filesDirStats.isDirectory()) {
        throw new Error('Storage path is not a directory!');
      }
    }
    catch (e) {
      console.warn('Storage directory is not writeable or does not exist: ' + e.path);
      console.warn('error: ' + e.errno + ' code: ' + e.code);
      process.exit(1);
    }

    if (options.allowUserSpecifiedIds) {
      allowUserSpecifiedIds = true;
    }

    app = connect();
    app.use(connect.cors());
    app.use(connect.static(options.client || __dirname + '/../public'));
    if (connect.json) {
      app.use(connect.json());
      app.use(connect.urlencoded());
    } else {
      // XXX Trickery to get around connect 1.7 vs 1.8 vs 2.x issues
      var bP = connect.bodyParser();

      app.use(modifiedBodyParser);
    }
    app.use(connect.query());
      //, connect.methodOverride()
    if (!connect.router) {
      connect.router = require('connect_router');
    }
    app.use(connect.router(router));
      // Development
    app.use(connect.errorHandler({ dumpExceptions: true, showStack: true }));
      // Production
      //, connect.errorHandler()

    return app;
  }

  module.exports.create = create;
}());
<commit_msg>respond with content-type json<commit_after>(function () {
  "use strict";
  /**
   * Module dependencies.
   */

  var connect = require('connect')
    , fs = require('fs.extra')
    , assert = require('assert')
    , Futures = require('futures')
    , Formaline = require('formaline')
      // The DropShare Epoch -- 1320969600000 -- Fri, 11 Nov 2011 00:00:00 GMT
    , generateId = require('./gen-id').create(1320769600000)
    , storage
    , filesDir = __dirname + '/../files'
    , allowUserSpecifiedIds = false
    , app
    ;

  connect.cors = require('connect-cors');

  // Routes
  function createIds(req, res, next) {
    var i
      , sequence = Futures.sequence()
      , ids = []
      , id
      , meta
      , err
      , now = Date.now()
      ;

    if (!Array.isArray(req.body)) {
      var err = {
        "result": "error",
        "data": "Must be an array of file metadata."
      };

      res.end(JSON.stringify(err), 400);
      return;
    }

    // TODO use forEachAsync
    req.body.forEach(function (meta, i) {
      meta.timestamp = now;
      if (allowUserSpecifiedIds && meta.id) {
        id = meta.id;
      }
      else {
        id = generateId();
      }
      //Dang for loops and closures
      (function (fileId) {
        sequence.then(function (next) {
          storage.set(fileId, meta, function (err, data) {
            ids.push(fileId);
            next();
          });
        });
      })(id);
    });

    sequence.then(function (next) {
      res.writeHead(200, {'content-type': 'application/json'});
      res.write(JSON.stringify(ids));
      res.end();
      next();
    });
  }

  function handleUploadedFiles (json, res) {
    var responses = []
      , sequence = require('sequence')()
      ;

    json.files.forEach(function (fileObj) {
      (function (fileData) {
        sequence.then(function (next) {
          handleUploadedFile(fileData, function (response) {
            responses.push(response);
            next();
          });
        });
      })(fileObj);
    });

    sequence.then(function (next) {
      res.writeHead(200, {"content-type": "application/json"});
      res.end(formatFileUploadResponses(responses));
      next();
    });
  }

  function handleUploadedFile (file, cb) {
    // Check that metadata exists for this ID
    storage.get(file.name, function (err, result) {
      var response;
      if (err !== null || result === null) {
        cb({
          "result": "error",
          "data": "No metadata for id '" + file.name + "'."
        });
        return;
      }

      // If metadata exists, then move the file and update the metadata with the new path
      var res = moveFileToStorage(file.name, file.value[0], cb({
        "result": "success",
        "data": "File " + file.name + " stored successfully."
      }));
    });
  }

  function moveFileToStorage(fileId, file) {
    var is
      , os
      , newFilePath = filesDir + '/' + file.sha1checksum
      ;

    fs.stat(file.path, function (err, stat) {
      assert.strictEqual(err, null, "tried to move a non-existent file");

      //check if file with same checksum already exists
      fs.stat(newFilePath, function (statErr, stat) {
        if (typeof stat === "undefined") {
          // File does not exist already, so move it in to place
          fs.move(file.path, newFilePath, function (movErr) {
            if (movErr) {
              console.warn('Error moving file to storage: ' + movErr.toString());
              //throw err;
            }

          });
        }
        else {
        }

        addSHA1ToMetadata(fileId, file.sha1checksum);
      });
    });
  }

  function addSHA1ToMetadata(id, checksum) {
    storage.get(id, function (err, data, isJSON) {
      assert.ok(isJSON, "Metadata is not JSON");

      data.sha1checksum = checksum;
      storage.set(id, data, function (err, res) {
        assert.deepEqual(err, null, "Error storing metadata again.");
      });
    });
  }

  function formatFileUploadResponses (responses) {
    return JSON.stringify(responses);
  }

  function receiveFiles(req, res, next) {
    var form
      , config
      ;

    config = {
        sha1sum: true
      , removeIncompleteFiles: true
      , uploadThreshold: 1024 * 1024 * 1024
      , listeners: {
            'fileprogress': function (ev, chunk) {
              // here's where we could snatch the target data
              // as it is streaming
            }

          , 'loadend': function (json, res, callback) {
              console.log('\njson is\n', json);
              try {
                callback(json, res);
              } catch ( err ) {
                console.error( 'error', err.stack );
              }
            }

          , 'error': function (err) {
              console.error('[formaline error]');
              console.error(err && err.stack || err);
              console.error(arguments);
            }

      } // end listeners
    }; // end config object

    // XXX Trickery to get around connect 1.7 vs 1.8 vs 2.x issues
    req.body = undefined;
    form = new Formaline(config);
    form.parse(req, res, handleUploadedFiles);
  }

  function checkForFileExistence(req, res, err, data) {
    if (err || data === null || typeof(data.sha1checksum) === "undefined") {
      res.writeHead(400, {'content-type': 'application/json'});
      res.write(JSON.stringify({
        "result": "error",
        "data": "No files uploaded for " + req.params.id + "."
      }));
      res.end();
      return false;
    }
    return true;
  }

  function sendFile(req, res, next) {
    storage.get(req.params.id, function (err, data) {
      if (!checkForFileExistence(req, res, err, data)) {
        return;
      }

      fs.readFile(filesDir + '/' + data.sha1checksum, function (err, fileData) {
        if (err) {
          console.warn('trying to get a file that\'s probably deleted');
          res.end(JSON.stringify({
              'error': true
            , 'result': 'error'
            , 'errors': ['No file found for ' + req.params.id + '.']
          }), 500);
          return;
        }

        res.writeHead(200, {'content-type': data.type });
        res.write(fileData);
        res.end();
      });

    });
  }

  function getMetadata(req, res, next) {
    storage.get(req.params.id, function (err, data) {
      if (err !== null || data === null) {
        res.writeHead(400, {'content-type': 'application/json'});
        res.end(JSON.stringify({
            'error': true
          , 'result': 'error'
          , 'errors': ['No metadata for ' + req.params.id + '.']
        }));
        return;
      }

      res.writeHead(200, {'content-type': 'application/json'});
      var response = {
          'success': true
        , 'result': data
        , 'error': false
        , 'errors': []
      };
      res.end(JSON.stringify(response));
    });
  }

  // Delete both the metadata and the file on the FS.
  // NOTE: this will break stuff it multiple IDs refer to the same
  // file. For example, if the same file is uploaded multiple times,
  // it will have the same sha1 hash. If one ID is DELETEd, it will
  // delete the file that other IDs refer to, and then a GET is
  // issued for a different ID that refers to the same file,
  // it will explode.

  // This could be fixed by storing a list of IDs files keyed by
  // the SHA1 hash of the file the refer to.
  function removeFile(req, res, next) {
    var id = req.params.id
      ;

    storage.get(id, function (err, data) {
      if (!checkForFileExistence(req, res, err, data)) {
        return;
      }

      function error(res, data) {
          res.writeHead(500, {'content-type': 'application/json'});
          res.write(JSON.stringify({
            "result": "error",
            "data": "Error in deleting " + data.id + "."
          }));
          res.end();
          return;
      }

      //Delete from Redis
      storage.del(id, function (err) {
        if (err) {
          error(res, data);
          return;
        }

        //Delete from fs
        fs.unlink(filesDir + '/' + data.sha1checksum, function (err) {
          if (err) {
            error(res, data);
            return;
          }

          res.writeHead(200, {'content-type': 'application/json'});
          res.write(JSON.stringify({
            "result": "success",
            "data": "Successfully deleted " + req.params.id + "."
          }));
          res.end();
        });
      });
    });
  }

  function create(options) {

    var filesDirStats
      ;

    function router(app) {
      /*
      app.get('/fs-meta', getAllFsFilesInfo);
      app.get('/fs-meta/*', getFsFileInfo);
      app.delete('/fs-meta/*', removeFile);
      app.get('/fs/*', getFsFile);
      app.post('/fs/*', createFsFile);
      app.put('/fs/*', createFsFile);
      */

      app.post('/meta/new', createIds);
      app.get('/meta/:id', getMetadata);
      app.delete('/meta/:id', removeFile);
      // deprecated
      app.delete('/files/:id', removeFile);
      app.post('/files/new', createIds);

      app.post('/files', receiveFiles);
      app.get('/files/:id/:filename?', sendFile);
    }

    function modifiedBodyParser(req, res, next) {
      var multi = connect.bodyParser.parse['multipart/form-data'];
      connect.bodyParser.parse['multipart/form-data'] = undefined;
      bP(req, res, function () {
        connect.bodyParser.parse['multipart/form-data'] = multi;
        next();
      });
    }

    options = options || {};

    // there could potentially be a race condition here at startup
    // should be negligible
    storage = require('./redis-wrapper').create(options.redis || {});

    filesDir = options.storageDir || options.files || filesDir;

    // Make sure filesDir exists and is writable
    try {
      filesDirStats = fs.statSync(filesDir);
      if (!filesDirStats.isDirectory()) {
        throw new Error('Storage path is not a directory!');
      }
    }
    catch (e) {
      console.warn('Storage directory is not writeable or does not exist: ' + e.path);
      console.warn('error: ' + e.errno + ' code: ' + e.code);
      process.exit(1);
    }

    if (options.allowUserSpecifiedIds) {
      allowUserSpecifiedIds = true;
    }

    app = connect();
    app.use(connect.cors());
    app.use(connect.static(options.client || __dirname + '/../public'));
    if (connect.json) {
      app.use(connect.json());
      app.use(connect.urlencoded());
    } else {
      // XXX Trickery to get around connect 1.7 vs 1.8 vs 2.x issues
      var bP = connect.bodyParser();

      app.use(modifiedBodyParser);
    }
    app.use(connect.query());
      //, connect.methodOverride()
    if (!connect.router) {
      connect.router = require('connect_router');
    }
    app.use(connect.router(router));
      // Development
    app.use(connect.errorHandler({ dumpExceptions: true, showStack: true }));
      // Production
      //, connect.errorHandler()

    return app;
  }

  module.exports.create = create;
}());
<|endoftext|>


<commit_before>/**
 * jquery.citys.js 1.0
 * http://passer-by.com
 */
;(function($, window, document, undefined) {
    $.fn.citys = function(parameter) {
        parameter = parameter || {};
        var defaults = {
            dataUrl:'citys.json',     //数据库地址
            provinceField:'province', //省份字段名
            cityField:'city',         //城市字段名
            areaField:'area',         //地区字段名
            province:0,               //省份,可以为地区编码或者名称
            city:0,                   //城市,可以为地区编码或者名称
            area:0,                   //地区,可以为地区编码或者名称
            required: true,           //是否必须选一个
            nodata:'hidden',          //当无数据时的表现形式
            onChange:function(){}     //地区切换时触发,回调函数传入地区数据
        };
        var options = $.extend({}, defaults, parameter);
        return this.each(function() {
            //对象定义
            var $this = $(this);
            var $province = $this.find('select[name="'+options.provinceField+'"]'),
                $city = $this.find('select[name="'+options.cityField+'"]'),
                $area = $this.find('select[name="'+options.areaField+'"]');
            $.getJSON(options.dataUrl,function(data){
                var province,city,area,hasCity;
                for(code in data){
                  if(data[code].indexOf(options.province)>-1){
                    options.province = isNaN(options.province)?code:options.province;
                  }else if(data[code].indexOf(options.city)>-1){
                    options.city = isNaN(options.city)?code:options.city;
                  }else if(data[code].indexOf(options.area)>-1){
                    options.area = isNaN(options.area)?code:options.area;
                  }
                }
                var updateData = function(){
                  province = {},city={},area={};
                  hasCity = false;       //判断是非有地级城市
                  for(code in data){
                    if(!(code%1e4)){     //获取所有的省级行政单位
                      province[code]=data[code];
                      if(!options.province){
                        options.province = code;
                      }
                    }else{
                      var p = code-options.province;
                      if(options.province&&p>0&&p<1e4){    //同省的城市或地区
                        if(!(code%100)){
                          hasCity = true;
                          city[code]=data[code];
                          if(!options.city){
                            options.city = code;
                          }
                        }else if(p>9000){                   //省直辖县级行政单位
                          city[code]=data[code];
                        }else{
                          if(hasCity){
                            var c = code-options.city;
                            if(options.city&&c>0&&c<100){   //同个城市的地区
                              area[code]=data[code];
                            }
                          }else{
                            city[code]=data[code];          //直辖市处理
                          }
                        }
                      }
                    }
                  }
                };
                var change = function(){
                  var status = {
                    province:data[options.province],
                    city:data[options.city],
                    area:data[options.area]
                  }
                  options.onChange(status);
                };
                var format = {
                  province:function(){
                    $province.empty();
                    if(!options.required){
                      $province.append('<option> - 请选择 - </options>');
                    }
                    for(i in province){
                      $province.append('<option value="'+i+'">'+province[i]+'</option>');
                    }
                    if(options.province){
                      $province.val(options.province);
                    }
                    this.city();
                  },
                  city:function(){
                    $city.empty();
                    if(!options.required){
                      $city.append('<option> - 请选择 - </options>');
                    }
                    if(options.nodata=='disabled'){
                        $city.prop('disabled',$.isEmptyObject(city));
                    }else{
                        $city.css('display',$.isEmptyObject(city)?'none':'');
                    }
                    for(i in city){
                      $city.append('<option value="'+i+'">'+city[i]+'</option>');
                    }
                    if(options.city){
                      $city.val(options.city);
                    }
                    this.area();
                  },
                  area:function(){
                    $area.empty();
                    if(!options.required){
                      $area.append('<option> - 请选择 - </options>');
                    }
                    if(options.nodata=='disabled'){
                        $area.prop('disabled',$.isEmptyObject(area));
                    }else{
                        $area.css('display',$.isEmptyObject(area)?'none':'');
                    }
                    for(i in area){
                      $area.append('<option value="'+i+'">'+area[i]+'</option>');
                    }
                    if(options.area){
                      $area.val(options.area);
                    }
                  }
                };
                $province.on('change',function(){
                  options.province = $(this).val().replace(/\d{4}$/,'0000');
                  options.city = 0;
                  options.area = 0;
                  updateData();
                  change();
                  format.city();
                });
                $city.on('change',function(){
                  options.city = $(this).val().replace(/\d{2}$/,'00');
                  options.area = 0;
                  updateData();
                  change();
                  format.area();
                });
                $area.on('change',function(){
                  change();
                });
                //初始化
                updateData();
                format.province();
            });
        });
    };
})(jQuery, window, document);
<commit_msg>updated 容错处理<commit_after>/**
 * jquery.citys.js 1.0
 * http://passer-by.com
 */
;(function($, window, document, undefined) {
    $.fn.citys = function(parameter) {
        parameter = parameter || {};
        var defaults = {
            dataUrl:'citys.json',     //数据库地址
            provinceField:'province', //省份字段名
            cityField:'city',         //城市字段名
            areaField:'area',         //地区字段名
            province:0,               //省份,可以为地区编码或者名称
            city:0,                   //城市,可以为地区编码或者名称
            area:0,                   //地区,可以为地区编码或者名称
            required: true,           //是否必须选一个
            nodata:'hidden',          //当无数据时的表现形式
            onChange:function(){}     //地区切换时触发,回调函数传入地区数据
        };
        var options = $.extend({}, defaults, parameter);
        return this.each(function() {
            //对象定义
            var $this = $(this);
            var $province = $this.find('select[name="'+options.provinceField+'"]'),
                $city = $this.find('select[name="'+options.cityField+'"]'),
                $area = $this.find('select[name="'+options.areaField+'"]');
            $.getJSON(options.dataUrl,function(data){
                var province,city,area,hasCity;
                var updateData = function(){
                  province = {},city={},area={};
                  hasCity = false;       //判断是非有地级城市
                  for(code in data){
                    if(!(code%1e4)){     //获取所有的省级行政单位
                      province[code]=data[code];
                      if(!options.province){
                        options.province = code;
                      }else if(data[code].indexOf(options.province)>-1){
                        options.province = isNaN(options.province)?code:options.province;
                      }
                    }else{
                      var p = code-options.province;
                      if(options.province&&p>0&&p<1e4){    //同省的城市或地区
                        if(!(code%100)){
                          hasCity = true;
                          city[code]=data[code];
                          if(!options.city){
                            options.city = code;
                          }else if(data[code].indexOf(options.city)>-1){
                            options.city = isNaN(options.city)?code:options.city;
                          }
                        }else if(p>9000){                   //省直辖县级行政单位
                          city[code]=data[code];
                        }else if(hasCity){                  //非直辖市
                          var c = code-options.city;
                          if(options.city&&c>0&&c<100){     //同个城市的地区
                            area[code]=data[code];
                            if(!options.area){
                              options.area = code;
                            }else if(data[code].indexOf(options.area)>-1){
                              options.area = isNaN(options.area)?code:options.area;
                            }
                          }
                        }else{
                          city[code]=data[code];            //直辖市
                        }
                      }
                    }
                  }
                };
                var change = function(){
                  var status = {
                    province:data[options.province],
                    city:data[options.city],
                    area:data[options.area]
                  }
                  options.onChange(status);
                };
                var format = {
                  province:function(){
                    $province.empty();
                    if(!options.required){
                      $province.append('<option> - 请选择 - </options>');
                    }
                    for(i in province){
                      $province.append('<option value="'+i+'">'+province[i]+'</option>');
                    }
                    if(options.province){
                      $province.val(options.province);
                    }
                    this.city();
                  },
                  city:function(){
                    $city.empty();
                    if(!options.required){
                      $city.append('<option> - 请选择 - </options>');
                    }
                    if(options.nodata=='disabled'){
                        $city.prop('disabled',$.isEmptyObject(city));
                    }else{
                        $city.css('display',$.isEmptyObject(city)?'none':'');
                    }
                    for(i in city){
                      $city.append('<option value="'+i+'">'+city[i]+'</option>');
                    }
                    if(options.city){
                      $city.val(options.city);
                    }
                    this.area();
                  },
                  area:function(){
                    $area.empty();
                    if(!options.required){
                      $area.append('<option> - 请选择 - </options>');
                    }
                    if(options.nodata=='disabled'){
                        $area.prop('disabled',$.isEmptyObject(area));
                    }else{
                        $area.css('display',$.isEmptyObject(area)?'none':'');
                    }
                    for(i in area){
                      $area.append('<option value="'+i+'">'+area[i]+'</option>');
                    }
                    if(options.area){
                      $area.val(options.area);
                    }
                  }
                };
                $province.on('change',function(){
                  options.province = $(this).val().replace(/\d{4}$/,'0000');
                  options.city = 0;
                  options.area = 0;
                  updateData();
                  change();
                  format.city();
                });
                $city.on('change',function(){
                  options.city = $(this).val().replace(/\d{2}$/,'00');
                  options.area = 0;
                  updateData();
                  change();
                  format.area();
                });
                $area.on('change',function(){
                  change();
                });
                //初始化
                updateData();
                format.province();
            });
        });
    };
})(jQuery, window, document);
<|endoftext|>


<commit_before>
let rnil = () => null
let EventEmitter = require('events').EventEmitter

let electron = {
  '@noCallThru': true,
  '@global': true,
  app: {
    getVersion: () => '1.0',
    getPath: () => 'tmp/',
    makeSingleInstance: (cb) => false,
    quit: rnil,
    on: rnil,
    dock: {
      setMenu: rnil,
      bounce: rnil,
      setBadge: rnil
    }
  },
  Tray: function () {
    Object.assign(this, electron.Tray)
  },
  BrowserWindow: function () {
    Object.assign(this, electron.BrowserWindow)
  },
  ipcMain: Object.assign({}, EventEmitter.prototype),
  ipcRenderer: Object.assign({
    send: function () {
      let args = []
      for (let i = 0; i < arguments.length; i++) {
        args.push(arguments[i])
      }
      args.splice(1, 0, {}) // inject fake 'ev' object
      electron.ipcMain.emit.apply(electron.ipcMain, args)
    }
  }, EventEmitter.prototype),
  remote: {
    require: (path) => ({})
  },
  shell: {
    openItem: rnil,
    openExternal: rnil
  },
  dialog: {
    showMessageBox: rnil
  },
  Menu: {
    buildFromTemplate: rnil,
    setApplicationMenu: rnil
  }
}

electron.ipcRenderer.setMaxListeners(Infinity)
electron.ipcMain.setMaxListeners(Infinity)

electron.remote.app = electron.app

Object.assign(electron.Tray, {
  setToolTip: rnil,
  setContextMenu: rnil,
  on: rnil,
  displayBalloon: rnil // win32-only
})

let webContents = {
  on: (e, cb) => cb(),
  executeJavaScript: rnil,
  openDevTools: rnil
}

Object.assign(electron.BrowserWindow, {
  getAllWindows: () => [],
  getFocusedWindow: () => null,
  setProgressBar: rnil,
  on: rnil,
  loadURL: rnil,
  hide: rnil,
  show: rnil,
  close: rnil,
  webContents
})

module.exports = {
  'electron': electron
}
<commit_msg>:green_heart:<commit_after>
let rnil = () => null
let EventEmitter = require('events').EventEmitter

let electron = {
  '@noCallThru': true,
  '@global': true,
  app: {
    getVersion: () => '1.0',
    getPath: () => 'tmp/',
    makeSingleInstance: (cb) => false,
    quit: rnil,
    on: rnil,
    dock: {
      setMenu: rnil,
      bounce: rnil,
      setBadge: rnil
    }
  },
  Tray: function () {
    Object.assign(this, electron.Tray)
  },
  BrowserWindow: function () {
    Object.assign(this, electron.BrowserWindow)
  },
  ipcMain: Object.assign({}, EventEmitter.prototype),
  ipcRenderer: Object.assign({
    send: function () {
      let args = []
      for (let i = 0; i < arguments.length; i++) {
        args.push(arguments[i])
      }
      args.splice(1, 0, {}) // inject fake 'ev' object
      electron.ipcMain.emit.apply(electron.ipcMain, args)
    }
  }, EventEmitter.prototype),
  remote: {
    require: (path) => ({})
  },
  shell: {
    openItem: rnil,
    openExternal: rnil
  },
  dialog: {
    showMessageBox: rnil
  },
  Menu: {
    buildFromTemplate: rnil,
    setApplicationMenu: rnil
  }
}

electron.ipcRenderer.setMaxListeners(Infinity)
electron.ipcMain.setMaxListeners(Infinity)

electron.remote.app = electron.app

Object.assign(electron.Tray, {
  setToolTip: rnil,
  setContextMenu: rnil,
  on: rnil,
  displayBalloon: rnil // win32-only
})

let webRequest = {
  onBeforeSendHeaders: rnil
}

let session = {
  clearCache: (f) => f(),
  webRequest
}

let webContents = {
  on: (e, cb) => cb({preventDefault: rnil}),
  executeJavaScript: rnil,
  insertCSS: rnil,
  openDevTools: rnil,
  getUserAgent: () => 'tester',
  setUserAgent: rnil,
  session
}

Object.assign(electron.BrowserWindow, {
  getAllWindows: () => [],
  getFocusedWindow: () => null,
  setProgressBar: rnil,
  on: rnil,
  loadURL: rnil,
  setMenu: rnil,
  hide: rnil,
  show: rnil,
  close: rnil,
  webContents
})

module.exports = {
  'electron': electron
}
<|endoftext|>


<commit_before>'use strict';

angular.module('simple-autocomplete', [])
	.directive('autocomplete', ['autocomplete-keys', '$window', '$timeout', function(Keys, $window, $timeout) {
		return {
			template: '<input type="text" class="autocomplete-input" placeholder="{{placeHolder}}"' +
							'ng-class="inputClass"' +
							'ng-model="searchTerm"' +
							'ng-keydown="keyDown($event)"' +
							'ng-blur="onBlur()" />' +

						'
' +
							'
' +
								'
' +
									'No matches' +
								'
' +

								'
' +
									'
' +
										'{{option[displayProperty]}}' +
									'
' +
								'
' +
							'
' +
						'
',
			restrict: 'E',
			scope: {
				options: '=',
				onSelect: '=',
				displayProperty: '=',
				inputClass: '@',
				clearInput: '@',
				placeHolder: '@'
			},
			controller: function($scope){
				$scope.searchTerm = '';
				$scope.highlightedOption = null;
				$scope.showOptions = false;
				$scope.matchingOptions = [];
				$scope.hasMatches = false;
				$scope.selectedOption = null;

				$scope.isOptionSelected = function(option) {
					return option === $scope.highlightedOption;
				};

				$scope.processSearchTerm = function(term) {
					console.log('ch-ch-ch-changin');
					if (term.length > 0) {
						if ($scope.selectedOption) {
							if (term != $scope.selectedOption[$scope.displayProperty]) {
								$scope.selectedOption = null;
							} else {
								$scope.closeAndClear();
								return;
							}
						}

						var matchingOptions = $scope.findMatchingOptions(term);
						$scope.matchingOptions = matchingOptions;
						if (!$scope.matchingOptions.indexOf($scope.highlightedOption) != -1) {
							$scope.clearHighlight();
						}
						$scope.hasMatches = matchingOptions.length > 0;
						$scope.showOptions = true;
					} else {
						$scope.closeAndClear();
					}
				};

				$scope.findMatchingOptions = function(term) {
					return $scope.options.filter(function(option) {
						var lowerCaseOption = option[$scope.displayProperty].toLowerCase();
						var lowerCaseTerm = term.toLowerCase();
						return lowerCaseOption.indexOf(lowerCaseTerm) != -1;
					});
				};

				$scope.findExactMatchingOptions = function(term) {
					return $scope.options.filter(function(option) {
						var lowerCaseOption = option[$scope.displayProperty].toLowerCase();
						var lowerCaseTerm = term.toLowerCase();
						return lowerCaseOption == lowerCaseTerm;
					});
				};

				$scope.keyDown = function(e) {
					switch(e.which) {
						case Keys.upArrow:
							e.preventDefault();
							if ($scope.showOptions) {
								$scope.highlightPrevious();
							}
							break;
						case Keys.downArrow:
							e.preventDefault();
							if ($scope.showOptions) {
								$scope.highlightNext();
							} else {
								$scope.showOptions = true;
								if ($scope.selectedOption) {
									$scope.highlightedOption = $scope.selectedOption;
								}
							}
							break;
						case Keys.enter:
							e.preventDefault();
							if ($scope.highlightedOption) {
								$scope.selectOption($scope.highlightedOption);
							} else {
								var exactMatches = $scope.findExactMatchingOptions($scope.searchTerm);
								if (exactMatches[0]) {
									$scope.selectOption(exactMatches[0]);
								}
							}
							break;
						case Keys.escape:
							$scope.closeAndClear();
							break;
					}
				};

				$scope.$watch('searchTerm', function(term){
					$scope.processSearchTerm(term);
				});

				$scope.highlightNext = function() {
					if (!$scope.highlightedOption) {
						$scope.highlightedOption = $scope.matchingOptions[0];
					} else {
						var currentIndex = $scope.currentOptionIndex();
						var nextIndex = currentIndex + 1 == $scope.matchingOptions.length ? 0 : currentIndex + 1;
						$scope.highlightedOption = $scope.matchingOptions[nextIndex];
					}
				};

				$scope.highlightPrevious = function() {
					if (!$scope.highlightedOption) {
						$scope.highlightedOption = $scope.matchingOptions[$scope.matchingOptions.length - 1];
					} else {
						var currentIndex = $scope.currentOptionIndex();
						var previousIndex = currentIndex == 0 ? $scope.matchingOptions.length - 1 : currentIndex - 1;
						$scope.highlightedOption = $scope.matchingOptions[previousIndex];
					}
				};

				$scope.onOptionHover = function(option) {
					$scope.highlightedOption = option;
				};

				$scope.onOptionClick = function(option) {
					console.log('clicking on optin');
				};

				$scope.$on('simple-autocomplete:clearInput', function() {
					$scope.searchTerm = '';
				});

				$scope.clearHighlight = function() {
					$scope.highlightedOption = null;
				};

				$scope.closeAndClear = function() {
					$scope.showOptions = false;
					$scope.clearHighlight();
				};

				$scope.selectOption = function(option) {
					console.log('selected the option');
					$scope.selectedOption = option;
					$scope.onSelect(option);

					if ($scope.clearInput != 'False' && $scope.clearInput != 'false') {
						$scope.searchTerm = '';
					} else {
						$scope.searchTerm = option[$scope.displayProperty];
					}

					$scope.closeAndClear();
				};

				$scope.onBlur = function() {
					$scope.closeAndClear();
				};

				$scope.currentOptionIndex = function() {
					return $scope.matchingOptions.indexOf($scope.highlightedOption);
				};
			},
			link: function(scope, elem, attrs) {
				scope.optionWidth = '400px';
				var inputElement = elem.children('.autocomplete-input')[0];

				scope.setOptionWidth = function() {
					console.log(inputElement.offsetWidth);
					$timeout(function() {
						var pixelWidth = inputElement.offsetWidth > 400 ? 400 : inputElement.offsetWidth - 2;
						scope.optionWidth = pixelWidth + 'px';
					});
				};

				angular.element(document).ready(function() {
					scope.setOptionWidth();
				});

				angular.element($window).bind('resize', function() {
	                scope.setOptionWidth();
	            });
			}
		};
	}])

	.factory('autocomplete-keys', function() {
		return {
			upArrow: 38,
			downArrow: 40,
			enter: 13,
			escape: 27
		};
	});<commit_msg>check for presence of display-property on options object<commit_after>'use strict';

angular.module('simple-autocomplete', [])
	.directive('autocomplete', ['autocomplete-keys', '$window', '$timeout', function(Keys, $window, $timeout) {
		return {
			template: '<input type="text" class="autocomplete-input" placeholder="{{placeHolder}}"' +
							'ng-class="inputClass"' +
							'ng-model="searchTerm"' +
							'ng-keydown="keyDown($event)"' +
							'ng-blur="onBlur()" />' +

						'
' +
							'
' +
								'
' +
									'No matches' +
								'
' +

								'
' +
									'
' +
										'{{option[displayProperty]}}' +
									'
' +
								'
' +
							'
' +
						'
',
			restrict: 'E',
			scope: {
				options: '=',
				onSelect: '=',
				displayProperty: '=',
				inputClass: '@',
				clearInput: '@',
				placeHolder: '@'
			},
			controller: function($scope){
				$scope.searchTerm = '';
				$scope.highlightedOption = null;
				$scope.showOptions = false;
				$scope.matchingOptions = [];
				$scope.hasMatches = false;
				$scope.selectedOption = null;

				$scope.isOptionSelected = function(option) {
					return option === $scope.highlightedOption;
				};

				$scope.processSearchTerm = function(term) {
					console.log('ch-ch-ch-changin');
					if (term.length > 0) {
						if ($scope.selectedOption) {
							if (term != $scope.selectedOption[$scope.displayProperty]) {
								$scope.selectedOption = null;
							} else {
								$scope.closeAndClear();
								return;
							}
						}

						var matchingOptions = $scope.findMatchingOptions(term);
						$scope.matchingOptions = matchingOptions;
						if (!$scope.matchingOptions.indexOf($scope.highlightedOption) != -1) {
							$scope.clearHighlight();
						}
						$scope.hasMatches = matchingOptions.length > 0;
						$scope.showOptions = true;
					} else {
						$scope.closeAndClear();
					}
				};

				$scope.findMatchingOptions = function(term) {
					return $scope.options.filter(function(option) {
						var searchProperty = option[$scope.displayProperty];
						if (searchProperty) {
							var lowerCaseOption = searchProperty.toLowerCase();
							var lowerCaseTerm = term.toLowerCase();
							return lowerCaseOption.indexOf(lowerCaseTerm) != -1;
						}
						return false;
					});
				};

				$scope.findExactMatchingOptions = function(term) {
					return $scope.options.filter(function(option) {
						var lowerCaseOption = option[$scope.displayProperty].toLowerCase();
						var lowerCaseTerm = term.toLowerCase();
						return lowerCaseOption == lowerCaseTerm;
					});
				};

				$scope.keyDown = function(e) {
					switch(e.which) {
						case Keys.upArrow:
							e.preventDefault();
							if ($scope.showOptions) {
								$scope.highlightPrevious();
							}
							break;
						case Keys.downArrow:
							e.preventDefault();
							if ($scope.showOptions) {
								$scope.highlightNext();
							} else {
								$scope.showOptions = true;
								if ($scope.selectedOption) {
									$scope.highlightedOption = $scope.selectedOption;
								}
							}
							break;
						case Keys.enter:
							e.preventDefault();
							if ($scope.highlightedOption) {
								$scope.selectOption($scope.highlightedOption);
							} else {
								var exactMatches = $scope.findExactMatchingOptions($scope.searchTerm);
								if (exactMatches[0]) {
									$scope.selectOption(exactMatches[0]);
								}
							}
							break;
						case Keys.escape:
							$scope.closeAndClear();
							break;
					}
				};

				$scope.$watch('searchTerm', function(term){
					$scope.processSearchTerm(term);
				});

				$scope.highlightNext = function() {
					if (!$scope.highlightedOption) {
						$scope.highlightedOption = $scope.matchingOptions[0];
					} else {
						var currentIndex = $scope.currentOptionIndex();
						var nextIndex = currentIndex + 1 == $scope.matchingOptions.length ? 0 : currentIndex + 1;
						$scope.highlightedOption = $scope.matchingOptions[nextIndex];
					}
				};

				$scope.highlightPrevious = function() {
					if (!$scope.highlightedOption) {
						$scope.highlightedOption = $scope.matchingOptions[$scope.matchingOptions.length - 1];
					} else {
						var currentIndex = $scope.currentOptionIndex();
						var previousIndex = currentIndex == 0 ? $scope.matchingOptions.length - 1 : currentIndex - 1;
						$scope.highlightedOption = $scope.matchingOptions[previousIndex];
					}
				};

				$scope.onOptionHover = function(option) {
					$scope.highlightedOption = option;
				};

				$scope.onOptionClick = function(option) {
					console.log('clicking on optin');
				};

				$scope.$on('simple-autocomplete:clearInput', function() {
					$scope.searchTerm = '';
				});

				$scope.clearHighlight = function() {
					$scope.highlightedOption = null;
				};

				$scope.closeAndClear = function() {
					$scope.showOptions = false;
					$scope.clearHighlight();
				};

				$scope.selectOption = function(option) {
					console.log('selected the option');
					$scope.selectedOption = option;
					$scope.onSelect(option);

					if ($scope.clearInput != 'False' && $scope.clearInput != 'false') {
						$scope.searchTerm = '';
					} else {
						$scope.searchTerm = option[$scope.displayProperty];
					}

					$scope.closeAndClear();
				};

				$scope.onBlur = function() {
					$scope.closeAndClear();
				};

				$scope.currentOptionIndex = function() {
					return $scope.matchingOptions.indexOf($scope.highlightedOption);
				};
			},
			link: function(scope, elem, attrs) {
				scope.optionWidth = '400px';
				var inputElement = elem.children('.autocomplete-input')[0];

				scope.setOptionWidth = function() {
					console.log(inputElement.offsetWidth);
					$timeout(function() {
						var pixelWidth = inputElement.offsetWidth > 400 ? 400 : inputElement.offsetWidth - 2;
						scope.optionWidth = pixelWidth + 'px';
					});
				};

				angular.element(document).ready(function() {
					scope.setOptionWidth();
				});

				angular.element($window).bind('resize', function() {
	                scope.setOptionWidth();
	            });
			}
		};
	}])

	.factory('autocomplete-keys', function() {
		return {
			upArrow: 38,
			downArrow: 40,
			enter: 13,
			escape: 27
		};
	});<|endoftext|>


<commit_before>'use strict';

export function unique(prefix) {
    let count = -1;
    return f => {
        return `${prefix}_${++count}`;
    };
}

export function noop() {
}

export function callbackTimeout(timer, onSuccess, onTimeout) {

    let timeout = setTimeout(() => {

        onSuccess = noop;
        onTimeout();

    }, timer);

    return function () {
        clearTimeout(timeout);
        onSuccess.apply(this, arguments);
    };
}

export function createElementWithID(parent, id, cleanContent = false) {
    var nEl = document.createElement('div');
    nEl.id = id;
    if (cleanContent) {
        parent.innerHTML = '';
    }
    parent.appendChild(nEl);
    return nEl;
}

export function isPositiveInt(newVal, oldVal) {
    return !isNaN(parseFloat(newVal)) && isFinite(newVal) && newVal > 0 ? newVal : oldVal;
}

let endsWith = (function () {
    if (String.prototype.endsWith) return String.prototype.endsWith;
    return function endsWith (searchString, position) {
        var subjectString = this.toString();
        if (position === undefined || position > subjectString.length) {
            position = subjectString.length;
        }
        position -= searchString.length;
        var lastIndex = subjectString.indexOf(searchString, position);
        return lastIndex !== -1 && lastIndex === position;
    };
})();

export function stringEndsWith(string, search) {
    return endsWith.call(string, search);
}

export function hideFlashEl(el) {
    // can't use display none because will not run the flash
    el.style.position = 'absolute';
    el.style.left = '-1px';
    el.style.top = '-1px';
    el.style.width = '1px';
    el.style.height = '1px';
    el.style.visibility = 'hidden';
}
<commit_msg>[Luis] fix issue in windows (Firefox and IE), visibility was causing the flash test to fail even if the browser supports flash<commit_after>'use strict';

export function unique(prefix) {
    let count = -1;
    return f => {
        return `${prefix}_${++count}`;
    };
}

export function noop() {
}

export function callbackTimeout(timer, onSuccess, onTimeout) {

    let timeout = setTimeout(() => {

        onSuccess = noop;
        onTimeout();

    }, timer);

    return function () {
        clearTimeout(timeout);
        onSuccess.apply(this, arguments);
    };
}

export function createElementWithID(parent, id, cleanContent = false) {
    var nEl = document.createElement('div');
    nEl.id = id;
    if (cleanContent) {
        parent.innerHTML = '';
    }
    parent.appendChild(nEl);
    return nEl;
}

export function isPositiveInt(newVal, oldVal) {
    return !isNaN(parseFloat(newVal)) && isFinite(newVal) && newVal > 0 ? newVal : oldVal;
}

let endsWith = (function () {
    if (String.prototype.endsWith) return String.prototype.endsWith;
    return function endsWith (searchString, position) {
        var subjectString = this.toString();
        if (position === undefined || position > subjectString.length) {
            position = subjectString.length;
        }
        position -= searchString.length;
        var lastIndex = subjectString.indexOf(searchString, position);
        return lastIndex !== -1 && lastIndex === position;
    };
})();

export function stringEndsWith(string, search) {
    return endsWith.call(string, search);
}

export function hideFlashEl(el) {
    // can't use display none or visibility none because will block flash in some browsers
    el.style.position = 'absolute';
    el.style.left = '-1px';
    el.style.top = '-1px';
    el.style.width = '1px';
    el.style.height = '1px';
}
<|endoftext|>


<commit_before>/**
 * Copyright 2015, Yahoo! Inc.
 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */

// some environments run the app from a different directory
process.chdir(__dirname);

require('node-jsx').install({ extension: '.jsx' });
var express = require('express');
var favicon = require('serve-favicon');
var serialize = require('serialize-javascript');
var navigateAction = require('flux-router-component').navigateAction;
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var csrf = require('csurf');
var React = require('react');
var app = require('./app');
var HtmlComponent = React.createFactory(require('./components/Html.jsx'));
var tracking = require('./configs/tracking');

var server = express();
server.set('state namespace', 'App');
server.use(favicon(__dirname + '/assets/images/favicon.ico'));
server.use('/public', express.static(__dirname + '/build'));
server.use(cookieParser());
server.use(bodyParser.json());
server.use(csrf({cookie: true}));

// Get access to the fetchr plugin instance
var fetchrPlugin = app.getPlugin('FetchrPlugin');

// Register our services
fetchrPlugin.registerService(require('./services/docs'));
fetchrPlugin.registerService(require('./services/api'));

// Set up the fetchr middleware
server.use(fetchrPlugin.getXhrPath(), fetchrPlugin.getMiddleware());

// Every other request gets the app bootstrap
server.use(function (req, res, next) {
    var context = app.createContext({
        req: req, // The fetchr plugin depends on this
        xhrContext: {
            _csrf: req.csrfToken() // Make sure all XHR requests have the CSRF token
        }
    });

    context.getActionContext().executeAction(navigateAction, {
        url: req.url
    }, function (err) {
        if (err) {
            if (err.status && err.status === 404) {
                next();
            } else {
                next(err);
            }
            return;
        }

        var exposed = 'window.App=' + serialize(app.dehydrate(context)) + ';';

        var AppComponent = app.getAppComponent();
        var doctype = '<!DOCTYPE html>';
        var html = React.renderToStaticMarkup(HtmlComponent({
            state: exposed,
            context: context.getComponentContext(),
            markup: React.renderToString(AppComponent({
                context: context.getComponentContext()
            })),
            tracking: tracking
        }));

        res.send(doctype + html);
    });
});

var port = process.env.PORT || 3000;
server.listen(port);
console.log('Listening on port ' + port);
<commit_msg>cleaned up server action call<commit_after>/**
 * Copyright 2015, Yahoo! Inc.
 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */

// some environments run the app from a different directory
process.chdir(__dirname);

require('node-jsx').install({ extension: '.jsx' });
var express = require('express');
var favicon = require('serve-favicon');
var serialize = require('serialize-javascript');
var navigateAction = require('flux-router-component').navigateAction;
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var csrf = require('csurf');
var React = require('react');
var app = require('./app');
var HtmlComponent = React.createFactory(require('./components/Html.jsx'));
var tracking = require('./configs/tracking');

var server = express();
server.set('state namespace', 'App');
server.use(favicon(__dirname + '/assets/images/favicon.ico'));
server.use('/public', express.static(__dirname + '/build'));
server.use(cookieParser());
server.use(bodyParser.json());
server.use(csrf({cookie: true}));

// Get access to the fetchr plugin instance
var fetchrPlugin = app.getPlugin('FetchrPlugin');

// Register our services
fetchrPlugin.registerService(require('./services/docs'));
fetchrPlugin.registerService(require('./services/api'));

// Set up the fetchr middleware
server.use(fetchrPlugin.getXhrPath(), fetchrPlugin.getMiddleware());

// Every other request gets the app bootstrap
server.use(function (req, res, next) {
    var context = app.createContext({
        req: req, // The fetchr plugin depends on this
        xhrContext: {
            _csrf: req.csrfToken() // Make sure all XHR requests have the CSRF token
        }
    });

    context.executeAction(navigateAction, {
        url: req.url
    }, function (err) {
        if (err) {
            if (err.status && err.status === 404) {
                next();
            } else {
                next(err);
            }
            return;
        }

        var exposed = 'window.App=' + serialize(app.dehydrate(context)) + ';';

        var AppComponent = app.getAppComponent();
        var doctype = '<!DOCTYPE html>';
        var html = React.renderToStaticMarkup(HtmlComponent({
            state: exposed,
            context: context.getComponentContext(),
            markup: React.renderToString(AppComponent({
                context: context.getComponentContext()
            })),
            tracking: tracking
        }));

        res.send(doctype + html);
    });
});

var port = process.env.PORT || 3000;
server.listen(port);
console.log('Listening on port ' + port);
<|endoftext|>