<commit_before>/* InstantClick's loading indicator | (C) 2014-2015 Alexandre Dieulot | http://instantclick.io/license */

;(function() {
  var $container
    , $element
    , $transformProperty
    , $progress
    , $timer
    , $hasTouch = 'createTouch' in document

  function init() {
    $container = document.createElement('div')
    $container.id = 'instantclick'
    $element = document.createElement('div')
    $element.id = 'instantclick-bar'
    $element.className = 'instantclick-bar'
    $container.appendChild($element)

    var vendors = ['Webkit', 'Moz', 'O']

    $transformProperty = 'transform'
    if (!($transformProperty in $element.style)) {
      for (var i = 0; i < vendors.length; i++) {
        if (vendors[i] + 'Transform' in $element.style) {
          $transformProperty = vendors[i] + 'Transform'
        }
      }
    }

    var transitionProperty = 'transition'
    if (!(transitionProperty in $element.style)) {
      for (var i = 0; i < vendors.length; i++) {
        if (vendors[i] + 'Transition' in $element.style) {
          transitionProperty = '-' + vendors[i].toLowerCase() + '-' + transitionProperty
        }
      }
    }

    var style = document.createElement('style')
    style.innerHTML = '#instantclick{position:' + ($hasTouch ? 'absolute' : 'fixed') + ';top:0;left:0;width:100%;pointer-events:none;z-index:2147483647;' + transitionProperty + ':opacity .25s .1s}'
      + '.instantclick-bar{background:#29d;width:100%;margin-left:-100%;height:2px;' + transitionProperty + ':all .25s}'
    /* We set the bar's background in `.instantclick-bar` so that it can be
       overriden in CSS with `#instantclick-bar`, as IDs have higher priority.
    */
    document.head.appendChild(style)

    if ($hasTouch) {
      updatePositionAndScale()
      addEventListener('resize', updatePositionAndScale)
      addEventListener('scroll', updatePositionAndScale)
    }

  }

  function start(at, jump) {
    $progress = at
    if (document.getElementById($container.id)) {
      document.body.removeChild($container)
    }
    $container.style.opacity = '1'
    if (document.getElementById($container.id)) {
      document.body.removeChild($container)
      /* So there's no CSS animation if already done once and it goes from 1 to 0 */
    }
    update()
    if (jump) {
      setTimeout(jumpStart, 0)
      /* Must be done in a timer, otherwise the CSS animation doesn't happen (I don't know why). */
    }
    clearTimeout($timer)
    $timer = setTimeout(inc, 500)
  }

  function jumpStart() {
    $progress = 10
    update()
  }

  function inc() {
    $progress += 1 + (Math.random() * 2)
    if ($progress >= 98) {
      $progress = 98
    }
    else {
      $timer = setTimeout(inc, 500)
    }
    update()
  }

  function update() {
    $element.style[$transformProperty] = 'translate(' + $progress + '%)'
    if (!document.getElementById($container.id)) {
      document.body.appendChild($container)
    }
  }

  function done() {
    if (document.getElementById($container.id)) {
      clearTimeout($timer)
      $progress = 100
      update()
      $container.style.opacity = '0'
      /* When you're debugging, setting this to 0.5 is handy. */
      return
    }

    /* The bar container hasn't been appended: It's a new page. */
    start($progress == 100 ? 0 : $progress)
    /* $progress is 100 on popstate, usually. */
    setTimeout(done, 0)
    /* Must be done in a timer, otherwise the CSS animation doesn't happen. */
  }

  function updatePositionAndScale() {
    /* Adapted from code by Sam Stephenson and Mislav Marohnic
       http://signalvnoise.com/posts/2407
    */

    $container.style.left = pageXOffset + 'px'
    $container.style.width = document.body.clientWidth + 'px'
    $container.style.top = pageYOffset + 'px'

    var landscape = 'orientation' in window && Math.abs(orientation) == 90
      , scaleY = innerWidth / screen[landscape ? 'height' : 'width'] * 2
    /* We multiply the size by 2 because the progress bar is harder
       to notice on a mobile device.
    */
    $container.style[$transformProperty] = 'scaleY(' + scaleY  + ')'
  }

  ////////////////////

  instantClick.on('change', function(isInitialPage) {
    if (isInitialPage && instantClick.supported) {
      init()
    }
    else if (!isInitialPage) {
      done()
    }
  })

  instantClick.on('wait', function() {
    start(0, true)
  })
})();
<commit_msg>More appropriate appearances for the loading indicator<commit_after>/* InstantClick's loading indicator | (C) 2014-2015 Alexandre Dieulot | http://instantclick.io/license */

;(function() {
  var $container
    , $element
    , $transformProperty
    , $progress
    , $timer
    , $hasTouch = 'createTouch' in document

  function init() {
    $container = document.createElement('div')
    $container.id = 'instantclick'
    $element = document.createElement('div')
    $element.id = 'instantclick-bar'
    $element.className = 'instantclick-bar'
    $container.appendChild($element)

    var vendors = ['Webkit', 'Moz', 'O']

    $transformProperty = 'transform'
    if (!($transformProperty in $element.style)) {
      for (var i = 0; i < vendors.length; i++) {
        if (vendors[i] + 'Transform' in $element.style) {
          $transformProperty = vendors[i] + 'Transform'
        }
      }
    }

    var transitionProperty = 'transition'
    if (!(transitionProperty in $element.style)) {
      for (var i = 0; i < vendors.length; i++) {
        if (vendors[i] + 'Transition' in $element.style) {
          transitionProperty = '-' + vendors[i].toLowerCase() + '-' + transitionProperty
        }
      }
    }

    var style = document.createElement('style')
    style.innerHTML = '#instantclick{position:' + ($hasTouch ? 'absolute' : 'fixed') + ';top:0;left:0;width:100%;pointer-events:none;z-index:2147483647;' + transitionProperty + ":opacity 1s}\n"
      + '.instantclick-bar{background:#29d;width:100%;margin-left:-100%;height:2px;' + transitionProperty + ':all 1s}'
    /* We set the bar's background in `.instantclick-bar` so that it can be
       overriden in CSS with `#instantclick-bar`, as IDs have higher priority.
    */
    document.head.appendChild(style)

    if ($hasTouch) {
      updatePositionAndScale()
      addEventListener('resize', updatePositionAndScale)
      addEventListener('scroll', updatePositionAndScale)
    }
  }

  function start() {
    $progress = 0
    $container.style.opacity = '0'
    update()
    setTimeout(display, 0) // Done in a timer to do that on next frame, so that the CSS animation happens
    $timer = setTimeout(inc, 500)
  }

  function display() {
    $progress = 10
    $container.style.opacity = '1'
    update()
  }

  function inc() {
    $progress += 1 + (Math.random() * 2)
    if ($progress > 99) {
      $progress = 99
    }
    else {
      $timer = setTimeout(inc, 500)
    }
    update()
  }

  function update() {
    $element.style[$transformProperty] = 'translate(' + $progress + '%)'
    if (!document.getElementById($container.id)) {
      document.body.appendChild($container)
    }
  }

  function done() {
    clearTimeout($timer)
  }

  function remove() {
    if (document.getElementById($container.id)) {
      document.body.removeChild($container)
    }
  }

  function updatePositionAndScale() {
    /* Adapted from code by Sam Stephenson and Mislav Marohnic
       http://signalvnoise.com/posts/2407
    */

    $container.style.left = pageXOffset + 'px'
    $container.style.width = document.body.clientWidth + 'px'
    $container.style.top = pageYOffset + 'px'

    var landscape = 'orientation' in window && Math.abs(orientation) == 90
      , scaleY = innerWidth / screen[landscape ? 'height' : 'width'] * 1.34
    /* We multiply the size by 2 because the progress bar is harder
       to notice on a mobile device.
    */
    $container.style[$transformProperty] = 'scaleY(' + scaleY  + ')'
  }

  ////////////////////

  instantClick.on('change', function(isInitialPage) {
    if (isInitialPage && instantClick.supported) {
      init()
    }
    else if (!isInitialPage) {
      done()
    }
  })

  instantClick.on('wait', start)

  instantClick.on('restore', remove) // Should be removed in a `beforechange` event instead
})();
<|endoftext|>


<commit_before>function Run() {
  BenchmarkSuite.RunSuites({ NotifyStep: ShowProgress,
                             NotifyError: AddError,
                             NotifyResult: AddResult,
                             NotifyScore: AddScore });
}

function ShowProgress(name) {
  print('PROGRESS', name);
}

function AddError(name, error) {
  print('ERROR', name, error);
  print(error.stack);
}

function AddResult(name, result) {
  print('RESULT', name, result);
}

function AddScore(score) {
  print('SCORE', score);
}

try {
  Run();
} catch (e) {
  print('*** Run() failed');
  print(e.stack || e);
}
<commit_msg>Ensure V8 benchmarks throws at the end with errors<commit_after>var globalObject = new Function('return this')();

if (typeof globalObject.print !== 'function') {
  globalObject.print = globalObject.console.log;
}

function Run() {
  BenchmarkSuite.RunSuites({ NotifyStep: ShowProgress,
                             NotifyError: AddError,
                             NotifyResult: AddResult,
                             NotifyScore: AddScore });
}

var harnessErrorCount = 0;

function ShowProgress(name) {
  print('PROGRESS', name);
}

function AddError(name, error) {
  print('ERROR', name, error);
  print(error.stack);
  harnessErrorCount++;
}

function AddResult(name, result) {
  print('RESULT', name, result);
}

function AddScore(score) {
  print('SCORE', score);
}

try {
  Run();
} catch (e) {
  print('*** Run() failed');
  print(e.stack || e);
}

if (harnessErrorCount > 0) {
  // Throw an error so that 'duk' has a non-zero exit code which helps
  // automatic testing.
  throw new Error('Benchmark had ' + harnessErrorCount + ' errors');
}
<|endoftext|>


<commit_before>// inject environment module into your module
angular.module('acme', ['environment']).
	// inject environmentServiceProvider into your config
	config(function(envServiceProvider) {
		// set the domains and variables for each environment
		envServiceProvider.config({
			domains: {
				development: ['localhost', 'local.dev'],
				production: ['acme.com', '*.dev.prod'],
				test: ['acme.test', 'acme.net', 'acme.*.test']
			},
			vars: {
				development: {
					apiUrl: '//localhost/api',
					staticUrl: '//localhost/static'
					// antoherCustomVar: ''
				},
				production: {
					apiUrl: '//api.acme.dev.prod/v1',
					staticUrl: '//static.acme.dev.prod'
					// antoherCustomVar: ''
				},
				test: {
					apiUrl: '//api.acme.dev.test/v1',
					staticUrl: '//static.acme.test.prod'
					// antoherCustomVar: ''
				}
			}
		});

		// run the environment check, so the comprobation is made
		// before controllers and services are built
		envServiceProvider.check();
	}).
	controller('Pages', ['$scope', 'envService', function($scope, envService) {
		$scope.environment = envService.get(); // store the current environment
		$scope.vars = envService.read('all');
	}]);
<commit_msg>Demo updated<commit_after>// inject environment module into your module
angular.module('acme', ['environment']).
	// inject environmentServiceProvider into your config
	config(function(envServiceProvider) {
		// set the domains and variables for each environment
		envServiceProvider.config({
			domains: {
				development: ['localhost', 'local.dev'],
				production: ['acme.com', '*.dev.prod'],
				test: ['acme.test', 'acme.net', 'acme.*.test']
			},
			vars: {
				development: {
					apiUrl: '//api.acme.dev.local/v1',
					staticUrl: '//static.acme.dev.local'
					// antoherCustomVar: ''
				},
				production: {
					apiUrl: '//api.acme.dev.prod/v1',
					staticUrl: '//static.acme.dev.prod'
					// antoherCustomVar: ''
				},
				test: {
					// apiUrl: '//api.acme.dev.test/v1',
					staticUrl: '//static.acme.dev.test'
					// antoherCustomVar: ''
				},
				defaults: {
					apiUrl: '//api.default.com/v1',
					staticUrl: '//static.default.com/'
				}
			}
		});

		// run the environment check, so the comprobation is made
		// before controllers and services are built
		envServiceProvider.check();
	}).
	controller('Pages', ['$scope', 'envService', function($scope, envService) {
		$scope.environment = envService.get(); // store the current environment
		$scope.vars = envService.read();
		$scope.ble = envService.read('pico');
		console.log('sin argumento devuelve: ' + $scope.vars);
		console.log('variable no existente devuelve: ' + $scope.ble);
	}]);
<|endoftext|>


<commit_before>
var gulp        = require('gulp'),
    sequence    = require('gulp-sequence'),
    jshint      = require('gulp-jshint'), // jshint-stylish
    lintspaces  = require('gulp-lintspaces'),
    rev         = require('gulp-rev'),
    revReplace  = require('gulp-rev-replace'),
    useref      = require('gulp-useref'),
    filter      = require('gulp-filter'),
    uglify      = require('gulp-uglify'),
    csso        = require('gulp-csso'),
    minifyHtml  = require('gulp-minify-html'),

    del         = require('del'),
    browserSync = require('browser-sync'),
    reload      = browserSync.reload,
    pkg         = require('./package.json');

//------------------------------------------------------------------------------
// utils

function projectInfoMsg() {
  console.log('');
  console.log('project: ' + pkg.name + ' v' + pkg.version);
  console.log('description: ' + pkg.description);
  console.log('');
}

//==============================================================================
// @begin: gulp tasks ==========================================================
//==============================================================================
// @begin: clean

gulp.task('clean:dist', del.bind(null, [ 'dist' ]));

gulp.task('clean:bower', del.bind(null, [ '.local/bower' ]));

gulp.task('clean', ['clean:dist', 'clean:bower']);

// @end: clean
//------------------------------------------------------------------------------
// @begin: bower

gulp.task('bower:jquery', function() {
  return gulp.src('bower_components/jquery/dist/*.{js,map}')
    .pipe(gulp.dest('.local/bower/vendor/jquery'))
});

gulp.task('bower:dev', sequence('clean:bower', 'bower:jquery'));

gulp.task('bower:dist', ['bower:dev'], function() {
  return gulp.src('.local/bower/**/*')
    .pipe(gulp.dest('dist'));
});

// @end: bower
//------------------------------------------------------------------------------
// @begin: jshint

gulp.task('jshint:tools', function() { console.log('TODO: define'); });
gulp.task('jshint:project', function() { console.log('TODO: define'); });
gulp.task('jshint', ['jshint:tools', 'jshint:project']);

// @end: jshint
//------------------------------------------------------------------------------
// @begin: lintspaces

gulp.task('lintspaces:tools', function() { console.log('TODO: define'); });
gulp.task('lintspaces:project:js', function() { console.log('TODO: define'); });
gulp.task('lintspaces:project:css', function() { console.log('TODO: define'); });
gulp.task('lintspaces:project:html', function() { console.log('TODO: define'); });
gulp.task('lintspaces:project', ['lintspaces:project:js', 'lintspaces:project:css', 'lintspaces:project:html']);
gulp.task('lintspaces', ['lintspaces:tools', 'lintspaces:project']);

// @end: lintspaces
//------------------------------------------------------------------------------
// validate
gulp.task('validate', ['jshint', 'lintspaces']);

//------------------------------------------------------------------------------
// @begin: build

gulp.task('build:index', function() {

  var jsFilter       = filter( '**/*.js' ),
      cssFilter      = filter( '**/*.css' ),
      htmlFilter     = filter( '**/*.html' ),
      userefAssets   = useref.assets(),
      minifyHtmlOpts = {
        conditionals: true,
        spare:true
      };

  return gulp.src( 'src/index.html' )
    .pipe( userefAssets ) // Concatenate with gulp-useref
    .pipe( jsFilter )
    .pipe( uglify() ) // Minify any javascript sources
    .pipe( jsFilter.restore() )
    .pipe( cssFilter )
    .pipe( csso() ) // Minify any CSS sources
    .pipe( cssFilter.restore() )
    .pipe( rev() ) // Rename the concatenated files
    .pipe( userefAssets.restore() )
    .pipe( useref() )
    .pipe( revReplace() ) // Substitute in new filenames
    .pipe( htmlFilter )
    .pipe( minifyHtml( minifyHtmlOpts ) )
    .pipe( htmlFilter.restore() )
    .pipe( gulp.dest('dist') );

});

gulp.task('build', sequence(['clean:dist', 'validate'], ['build:index', 'bower:dist']));

// @end: build
//------------------------------------------------------------------------------
// @begin: webserver

gulp.task('webserver:dist', ['build'], function() {

  browserSync({
    ui: false,
    port: 1337,
    server:{
      baseDir: 'dist'
    }
  });

});

gulp.task('webserver:dev', ['validate', 'bower:dev'], function() {

  browserSync({
    port: 1337,
    server:{
      baseDir: ['src', '.local/bower']
    }
  });

});

// @end: webserver
//------------------------------------------------------------------------------
// @begin: watch

gulp.task('watch', ['webserver:dev'], function() { console.log('TODO: define'); });

// @end: watch
//------------------------------------------------------------------------------
// @begin: main

gulp.task('default', ['watch'], function() {
  projectInfoMsg();
});

gulp.task('release', ['build'], function() {
  projectInfoMsg();
});

gulp.task('preview', ['webserver:dist'], function() {
  projectInfoMsg();
});

// @end: main
//==============================================================================
// @end: gulp tasks ============================================================
//==============================================================================
<commit_msg>gulp step 01 - jshint:tools task defined<commit_after>
var gulp        = require('gulp'),
    sequence    = require('gulp-sequence'),
    jshint      = require('gulp-jshint'), // jshint-stylish
    lintspaces  = require('gulp-lintspaces'),
    rev         = require('gulp-rev'),
    revReplace  = require('gulp-rev-replace'),
    useref      = require('gulp-useref'),
    filter      = require('gulp-filter'),
    uglify      = require('gulp-uglify'),
    csso        = require('gulp-csso'),
    minifyHtml  = require('gulp-minify-html'),

    del         = require('del'),
    browserSync = require('browser-sync'),
    reload      = browserSync.reload,
    pkg         = require('./package.json');

//------------------------------------------------------------------------------
// utils

function projectInfoMsg() {
  console.log('');
  console.log('project: ' + pkg.name + ' v' + pkg.version);
  console.log('description: ' + pkg.description);
  console.log('');
}

//==============================================================================
// @begin: gulp tasks ==========================================================
//==============================================================================
// @begin: clean

gulp.task('clean:dist', del.bind(null, [ 'dist' ]));

gulp.task('clean:bower', del.bind(null, [ '.local/bower' ]));

gulp.task('clean', ['clean:dist', 'clean:bower']);

// @end: clean
//------------------------------------------------------------------------------
// @begin: bower

gulp.task('bower:jquery', function() {
  return gulp.src('bower_components/jquery/dist/*.{js,map}')
    .pipe(gulp.dest('.local/bower/vendor/jquery'));
});

gulp.task('bower:dev', sequence('clean:bower', 'bower:jquery'));

gulp.task('bower:dist', ['bower:dev'], function() {
  return gulp.src('.local/bower/**/*')
    .pipe(gulp.dest('dist'));
});

// @end: bower
//------------------------------------------------------------------------------
// @begin: jshint

gulp.task('jshint:tools', function() {
  return gulp.src('gulpfile.js')
    .pipe( jshint() )
    .pipe( jshint.reporter('jshint-stylish') )
    .pipe( jshint.reporter('fail') );
});

gulp.task('jshint:project', function() { console.log('TODO: define'); });

gulp.task('jshint', ['jshint:tools', 'jshint:project']);

// @end: jshint
//------------------------------------------------------------------------------
// @begin: lintspaces

gulp.task('lintspaces:tools', function() { console.log('TODO: define'); });
gulp.task('lintspaces:project:js', function() { console.log('TODO: define'); });
gulp.task('lintspaces:project:css', function() { console.log('TODO: define'); });
gulp.task('lintspaces:project:html', function() { console.log('TODO: define'); });
gulp.task('lintspaces:project', ['lintspaces:project:js', 'lintspaces:project:css', 'lintspaces:project:html']);
gulp.task('lintspaces', ['lintspaces:tools', 'lintspaces:project']);

// @end: lintspaces
//------------------------------------------------------------------------------
// validate
gulp.task('validate', ['jshint', 'lintspaces']);

//------------------------------------------------------------------------------
// @begin: build

gulp.task('build:index', function() {

  var jsFilter       = filter( '**/*.js' ),
      cssFilter      = filter( '**/*.css' ),
      htmlFilter     = filter( '**/*.html' ),
      userefAssets   = useref.assets(),
      minifyHtmlOpts = {
        conditionals: true,
        spare:true
      };

  return gulp.src( 'src/index.html' )
    .pipe( userefAssets ) // Concatenate with gulp-useref
    .pipe( jsFilter )
    .pipe( uglify() ) // Minify any javascript sources
    .pipe( jsFilter.restore() )
    .pipe( cssFilter )
    .pipe( csso() ) // Minify any CSS sources
    .pipe( cssFilter.restore() )
    .pipe( rev() ) // Rename the concatenated files
    .pipe( userefAssets.restore() )
    .pipe( useref() )
    .pipe( revReplace() ) // Substitute in new filenames
    .pipe( htmlFilter )
    .pipe( minifyHtml( minifyHtmlOpts ) )
    .pipe( htmlFilter.restore() )
    .pipe( gulp.dest('dist') );

});

gulp.task('build', sequence(['clean:dist', 'validate'], ['build:index', 'bower:dist']));

// @end: build
//------------------------------------------------------------------------------
// @begin: webserver

gulp.task('webserver:dist', ['build'], function() {

  browserSync({
    ui: false,
    port: 1337,
    server:{
      baseDir: 'dist'
    }
  });

});

gulp.task('webserver:dev', ['validate', 'bower:dev'], function() {

  browserSync({
    port: 1337,
    server:{
      baseDir: ['src', '.local/bower']
    }
  });

});

// @end: webserver
//------------------------------------------------------------------------------
// @begin: watch

gulp.task('watch', ['webserver:dev'], function() { console.log('TODO: define'); });

// @end: watch
//------------------------------------------------------------------------------
// @begin: main

gulp.task('default', ['watch'], function() {
  projectInfoMsg();
});

gulp.task('release', ['build'], function() {
  projectInfoMsg();
});

gulp.task('preview', ['webserver:dist'], function() {
  projectInfoMsg();
});

// @end: main
//==============================================================================
// @end: gulp tasks ============================================================
//==============================================================================
<|endoftext|>


<commit_before>// 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.

couchTests.list_views = function(debug) {
  var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"});
  db.deleteDb();
  db.createDb();
  if (debug) debugger;

  var designDoc = {
    _id:"_design/lists",
    language: "javascript",
    views : {
      basicView : {
        map : stringFun(function(doc) {
          emit(doc.integer, doc.string);
        })
      },
      withReduce : {
        map : stringFun(function(doc) {
          emit(doc.integer, doc.string);
        }),
        reduce : stringFun(function(keys, values, rereduce) {
          if (rereduce) {
            return sum(values);
          } else {
            return values.length;
          }
        })
      }
    },
    lists: {
      basicBasic : stringFun(function(head, req) {
        send("head");
        var row;
        while(row = getRow()) {
          log("row: "+toJSON(row));
          send(row.key);
        };
        return "tail";
      }),
      basicJSON : stringFun(function(head, req) {
        start({"headers":{"Content-Type" : "application/json"}});
        send('{"head":'+toJSON(head)+', ');
        send('"req":'+toJSON(req)+', ');
        send('"rows":[');
        var row, sep = '';
        while (row = getRow()) {
          send(sep + toJSON(row));
          sep = ', ';
        }
        return "]}";
      }),
      simpleForm: stringFun(function(head, req) {
        log("simpleForm");
        send('
Total Rows: '
              // + head.total_rows
              // + ' Offset: ' + head.offset
              + '

');

        // rows
        var row, row_number = 0, prevKey, firstKey = null;
        while (row = getRow()) {
          row_number += 1;
          if (!firstKey) firstKey = row.key;
          prevKey = row.key;
          send('\n
Key: '+row.key
          +' Value: '+row.value
          +' LineNo: '+row_number+'
');
        }

        // tail
        return '

FirstKey: '+ firstKey + ' LastKey: '+ prevKey+'
';
      }),
      acceptSwitch: stringFun(function(head, req) {
        // respondWith takes care of setting the proper headers
        provides("html", function() {
          send("HTML
");

          var row, num = 0;
          while (row = getRow()) {
            num ++;
            send('\n
Key: '
              +row.key+' Value: '+row.value
              +' LineNo: '+num+'
');
          }

          // tail
          return '
';
        });

        provides("xml", function() {
          send('<feed xmlns="http://www.w3.org/2005/Atom">'
            +'<title>Test XML Feed</title>');

          while (row = getRow()) {
            var entry = new XML('<entry/>');
            entry.id = row.id;
            entry.title = row.key;
            entry.content = row.value;
            send(entry);
          }
          return "</feed>";
        });
      }),
      qsParams: stringFun(function(head, req) {
        return toJSON(req.query) + "\n";
      }),
      stopIter: stringFun(function(req) {
        send("head");
        var row, row_number = 0;
        while(row = getRow()) {
          if(row_number > 2) break;
          send(" " + row_number);
          row_number += 1;
        };
        return " tail";
      }),
      stopIter2: stringFun(function(head, req) {
        provides("html", function() {
          send("head");
          var row, row_number = 0;
          while(row = getRow()) {
            if(row_number > 2) break;
            send(" " + row_number);
            row_number += 1;
          };
          return " tail";
        });
      }),
      tooManyGetRows : stringFun(function() {
        send("head");
        var row;
        while(row = getRow()) {
          send(row.key);
        };
        getRow();
        getRow();
        getRow();
        row = getRow();
        return "after row: "+toJSON(row);
      }),
      emptyList: stringFun(function() {
        return " ";
      }),
      rowError : stringFun(function(head, req) {
        send("head");
        var row = getRow();
        send(fooBarBam); // intentional error
        return "tail";
      }),
      docReference : stringFun(function(head, req) {
        send("head");
        var row = getRow();
        send(row.doc.integer);
        return "tail";
      })
    }
  };

  T(db.save(designDoc).ok);

  var docs = makeDocs(0, 10);
  db.bulkSave(docs);

  var view = db.view('lists/basicView');
  T(view.total_rows == 10);

  // standard get
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/basicBasic/basicView");
  T(xhr.status == 200, "standard get should be 200");
  T(/head0123456789tail/.test(xhr.responseText));

  var xhr = CouchDB.request("GET", "/test_suite_db/_view/lists/basicView?list=basicBasic");
  T(xhr.status == 200, "standard get should be 200");
  T(/head0123456789tail/.test(xhr.responseText));

  // test that etags are available
  var etag = xhr.getResponseHeader("etag");
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/basicBasic/basicView", {
    headers: {"if-none-match": etag}
  });
  T(xhr.status == 304);

  var etag = xhr.getResponseHeader("etag");
  xhr = CouchDB.request("GET", "/test_suite_db/_view/lists/basicView?list=basicBasic", {
    headers: {"if-none-match": etag}
  });
  T(xhr.status == 304);

  // test the richness of the arguments
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/basicJSON/basicView");
  T(xhr.status == 200, "standard get should be 200");
  var resp = JSON.parse(xhr.responseText);
  TEquals(resp.head, {total_rows:10, offset:0});
  T(resp.rows.length == 10);
  TEquals(resp.rows[0], {"id": "0","key": 0,"value": "0"});

  TEquals(resp.req.info.db_name, "test_suite_db");
  TEquals(resp.req.verb, "GET");
  TEquals(resp.req.path, [
      "test_suite_db",
      "_design",
      "lists",
      "_list",
      "basicJSON",
      "basicView"
  ]);
  T(resp.req.headers.Accept);
  T(resp.req.headers.Host);
  T(resp.req.headers["User-Agent"]);
  T(resp.req.cookie);

  // get with query params
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/basicView?startkey=3");
  T(xhr.status == 200, "with query params");
  T(/Total Rows/.test(xhr.responseText));
  T(!(/Key: 1/.test(xhr.responseText)));
  T(/FirstKey: 3/.test(xhr.responseText));
  T(/LastKey: 9/.test(xhr.responseText));

  var xhr = CouchDB.request("GET", "/test_suite_db/_view/lists/basicView?list=simpleForm&startkey=3");
  T(xhr.status == 200, "with query params");
  T(/Total Rows/.test(xhr.responseText));
  T(!(/Key: 1/.test(xhr.responseText)));
  T(/FirstKey: 3/.test(xhr.responseText));
  T(/LastKey: 9/.test(xhr.responseText));

  // with 0 rows
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/basicView?startkey=30");
  T(xhr.status == 200, "0 rows");
  T(/Total Rows/.test(xhr.responseText));

   var xhr = CouchDB.request("GET", "/test_suite_db/_view/lists/basicView?list=simpleForm&startkey=30");
  T(xhr.status == 200, "0 rows");
  T(/Total Rows/.test(xhr.responseText));

  //too many Get Rows
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/tooManyGetRows/basicView");
  T(xhr.status == 200, "tooManyGetRows");
  T(/9after row: null/.test(xhr.responseText));

  // reduce with 0 rows
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?startkey=30");
  T(xhr.status == 200, "reduce 0 rows");
  T(/Total Rows/.test(xhr.responseText));
  T(/LastKey: undefined/.test(xhr.responseText));

  // reduce with 0 rows
   var xhr = CouchDB.request("GET", "/test_suite_db/_view/lists/withReduce?list=simpleForm&startkey=30");
   T(xhr.status == 200, "reduce 0 rows");
   T(/Total Rows/.test(xhr.responseText));
   T(/LastKey: undefined/.test(xhr.responseText));

  // when there is a reduce present, but not used
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?reduce=false");
  T(xhr.status == 200, "reduce false");
  T(/Total Rows/.test(xhr.responseText));
  T(/Key: 1/.test(xhr.responseText));

  // when there is a reduce present, and used
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=true");
  T(xhr.status == 200, "group reduce");
  T(/Key: 1/.test(xhr.responseText));

  // there should be etags on reduce as well
  var etag = xhr.getResponseHeader("etag");
  T(etag, "Etags should be served with reduce lists");
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=true", {
    headers: {"if-none-match": etag}
  });
  T(xhr.status == 304);

  // verify the etags expire correctly
  var docs = makeDocs(11, 12);
  db.bulkSave(docs);

  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=true", {
    headers: {"if-none-match": etag}
  });
  T(xhr.status == 200, "reduce etag");

  // empty list
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/emptyList/basicView");
  T(xhr.responseText.match(/^ $/));
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/emptyList/withReduce?group=true");
  T(xhr.responseText.match(/^ $/));

  // multi-key fetch
  var xhr = CouchDB.request("POST", "/test_suite_db/_design/lists/_list/simpleForm/basicView", {
    body: '{"keys":[2,4,5,7]}'
  });
  T(xhr.status == 200, "multi key");
  T(/Total Rows/.test(xhr.responseText));
  T(!(/Key: 1/.test(xhr.responseText)));
  T(/Key: 2/.test(xhr.responseText));
  T(/FirstKey: 2/.test(xhr.responseText));
  T(/LastKey: 7/.test(xhr.responseText));

  // no multi-key fetch allowed when group=false
  xhr = CouchDB.request("POST", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=false", {
    body: '{"keys":[2,4,5,7]}'
  });
  T(xhr.status == 400);
  T(/query_parse_error/.test(xhr.responseText));

  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/rowError/basicView");
  T(/ReferenceError/.test(xhr.responseText));

  // with include_docs and a reference to the doc.
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/docReference/basicView?include_docs=true");
  T(xhr.responseText.match(/head0tail/));

  // now with extra qs params
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/qsParams/basicView?foo=blam");
  T(xhr.responseText.match(/blam/));

  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter/basicView");
  // T(xhr.getResponseHeader("Content-Type") == "text/plain");
  T(xhr.responseText.match(/^head 0 1 2 tail$/) && "basic stop");

  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter2/basicView");
  T(xhr.responseText.match(/^head 0 1 2 tail$/) && "stop 2");

  // aborting iteration with reduce
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter/withReduce?group=true");
  T(xhr.responseText.match(/^head 0 1 2 tail$/) && "reduce stop");
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter2/withReduce?group=true");
  T(xhr.responseText.match(/^head 0 1 2 tail$/) && "reduce stop 2");

  // with accept headers for HTML
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/acceptSwitch/basicView", {
    headers: {
      "Accept": 'text/html'
    }
  });
  T(xhr.getResponseHeader("Content-Type") == "text/html; charset=utf-8");
  T(xhr.responseText.match(/HTML/));
  T(xhr.responseText.match(/Value/));

  // now with xml
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/acceptSwitch/basicView", {
    headers: {
      "Accept": 'application/xml'
    }
  });
  T(xhr.getResponseHeader("Content-Type") == "application/xml");
  T(xhr.responseText.match(/XML/));
  T(xhr.responseText.match(/entry/));
};
<commit_msg>fix whitespace<commit_after>// 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.

couchTests.list_views = function(debug) {
  var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"});
  db.deleteDb();
  db.createDb();
  if (debug) debugger;

  var designDoc = {
    _id:"_design/lists",
    language: "javascript",
    views : {
      basicView : {
        map : stringFun(function(doc) {
          emit(doc.integer, doc.string);
        })
      },
      withReduce : {
        map : stringFun(function(doc) {
          emit(doc.integer, doc.string);
        }),
        reduce : stringFun(function(keys, values, rereduce) {
          if (rereduce) {
            return sum(values);
          } else {
            return values.length;
          }
        })
      }
    },
    lists: {
      basicBasic : stringFun(function(head, req) {
        send("head");
        var row;
        while(row = getRow()) {
          log("row: "+toJSON(row));
          send(row.key);
        };
        return "tail";
      }),
      basicJSON : stringFun(function(head, req) {
        start({"headers":{"Content-Type" : "application/json"}});
        send('{"head":'+toJSON(head)+', ');
        send('"req":'+toJSON(req)+', ');
        send('"rows":[');
        var row, sep = '';
        while (row = getRow()) {
          send(sep + toJSON(row));
          sep = ', ';
        }
        return "]}";
      }),
      simpleForm: stringFun(function(head, req) {
        log("simpleForm");
        send('
Total Rows: '
              // + head.total_rows
              // + ' Offset: ' + head.offset
              + '

');

        // rows
        var row, row_number = 0, prevKey, firstKey = null;
        while (row = getRow()) {
          row_number += 1;
          if (!firstKey) firstKey = row.key;
          prevKey = row.key;
          send('\n
Key: '+row.key
          +' Value: '+row.value
          +' LineNo: '+row_number+'
');
        }

        // tail
        return '

FirstKey: '+ firstKey + ' LastKey: '+ prevKey+'
';
      }),
      acceptSwitch: stringFun(function(head, req) {
        // respondWith takes care of setting the proper headers
        provides("html", function() {
          send("HTML
");

          var row, num = 0;
          while (row = getRow()) {
            num ++;
            send('\n
Key: '
              +row.key+' Value: '+row.value
              +' LineNo: '+num+'
');
          }

          // tail
          return '
';
        });

        provides("xml", function() {
          send('<feed xmlns="http://www.w3.org/2005/Atom">'
            +'<title>Test XML Feed</title>');

          while (row = getRow()) {
            var entry = new XML('<entry/>');
            entry.id = row.id;
            entry.title = row.key;
            entry.content = row.value;
            send(entry);
          }
          return "</feed>";
        });
      }),
      qsParams: stringFun(function(head, req) {
        return toJSON(req.query) + "\n";
      }),
      stopIter: stringFun(function(req) {
        send("head");
        var row, row_number = 0;
        while(row = getRow()) {
          if(row_number > 2) break;
          send(" " + row_number);
          row_number += 1;
        };
        return " tail";
      }),
      stopIter2: stringFun(function(head, req) {
        provides("html", function() {
          send("head");
          var row, row_number = 0;
          while(row = getRow()) {
            if(row_number > 2) break;
            send(" " + row_number);
            row_number += 1;
          };
          return " tail";
        });
      }),
      tooManyGetRows : stringFun(function() {
        send("head");
        var row;
        while(row = getRow()) {
          send(row.key);
        };
        getRow();
        getRow();
        getRow();
        row = getRow();
        return "after row: "+toJSON(row);
      }),
      emptyList: stringFun(function() {
        return " ";
      }),
      rowError : stringFun(function(head, req) {
        send("head");
        var row = getRow();
        send(fooBarBam); // intentional error
        return "tail";
      }),
      docReference : stringFun(function(head, req) {
        send("head");
        var row = getRow();
        send(row.doc.integer);
        return "tail";
      })
    }
  };

  T(db.save(designDoc).ok);

  var docs = makeDocs(0, 10);
  db.bulkSave(docs);

  var view = db.view('lists/basicView');
  T(view.total_rows == 10);

  // standard get
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/basicBasic/basicView");
  T(xhr.status == 200, "standard get should be 200");
  T(/head0123456789tail/.test(xhr.responseText));

  var xhr = CouchDB.request("GET", "/test_suite_db/_view/lists/basicView?list=basicBasic");
  T(xhr.status == 200, "standard get should be 200");
  T(/head0123456789tail/.test(xhr.responseText));

  // test that etags are available
  var etag = xhr.getResponseHeader("etag");
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/basicBasic/basicView", {
    headers: {"if-none-match": etag}
  });
  T(xhr.status == 304);

  var etag = xhr.getResponseHeader("etag");
  xhr = CouchDB.request("GET", "/test_suite_db/_view/lists/basicView?list=basicBasic", {
    headers: {"if-none-match": etag}
  });
  T(xhr.status == 304);

  // test the richness of the arguments
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/basicJSON/basicView");
  T(xhr.status == 200, "standard get should be 200");
  var resp = JSON.parse(xhr.responseText);
  TEquals(resp.head, {total_rows:10, offset:0});
  T(resp.rows.length == 10);
  TEquals(resp.rows[0], {"id": "0","key": 0,"value": "0"});

  TEquals(resp.req.info.db_name, "test_suite_db");
  TEquals(resp.req.verb, "GET");
  TEquals(resp.req.path, [
      "test_suite_db",
      "_design",
      "lists",
      "_list",
      "basicJSON",
      "basicView"
  ]);
  T(resp.req.headers.Accept);
  T(resp.req.headers.Host);
  T(resp.req.headers["User-Agent"]);
  T(resp.req.cookie);

  // get with query params
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/basicView?startkey=3");
  T(xhr.status == 200, "with query params");
  T(/Total Rows/.test(xhr.responseText));
  T(!(/Key: 1/.test(xhr.responseText)));
  T(/FirstKey: 3/.test(xhr.responseText));
  T(/LastKey: 9/.test(xhr.responseText));

  var xhr = CouchDB.request("GET", "/test_suite_db/_view/lists/basicView?list=simpleForm&startkey=3");
  T(xhr.status == 200, "with query params");
  T(/Total Rows/.test(xhr.responseText));
  T(!(/Key: 1/.test(xhr.responseText)));
  T(/FirstKey: 3/.test(xhr.responseText));
  T(/LastKey: 9/.test(xhr.responseText));

  // with 0 rows
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/basicView?startkey=30");
  T(xhr.status == 200, "0 rows");
  T(/Total Rows/.test(xhr.responseText));

   var xhr = CouchDB.request("GET", "/test_suite_db/_view/lists/basicView?list=simpleForm&startkey=30");
  T(xhr.status == 200, "0 rows");
  T(/Total Rows/.test(xhr.responseText));

  //too many Get Rows
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/tooManyGetRows/basicView");
  T(xhr.status == 200, "tooManyGetRows");
  T(/9after row: null/.test(xhr.responseText));

  // reduce with 0 rows
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?startkey=30");
  T(xhr.status == 200, "reduce 0 rows");
  T(/Total Rows/.test(xhr.responseText));
  T(/LastKey: undefined/.test(xhr.responseText));

  // reduce with 0 rows
  var xhr = CouchDB.request("GET", "/test_suite_db/_view/lists/withReduce?list=simpleForm&startkey=30");
  T(xhr.status == 200, "reduce 0 rows");
  T(/Total Rows/.test(xhr.responseText));
  T(/LastKey: undefined/.test(xhr.responseText));

  // when there is a reduce present, but not used
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?reduce=false");
  T(xhr.status == 200, "reduce false");
  T(/Total Rows/.test(xhr.responseText));
  T(/Key: 1/.test(xhr.responseText));

  // when there is a reduce present, and used
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=true");
  T(xhr.status == 200, "group reduce");
  T(/Key: 1/.test(xhr.responseText));

  // there should be etags on reduce as well
  var etag = xhr.getResponseHeader("etag");
  T(etag, "Etags should be served with reduce lists");
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=true", {
    headers: {"if-none-match": etag}
  });
  T(xhr.status == 304);

  // verify the etags expire correctly
  var docs = makeDocs(11, 12);
  db.bulkSave(docs);

  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=true", {
    headers: {"if-none-match": etag}
  });
  T(xhr.status == 200, "reduce etag");

  // empty list
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/emptyList/basicView");
  T(xhr.responseText.match(/^ $/));
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/emptyList/withReduce?group=true");
  T(xhr.responseText.match(/^ $/));

  // multi-key fetch
  var xhr = CouchDB.request("POST", "/test_suite_db/_design/lists/_list/simpleForm/basicView", {
    body: '{"keys":[2,4,5,7]}'
  });
  T(xhr.status == 200, "multi key");
  T(/Total Rows/.test(xhr.responseText));
  T(!(/Key: 1/.test(xhr.responseText)));
  T(/Key: 2/.test(xhr.responseText));
  T(/FirstKey: 2/.test(xhr.responseText));
  T(/LastKey: 7/.test(xhr.responseText));

  // no multi-key fetch allowed when group=false
  xhr = CouchDB.request("POST", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=false", {
    body: '{"keys":[2,4,5,7]}'
  });
  T(xhr.status == 400);
  T(/query_parse_error/.test(xhr.responseText));

  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/rowError/basicView");
  T(/ReferenceError/.test(xhr.responseText));

  // with include_docs and a reference to the doc.
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/docReference/basicView?include_docs=true");
  T(xhr.responseText.match(/head0tail/));

  // now with extra qs params
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/qsParams/basicView?foo=blam");
  T(xhr.responseText.match(/blam/));

  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter/basicView");
  // T(xhr.getResponseHeader("Content-Type") == "text/plain");
  T(xhr.responseText.match(/^head 0 1 2 tail$/) && "basic stop");

  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter2/basicView");
  T(xhr.responseText.match(/^head 0 1 2 tail$/) && "stop 2");

  // aborting iteration with reduce
  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter/withReduce?group=true");
  T(xhr.responseText.match(/^head 0 1 2 tail$/) && "reduce stop");
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter2/withReduce?group=true");
  T(xhr.responseText.match(/^head 0 1 2 tail$/) && "reduce stop 2");

  // with accept headers for HTML
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/acceptSwitch/basicView", {
    headers: {
      "Accept": 'text/html'
    }
  });
  T(xhr.getResponseHeader("Content-Type") == "text/html; charset=utf-8");
  T(xhr.responseText.match(/HTML/));
  T(xhr.responseText.match(/Value/));

  // now with xml
  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/acceptSwitch/basicView", {
    headers: {
      "Accept": 'application/xml'
    }
  });
  T(xhr.getResponseHeader("Content-Type") == "application/xml");
  T(xhr.responseText.match(/XML/));
  T(xhr.responseText.match(/entry/));
};
<|endoftext|>


<commit_before>/**
 * @fileoverview Rule to flag use an lodash aliases
 *
 */

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

'use strict';

var LODASH_FN_ALIASES = {
  drop:      'rest',
  head:      'first',
  object:    'zipObject',
  tail:      'rest',
  take:      'first',
  unique:    'uniq',
  unzip:     'zip',
  all:       'every',
  any:       'some',
  collect:   'map',
  detect:    'find',
  each:      'forEach',
  eachRight: 'forEachRight',
  findWhere: 'find',
  foldl:     'reduce',
  foldr:     'reduceRight',
  include:   'contains',
  inject:    'reduce',
  select:    'filter',
  extend:    'assign',
  methods:   'functions'
};

var LODASH_NAMES = ['lodash', '_'];

module.exports = function(context) {

  return {
    'CallExpression': function(node) {

      var callee = node.callee;

      // Check patterns like `_.each(..)`,
      // that should be <Identifier.MemberExpression>
      if (callee.type === 'MemberExpression' &&
          callee.object.type === 'Identifier') {

        var objName = callee.object.name;

        if (LODASH_NAMES.indexOf(objName) !== -1 &&
            LODASH_FN_ALIASES[callee.property.name]) {
          var methodName = LODASH_FN_ALIASES[callee.property.name];
          var methodAlias = callee.property.name;
          context.report(
            node,
            '{{ldh}}.{{alias}}() is alias, use {{ldh}}.{{method}}() instead.',
            {
              ldh: objName,
              alias: methodAlias,
              method: methodName
            }
          );
        }
      }
    }
  };
};
<commit_msg>eslint plugin logic cleanup<commit_after>/**
 * @fileoverview Rule to flag use an lodash aliases
 *
 */

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

'use strict';

var LODASH_FN_ALIASES = {
  drop:      'rest',
  head:      'first',
  object:    'zipObject',
  tail:      'rest',
  take:      'first',
  unique:    'uniq',
  unzip:     'zip',
  all:       'every',
  any:       'some',
  collect:   'map',
  detect:    'find',
  each:      'forEach',
  eachRight: 'forEachRight',
  findWhere: 'find',
  foldl:     'reduce',
  foldr:     'reduceRight',
  include:   'contains',
  inject:    'reduce',
  select:    'filter',
  extend:    'assign',
  methods:   'functions'
};

var LODASH_NAMES = ['lodash', '_'];

module.exports = function(context) {

  return {
    'CallExpression': function detectLodashAlias(node) {

      var callee = node.callee;

      // Check patterns like `_.each(..)`,
      // that should be <Identifier.MemberExpression>

      if (callee.type === 'MemberExpression' &&
          LODASH_FN_ALIASES.hasOwnProperty(callee.property.name)) {

        var parentName = callee.object.name;

        if (callee.object.type === 'Identifier' &&
            LODASH_NAMES.indexOf(parentName) !== -1) {

          context.report(
            node,
            '{{ldh}}.{{alias}}() is alias, use {{ldh}}.{{method}}() instead.',
            {
              ldh:    parentName,
              alias:  callee.property.name,
              method: LODASH_FN_ALIASES[callee.property.name]
            }
          );
        }
      }
    }
  };
};
<|endoftext|>


<commit_before>import htmlparser from 'htmlparser2';
import sourcemap from 'source-map';
import svelte from 'svelte';

SvelteCompiler = class SvelteCompiler extends CachingCompiler {
  constructor(options = {}) {
    super({
      compilerName: 'svelte',
      defaultCacheSize: 1024 * 1024 * 10
    });

    this.options = options;
  }

  getCacheKey(file) {
    return [
      this.options,
      file.getPathInPackage(),
      file.getSourceHash(),
      file.getArch()
    ];
  }

  setDiskCacheDirectory(cacheDirectory) {
    this.cacheDirectory = cacheDirectory;
  }

  // The compile result returned from `compileOneFile` can be an array or an
  // object. If the processed HTML file is not a Svelte component, the result is
  // an array of HTML sections (head and/or body). Otherwise, it's an object
  // with JavaScript from a compiled Svelte component.
  compileResultSize(result) {
    let size = 0;

    if (Array.isArray(result)) {
      result.forEach(section => size += section.data.length);
    } else {
      size = result.data.length + result.sourceMap.toString().length;
    }

    return size;
  }

  addCompileResult(file, result) {
    if (Array.isArray(result)) {
      result.forEach(section => file.addHtml(section));
    } else {
      file.addJavaScript(result);
    }
  }

  compileOneFile(file) {
    const raw = file.getContentsAsString();
    const basename = file.getBasename();
    const path = file.getPathInPackage();

    const extension = path.substring(path.lastIndexOf('.') + 1);

    if (extension === 'html') {
      let isSvelteComponent = true;
      const sections = [];

      // Search for top level head and body tags. If at least one of these tags
      // exists, the file is not processed with the Svelte compiler. Instead,
      // the inner HTML of the tags is added to the respective section in the
      // HTML output generated by Meteor.
      htmlparser.parseDOM(raw).forEach(el => {
        if (el.name === 'head' || el.name === 'body') {
          isSvelteComponent = false;

          sections.push({
            section: el.name,
            data: htmlparser.DomUtils.getInnerHTML(el).trim()
          });
        }
      });

      if (!isSvelteComponent) {
        return sections;
      }
    }

    const svelteOptions = {
      dev: process.env.NODE_ENV !== 'production',
      filename: path,
      name: basename
        .slice(0, basename.indexOf('.')) // Remove extension
        .replace(/[^a-z0-9_$]/ig, '_') // Ensure valid identifier
    };

    if (file.getArch().startsWith('os.')) {
      svelteOptions.generate = 'ssr';
    } else {
      const { hydratable, css } = this.options;

      if (hydratable === true) {
        svelteOptions.hydratable = true;
      }

      if (css === false) {
        svelteOptions.css = false;
      }
    }

    try {
      return this.transpileWithBabel(
        svelte.compile(raw, svelteOptions).js,
        path
      );
    } catch (e) {
      // Throw unknown errors.
      if (!e.start) {
        throw e;
      }

      let message;

      if (e.frame) {
        // Prepend a vertical bar to each line to prevent Meteor from trimming
        // whitespace and moving the code frame indicator to the wrong position.
        const frame = e.frame.split('\n').map(line => {
          return `| ${line}`;
        }).join('\n');

        message = `${e.message}\n\n${frame}`;
      } else {
        message = e.message;
      }

      file.error({
        message,
        line: e.start.line,
        column: e.start.column
      });
    }
  }

  transpileWithBabel(source, path) {
    const options = Babel.getDefaultOptions();
    options.filename = path;

    const transpiled = Babel.compile(source.code, options, {
      cacheDirectory: this.cacheDirectory
    });

    return {
      sourcePath: path,
      path,
      data: transpiled.code,
      sourceMap: this.combineSourceMaps(transpiled.map, source.map)
    };
  }

  // Generates a new source map that maps a file transpiled by Babel back to the
  // original HTML via a source map generated by the Svelte compiler.
  combineSourceMaps(babelMap, svelteMap) {
    const result = new sourcemap.SourceMapGenerator;

    const babelConsumer = new sourcemap.SourceMapConsumer(babelMap);
    const svelteConsumer = new sourcemap.SourceMapConsumer(svelteMap);

    babelConsumer.eachMapping(mapping => {
      // Ignore mappings that don't have a source.
      if (!mapping.source) {
        return;
      }

      const position = svelteConsumer.originalPositionFor({
        line: mapping.originalLine,
        column: mapping.originalColumn
      });

      // Ignore mappings that don't map to the original HTML.
      if (!position.source) {
        return;
      }

      result.addMapping({
        source: position.source,
        original: {
          line: position.line,
          column: position.column
        },
        generated: {
          line: mapping.generatedLine,
          column: mapping.generatedColumn
        }
      });
    });

    // Copy source content from the source map generated by the Svelte compiler.
    // We can just take the first entry because only one file is involved in the
    // Svelte compilation and Babel transpilation.
    result.setSourceContent(
      svelteMap.sources[0],
      svelteMap.sourcesContent[0]
    );

    return result.toJSON();
  }
};
<commit_msg>Clarify architecture detection for server-side rendering<commit_after>import htmlparser from 'htmlparser2';
import sourcemap from 'source-map';
import svelte from 'svelte';

SvelteCompiler = class SvelteCompiler extends CachingCompiler {
  constructor(options = {}) {
    super({
      compilerName: 'svelte',
      defaultCacheSize: 1024 * 1024 * 10
    });

    this.options = options;
  }

  getCacheKey(file) {
    return [
      this.options,
      file.getPathInPackage(),
      file.getSourceHash(),
      file.getArch()
    ];
  }

  setDiskCacheDirectory(cacheDirectory) {
    this.cacheDirectory = cacheDirectory;
  }

  // The compile result returned from `compileOneFile` can be an array or an
  // object. If the processed HTML file is not a Svelte component, the result is
  // an array of HTML sections (head and/or body). Otherwise, it's an object
  // with JavaScript from a compiled Svelte component.
  compileResultSize(result) {
    let size = 0;

    if (Array.isArray(result)) {
      result.forEach(section => size += section.data.length);
    } else {
      size = result.data.length + result.sourceMap.toString().length;
    }

    return size;
  }

  addCompileResult(file, result) {
    if (Array.isArray(result)) {
      result.forEach(section => file.addHtml(section));
    } else {
      file.addJavaScript(result);
    }
  }

  compileOneFile(file) {
    const raw = file.getContentsAsString();
    const basename = file.getBasename();
    const path = file.getPathInPackage();

    const extension = path.substring(path.lastIndexOf('.') + 1);

    if (extension === 'html') {
      let isSvelteComponent = true;
      const sections = [];

      // Search for top level head and body tags. If at least one of these tags
      // exists, the file is not processed with the Svelte compiler. Instead,
      // the inner HTML of the tags is added to the respective section in the
      // HTML output generated by Meteor.
      htmlparser.parseDOM(raw).forEach(el => {
        if (el.name === 'head' || el.name === 'body') {
          isSvelteComponent = false;

          sections.push({
            section: el.name,
            data: htmlparser.DomUtils.getInnerHTML(el).trim()
          });
        }
      });

      if (!isSvelteComponent) {
        return sections;
      }
    }

    const svelteOptions = {
      dev: process.env.NODE_ENV !== 'production',
      filename: path,
      name: basename
        .slice(0, basename.indexOf('.')) // Remove extension
        .replace(/[^a-z0-9_$]/ig, '_') // Ensure valid identifier
    };

    // If the component was imported by server code, compile it for SSR.
    if (file.getArch().startsWith('os.')) {
      svelteOptions.generate = 'ssr';
    } else {
      const { hydratable, css } = this.options;

      if (hydratable === true) {
        svelteOptions.hydratable = true;
      }

      if (css === false) {
        svelteOptions.css = false;
      }
    }

    try {
      return this.transpileWithBabel(
        svelte.compile(raw, svelteOptions).js,
        path
      );
    } catch (e) {
      // Throw unknown errors.
      if (!e.start) {
        throw e;
      }

      let message;

      if (e.frame) {
        // Prepend a vertical bar to each line to prevent Meteor from trimming
        // whitespace and moving the code frame indicator to the wrong position.
        const frame = e.frame.split('\n').map(line => {
          return `| ${line}`;
        }).join('\n');

        message = `${e.message}\n\n${frame}`;
      } else {
        message = e.message;
      }

      file.error({
        message,
        line: e.start.line,
        column: e.start.column
      });
    }
  }

  transpileWithBabel(source, path) {
    const options = Babel.getDefaultOptions();
    options.filename = path;

    const transpiled = Babel.compile(source.code, options, {
      cacheDirectory: this.cacheDirectory
    });

    return {
      sourcePath: path,
      path,
      data: transpiled.code,
      sourceMap: this.combineSourceMaps(transpiled.map, source.map)
    };
  }

  // Generates a new source map that maps a file transpiled by Babel back to the
  // original HTML via a source map generated by the Svelte compiler.
  combineSourceMaps(babelMap, svelteMap) {
    const result = new sourcemap.SourceMapGenerator;

    const babelConsumer = new sourcemap.SourceMapConsumer(babelMap);
    const svelteConsumer = new sourcemap.SourceMapConsumer(svelteMap);

    babelConsumer.eachMapping(mapping => {
      // Ignore mappings that don't have a source.
      if (!mapping.source) {
        return;
      }

      const position = svelteConsumer.originalPositionFor({
        line: mapping.originalLine,
        column: mapping.originalColumn
      });

      // Ignore mappings that don't map to the original HTML.
      if (!position.source) {
        return;
      }

      result.addMapping({
        source: position.source,
        original: {
          line: position.line,
          column: position.column
        },
        generated: {
          line: mapping.generatedLine,
          column: mapping.generatedColumn
        }
      });
    });

    // Copy source content from the source map generated by the Svelte compiler.
    // We can just take the first entry because only one file is involved in the
    // Svelte compilation and Babel transpilation.
    result.setSourceContent(
      svelteMap.sources[0],
      svelteMap.sourcesContent[0]
    );

    return result.toJSON();
  }
};
<|endoftext|>


<commit_before>'use strict';

const enabled = process.env.BLINK_LOGGER_TRANSFORMER_LEANIFY === 'true';

// Keys that bloat the log without adding significant value
const bloatKeys = [
  'AccountSid',
  'ApiVersion',
  'deliveredAt',
  'failedAt',
  'MessagingServiceSid',
  'SmsMessageSid',
  'SmsSid',
];

module.exports = {
  enabled,
  bloatKeys,
};
<commit_msg>Adds params from PasswordResetMessage<commit_after>'use strict';

const enabled = process.env.BLINK_LOGGER_TRANSFORMER_LEANIFY === 'true';

// Keys that bloat the log without adding significant value
const bloatKeys = [
  'AccountSid',
  'ApiVersion',
  'body',
  'deliveredAt',
  'failedAt',
  'MessagingServiceSid',
  'SmsMessageSid',
  'SmsSid',
  'subject',
  'url',
];

module.exports = {
  enabled,
  bloatKeys,
};
<|endoftext|>


<commit_before>var async = require('async');
var AWS = require('aws-sdk');
require('dotenv').config();

AWS.config.update({
  region: process.env.AWS_REGION
});

var docClient = new AWS.DynamoDB.DocumentClient();

module.exports = {
  // Log of taxis locations
  // Trigger this every 30 seconds
  logTaxis: function (event, context) {
    require('./taxis').fetch(function (err, results, headers) {
      if (err) {
        return context.fail(err);
      }
      var timestamp = Math.floor(new Date(headers.lastmod).getTime() / 1000);

      async.series({
        validate: function (callback) {
          var params = {
            TableName: process.env.AWS_DYNAMODB_TABLE,
            Select: 'COUNT',
            KeyConditionExpression: "#ts = :tttt",
            ExpressionAttributeNames: {
              '#ts': 'timestamp'
            },
            ExpressionAttributeValues: {
              ":tttt": timestamp
            }
          };

          docClient.query(params, function (err, data) {
            if (!err) {
              if (data.Count === 0) {
                return callback(null);
              } else {
                return callback(data);
              }
            }
            return callback(err);
          });

        },

        put: function (callback) {
          var params = {
            TableName: process.env.AWS_DYNAMODB_TABLE,
            Item: {
              timestamp: timestamp,
              locations: results
            }
          };

          var saved = false;
          async.whilst( function() {
              return !saved;
            }, function (callback) {
            docClient.put(params, function (err, data) {
              saved = true;
              if (err && err.retryable === true) {
                saved = false;
              }
              callback(err, data);
            });
          }, function (err, data) {
            return callback(err);
          });
        }
      }, function (err) {
        if (err) {
          return context.fail(err);
        } else {
          return context.done(err, results.length + ' locations saved successfully with timestamp ' + headers.lastmod);
        }
      });

    });
  }
};
<commit_msg>Bug fix for err<commit_after>var async = require('async');
var AWS = require('aws-sdk');
require('dotenv').config();

AWS.config.update({
  region: process.env.AWS_REGION
});

var docClient = new AWS.DynamoDB.DocumentClient();

module.exports = {
  // Log of taxis locations
  // Trigger this every 30 seconds
  logTaxis: function (event, context) {
    require('./taxis').fetch(function (err, results, headers) {
      if (err) {
        return context.fail(err);
      }
      var timestamp = Math.floor(new Date(headers.lastmod).getTime() / 1000);

      async.series({
        validate: function (callback) {
          var params = {
            TableName: process.env.AWS_DYNAMODB_TABLE,
            Select: 'COUNT',
            KeyConditionExpression: "#ts = :tttt",
            ExpressionAttributeNames: {
              '#ts': 'timestamp'
            },
            ExpressionAttributeValues: {
              ":tttt": timestamp
            }
          };

          docClient.query(params, function (err, data) {
            if (!err) {
              if (data.Count === 0) {
                return callback(null);
              } else {
                return callback('Data for timestamp ' + timestamp + ' is already logged.');
              }
            }
            return callback(err);
          });

        },

        put: function (callback) {
          var params = {
            TableName: process.env.AWS_DYNAMODB_TABLE,
            Item: {
              timestamp: timestamp,
              locations: results
            }
          };

          var saved = false;
          async.whilst( function() {
              return !saved;
            }, function (callback) {
            docClient.put(params, function (err, data) {
              saved = true;
              if (err && err.retryable === true) {
                saved = false;
              }
              callback(err, data);
            });
          }, function (err, data) {
            return callback(err);
          });
        }
      }, function (err) {
        if (err) {
          return context.fail(err);
        } else {
          return context.done(err, results.length + ' locations saved successfully with timestamp ' + headers.lastmod);
        }
      });

    });
  }
};
<|endoftext|>


<commit_before>var container = null;
var genderSelect = null;
var weightInput = null;
var goalSelect = null;

class StatsService {

    constructor() {
    }

	render(appContainer) {
        let row = document.createElement('div');
        row.className = 'row';

        container = row;

        let column = document.createElement('div');
        column.className = 'col-xs-12';

        renderGenderSelect(column);
        renderWeightInput(column);
        renderGoalSelect(column);

        row.appendChild(column);
        appContainer.appendChild(row);
	}

	getValues() {
        let genderValue = genderSelect.value;
        let weightValue = weightInput.value;
        let goalValue = goalSelect.value;

        let errors = [];

        if(genderValue.length === 0) {
            errors.push('Please select your gender');
        }

        let weight = parseInt(weightValue, 10);
        if(weight !== weight) {
            errors.push('Please enter a weight 1 through 999');
        }

        if(goalValue.length === 0) {
            errors.push('Please select your goal');
        }

        return {
            stats: {
                gender: genderValue,
                weight: weight,
                goal: goalValue
            },
            errors: errors.length == 0 ? null : errors
        };
    }

	hide() {
        container.style.display = 'none';
    }

    show() {

    }
}

function renderGenderSelect(column) {
    let genderGroup = document.createElement('div');
    genderGroup.className = 'form-group';

    let genderSelect = document.createElement('select');
    genderSelect.id = 'gender-select';
    genderSelect.className = 'form-control';

    genderSelect = genderSelect;

    let options = [
        { text: 'Select one...', value: '' },
        { text: 'Male', value: 'male' },
        { text: 'Female', value: 'female' },
    ];

    options.forEach((currentOption) => {
        let option = document.createElement('option');
        option.text = currentOption.text;
        option.value = currentOption.value;

        genderSelect.appendChild(option);
    });

    genderSelect.selectedIndex = 0;

    genderGroup.appendChild(genderSelect);
    column.appendChild(genderGroup);
}

function renderWeightInput(column) {
    let weightGroup = document.createElement('div');
    weightGroup.className = 'form-group';

    let weightInput = document.createElement('input');
    weightInput.id = 'weight-input';
    weightInput.type = 'number';
    weightInput.className = 'form-control';
    weightInput.min = 1;
    weightInput.max = 999;
    weightInput.maxLength = 3;
    weightInput.setAttribute('placeholder', 'Enter weight');

    weightInput = weightInput;

    weightGroup.appendChild(weightInput);
    column.appendChild(weightGroup);
}

function renderGoalSelect(column) {
    let goalGroup = document.createElement('div');
    goalGroup.className = 'form-group';

    let goalSelect = document.createElement('select');
    goalSelect.id = 'goal-select';
    goalSelect.className = 'form-control';

    goalSelect = goalSelect;

    let options = [
        { text: 'Select one...', value: '' },
        { text: 'Lose Weight', value: 'lose' },
        { text: 'Gain Weight', value: 'gain' },
    ];

    options.forEach((currentOption) => {
        let option = document.createElement('option');
        option.text = currentOption.text;
        option.value = currentOption.value;

        goalSelect.appendChild(option);
    });

    goalSelect.selectedIndex = 0;

    goalGroup.appendChild(goalSelect);
    column.appendChild(goalGroup);
}

let statsService = new StatsService();

export default statsService;<commit_msg>removed usages of var<commit_after>let container = null;
let genderSelect = null;
let weightInput = null;
let goalSelect = null;

class StatsService {

    constructor() {
    }

	render(appContainer) {
        let row = document.createElement('div');
        row.className = 'row';

        container = row;

        let column = document.createElement('div');
        column.className = 'col-xs-12';

        renderGenderSelect(column);
        renderWeightInput(column);
        renderGoalSelect(column);

        row.appendChild(column);
        appContainer.appendChild(row);
	}

	getValues() {
        let genderValue = genderSelect.value;
        let weightValue = weightInput.value;
        let goalValue = goalSelect.value;

        let errors = [];

        if(genderValue.length === 0) {
            errors.push('Please select your gender');
        }

        let weight = parseInt(weightValue, 10);
        if(weight !== weight) {
            errors.push('Please enter a weight 1 through 999');
        }

        if(goalValue.length === 0) {
            errors.push('Please select your goal');
        }

        return {
            stats: {
                gender: genderValue,
                weight: weight,
                goal: goalValue
            },
            errors: errors.length == 0 ? null : errors
        };
    }

	hide() {
        container.style.display = 'none';
    }

    show() {

    }
}

function renderGenderSelect(column) {
    let genderGroup = document.createElement('div');
    genderGroup.className = 'form-group';

    let genderSelect = document.createElement('select');
    genderSelect.id = 'gender-select';
    genderSelect.className = 'form-control';

    genderSelect = genderSelect;

    let options = [
        { text: 'Select one...', value: '' },
        { text: 'Male', value: 'male' },
        { text: 'Female', value: 'female' },
    ];

    options.forEach((currentOption) => {
        let option = document.createElement('option');
        option.text = currentOption.text;
        option.value = currentOption.value;

        genderSelect.appendChild(option);
    });

    genderSelect.selectedIndex = 0;

    genderGroup.appendChild(genderSelect);
    column.appendChild(genderGroup);
}

function renderWeightInput(column) {
    let weightGroup = document.createElement('div');
    weightGroup.className = 'form-group';

    let weightInput = document.createElement('input');
    weightInput.id = 'weight-input';
    weightInput.type = 'number';
    weightInput.className = 'form-control';
    weightInput.min = 1;
    weightInput.max = 999;
    weightInput.maxLength = 3;
    weightInput.setAttribute('placeholder', 'Enter weight');

    weightInput = weightInput;

    weightGroup.appendChild(weightInput);
    column.appendChild(weightGroup);
}

function renderGoalSelect(column) {
    let goalGroup = document.createElement('div');
    goalGroup.className = 'form-group';

    let goalSelect = document.createElement('select');
    goalSelect.id = 'goal-select';
    goalSelect.className = 'form-control';

    goalSelect = goalSelect;

    let options = [
        { text: 'Select one...', value: '' },
        { text: 'Lose Weight', value: 'lose' },
        { text: 'Gain Weight', value: 'gain' },
    ];

    options.forEach((currentOption) => {
        let option = document.createElement('option');
        option.text = currentOption.text;
        option.value = currentOption.value;

        goalSelect.appendChild(option);
    });

    goalSelect.selectedIndex = 0;

    goalGroup.appendChild(goalSelect);
    column.appendChild(goalGroup);
}

let statsService = new StatsService();

export default statsService;<|endoftext|>


<commit_before>// big thank you to share-codemirror
// this is as much as possible copied from there

(function () {
  'use strict';

  /**
   * @param cm - CodeMirror instance
   * @param ctx - Share context
   * @param timestamps.client - unique identifier for timestamps.client
   */
  function shareCodeMirror(cm, ctx, timestamps) {
    if (!ctx.provides.json) throw new Error('Cannot attach to non-json document');

    var suppress = false;

    // fetch initial document from sharejs
    var doc = ctx.get();

    cm.setValue(doc.text);

    check();

    var textListenerPath = ['text'];
    var textInsertHandler = function(startPos, insertedText) {
      //console.log('text listener insert', startPos, insertedText);

      // suppress changes until this op has been incorporated
      suppress = true;

      // add in the inserted text we received from the sharejs context
      cm.replaceRange(insertedText, cm.posFromIndex(startPos));
      suppress = false;

      // now, make sure we are in sync with remote document
      check();
    };

    // on remote inserts to the 'text' attribute of our document,
    // run the textInsertHandler function
    var textInsertListener = ctx.addListener(
      textListenerPath,
      'insert',
      textInsertHandler
    );

    var textDeleteHandler = function(startPos, deletedText) {
      //console.log('text listener delete', startPos, deletedText);
      suppress = true;
      var from = cm.posFromIndex(startPos);
      var to = cm.posFromIndex(startPos + deletedText.length);
      cm.replaceRange('', from, to);
      suppress = false;

      // check to make sure document is in sync, draw updated timestamps
      check();
    };

    var textDeleteListener = ctx.addListener(
      textListenerPath,
      'delete',
      textDeleteHandler
    );

    cm.on('change', onLocalChange);

    function onLocalChange(cm, change) {
      if (suppress) return;
      applyToShareJS(cm, change);

      // check to make sure document in sync, update timestampss
      check();
    }

    cm.detachShareJsDoc = function () {
      ctx.removeListener(textInsertListener);
      ctx.removeListener(textDeleteListener);
      cm.off('change', onLocalChange);
    };

    // Convert a CodeMirror change into an op understood by share.js
    function applyToShareJS(cm, change) {

      // CodeMirror changes give a text replacement.

      var startPos = 0;  // Get character position from # of chars in each line.
      var i = 0;         // i goes through all lines.

      while (i < change.from.line) {
        startPos += cm.lineInfo(i).text.length + 1;   // Add 1 for '\n'
        i++;
      }

      startPos += change.from.ch;

      // sharejs json path to the location of the change
      var textPath = ['text', startPos];

      // array of operations that will be submitted
      var ops = [];

      // get an updated document
      var doc = ctx.get();

      if (change.to.line == change.from.line && change.to.ch == change.from.ch) {
        // nothing was removed.
      } else {

        // delete.removed contains an array of removed lines as strings, so this adds
        // all the lengths. Later change.removed.length - 1 is added for the \n-chars
        // (-1 because the linebreak on the last line won't get deleted)
        var delLen = 0;
        for (var rm = 0; rm < change.removed.length; rm++) {
          delLen += change.removed[rm].length;
        }
        delLen += change.removed.length - 1;

        // this is the changed text
        //change.removed.join('\n')

        for (i = change.to.line; i > change.from.line; i--) {
          ops.push({p:['lines', i], ld: doc.lines[i]});
        }

        ops.push({p:textPath, sd: change.removed.join('\n')});

        // submit all of these with the insertions later
        //ctx.remove(textPath, delLen, function(error, appliedOp) {
          //console.info('delete callback', error, appliedOp);
        //});
      }

      if (change.text) {

        // insert op
        ops.push({p:textPath, si: change.text.join('\n')});

        // update timestamps
        for (i = change.from.line; i <= change.to.line; i++) {
          if (doc.lines[i]) {

            var newTimestamp = timestamps.newDate();

            if (newTimestamp !== doc.lines[i].timestamp ||
                timestamps.client !== doc.lines[i].client) {

                // replace (delete and insert) the line with updated values
                ops.push({p:['lines', i], ld: doc.lines[i], li: {
                  client: timestamps.client,
                  timestamp: timestamps.newDate()
                }});
            }

            // figure out if there should also be an included line insertion
            // // if the change was just to add a new line character, do a replace
            // // on that line and then do an insert for the next
            if (change.text.join('\n') === '\n') {
              ops.push({p:['lines', i+1], li: {
                client: timestamps.client,
                timestamp: timestamps.newDate()
              }});
            }

          } else {
            // insert a new line
            ops.push({p:['lines', i], li: {
              client: timestamps.client,
              timestamp: timestamps.newDate()
            }});
          }
        }

        // use this os that we can submit an array of ops that includes
        // both the changes to the text and to the line information
        //ctx.submitOp(ops);

        //ctx.insert(textPath, change.text.join('\n'));
      }

      ctx.submitOp(ops);

      // call the function again on the next change, if there is one
      if (change.next) {
        applyToShareJS(cm, change.next);
      }
    }

    function check() {
      // magic, no touchy
      setTimeout(function () {
        var cmText = cm.getValue();
        var otDoc = ctx.get();

        if (cmText !== otDoc.text) {
          console.error("Text does not match!");
          console.error("cm: " + cmText);
          console.error("ot: " + otDoc.text);
          // Replace the editor text with the ctx snapshot.
          cm.setValue(ctx.get().text);
        }

        // just draw whatever the server tells us to
        timestamps.draw(otDoc.lines);
      }, 0);
    }

    return ctx;
  }

  if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
    // Node.js
    module.exports = shareCodeMirror;
    module.exports.scriptsDir = __dirname;
  } else {
    if (typeof define === 'function' && define.amd) {
      // AMD
      define([], function () {
        return shareCodeMirror;
      });
    } else {
      // Browser, no AMD
      window.sharejs.Doc.prototype.attachCodeMirror = function (cm, ctx, timestamps) {
        if (!ctx) ctx = this.createContext();
        shareCodeMirror(cm, ctx, timestamps);
      };
    }
  }
})();
<commit_msg>JSON Sync working with paste and multi-line delete.<commit_after>
//
//  share-codemirror-json.js
//
//  - Synchronizes JSON documents between ShareJS and CodeMirror
//
//  Credit to share-codemirror, this is taken as much as possible from that.
//  - https://github.com/share/share-codemirror
//
//  Copyright (c) 2015 Visionist, 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.
//

(function () {
  'use strict';

  /**
   * @param cm - CodeMirror instance
   * @param ctx - Share context
   * @param timestamps.client - unique identifier for timestamps.client
   */
  function shareCodeMirror(cm, ctx, timestamps) {
    if (!ctx.provides.json) throw new Error('Cannot attach to non-json document');

    var suppress = false;

    // fetch initial document from sharejs
    var doc = ctx.get();

    cm.setValue(doc.text);

    check();

    var textListenerPath = ['text'];
    var textInsertHandler = function(startPos, insertedText) {
      //console.log('text listener insert', startPos, insertedText);

      // suppress changes until this op has been incorporated
      suppress = true;

      // add in the inserted text we received from the sharejs context
      cm.replaceRange(insertedText, cm.posFromIndex(startPos));
      suppress = false;

      // now, make sure we are in sync with remote document
      check();
    };

    // on remote inserts to the 'text' attribute of our document,
    // run the textInsertHandler function
    var textInsertListener = ctx.addListener(
      textListenerPath,
      'insert',
      textInsertHandler
    );

    var textDeleteHandler = function(startPos, deletedText) {
      //console.log('text listener delete', startPos, deletedText);
      suppress = true;
      var from = cm.posFromIndex(startPos);
      var to = cm.posFromIndex(startPos + deletedText.length);
      cm.replaceRange('', from, to);
      suppress = false;

      // check to make sure document is in sync, draw updated timestamps
      check();
    };

    var textDeleteListener = ctx.addListener(
      textListenerPath,
      'delete',
      textDeleteHandler
    );

    cm.on('change', onLocalChange);

    function onLocalChange(cm, change) {
      if (suppress) return;
      applyToShareJS(cm, change);

      // check to make sure document in sync, update timestampss
      check();
    }

    cm.detachShareJsDoc = function () {
      ctx.removeListener(textInsertListener);
      ctx.removeListener(textDeleteListener);
      cm.off('change', onLocalChange);
    };

    // Convert a CodeMirror change into an op understood by share.js
    function applyToShareJS(cm, change) {

      // CodeMirror changes give a text replacement.

      var startPos = 0;  // Get character position from # of chars in each line.
      var i = 0;         // i goes through all lines.

      while (i < change.from.line) {
        startPos += cm.lineInfo(i).text.length + 1;   // Add 1 for '\n'
        i++;
      }

      startPos += change.from.ch;

      // sharejs json path to the location of the change
      var textPath = ['text', startPos];

      // array of operations that will be submitted
      var ops = [];

      // object to keep track of lines that were deleted
      var deletedLines = {};

      // get an updated document
      var doc = ctx.get();

      if (change.to.line == change.from.line && change.to.ch == change.from.ch) {
        // nothing was removed.
      } else {

        // change in text (deletion)
        ops.push({p:textPath, sd: change.removed.join('\n')});

        // change in lines (deleted lines)
        for (i = change.to.line; i > change.from.line; i--) {
          ops.push({p:['lines', i], ld: doc.lines[i]});
          deletedLines[i] = true;
        }
      }

      if (change.text) {

        // change in text (insertion)
        ops.push({p:textPath, si: change.text.join('\n')});

        // new lines and pasting
        if ((change.from.line === change.to.line && change.text.length > 1) || change.origin === 'paste') {

          // figure out if there should also be an included line insertion
          // // if the change was just to add a new line character, do a replace
          // // on that line and then do an insert for the next
          if (change.text.join('\n') === '\n') {
            ops.push({p:['lines', change.from.line+1], li: {
              client: timestamps.client,
              timestamp: timestamps.newDate()
            }});
          } else {
            if (change.origin !== 'paste') {
              console.warn('not sure what to do in this case', change);
            } else {

              if (newTimestamp !== doc.lines[change.from.line].timestamp ||
                  timestamps.client !== doc.lines[change.from.line].client) {

                // replace (delete and insert) the line with updated values
                ops.push({p:['lines', change.from.line], ld: doc.lines[change.from.line], li: {
                  client: timestamps.client,
                  timestamp: timestamps.newDate()
                }});
              }

              for (i = 1; i < change.text.length; i++) {
                ops.push({p:['lines', change.from.line+1], li: {
                  client: timestamps.client,
                  timestamp: timestamps.newDate()
                }});
              }
            }
          }
        } else {
          // change in lines (replace + insertion)
          for (var changeTextIndex = 0; changeTextIndex < change.text.length; changeTextIndex++) {
            var lineChange = change.text[changeTextIndex];
            var lineIndex = change.from.line + changeTextIndex;

            if (doc.lines[lineIndex]) {

              // if this line was just deleted, we don't want to submit any
              // updates for it ... we have already updated the text appropriately,
              // updating this now will update the wrong line.
              if (deletedLines[lineIndex]) {
                continue;
              }

              var newTimestamp = timestamps.newDate();

              // the line metadata has changed (new author or new date)
              if (newTimestamp !== doc.lines[lineIndex].timestamp ||
                  timestamps.client !== doc.lines[lineIndex].client) {

                // replace (delete and insert) the line with updated values
                ops.push({p:['lines', lineIndex], ld: doc.lines[lineIndex], li: {
                  client: timestamps.client,
                  timestamp: newTimestamp
                }});
              }

            } else {
              // the line doesn't currently exist, so insert a new line
              ops.push({p:['lines', lineIndex], li: {
                client: timestamps.client,
                timestamp: timestamps.newDate()
              }});
            }
          }
        }
      }

      // submit the complete list of changes
      ctx.submitOp(ops);

      // call the function again on the next change, if there is one
      if (change.next) {
        applyToShareJS(cm, change.next);
      }
    }

    function check() {
      // magic, no touchy
      setTimeout(function () {
        var cmText = cm.getValue();
        var otDoc = ctx.get();

        if (cmText !== otDoc.text) {
          console.error("Text does not match!");
          console.error("cm: " + cmText);
          console.error("ot: " + otDoc.text);
          // Replace the editor text with the ctx snapshot.
          cm.setValue(ctx.get().text);
        }

        // just draw whatever the server tells us to
        timestamps.draw(otDoc.lines);
      }, 0);
    }

    return ctx;
  }

  if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
    // Node.js
    module.exports = shareCodeMirror;
    module.exports.scriptsDir = __dirname;
  } else {
    if (typeof define === 'function' && define.amd) {
      // AMD
      define([], function () {
        return shareCodeMirror;
      });
    } else {
      // Browser, no AMD
      window.sharejs.Doc.prototype.attachCodeMirror = function (cm, ctx, timestamps) {
        if (!ctx) ctx = this.createContext();
        shareCodeMirror(cm, ctx, timestamps);
      };
    }
  }
})();
<|endoftext|>