<commit_before>
var gulp      = require('gulp');

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

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

gulp.task('clean:bower', $.del.bind(null, [ $.config.paths.bower.toUse ]));

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

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

gulp.task('bower:jquery', function() {
  return gulp.src( $.config.paths.bower.downloaded + '/jquery/dist/*.{js,map}' )
    .pipe( gulp.dest( $.config.paths.bower.toUse + '/vendor/jquery' ) );
});

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

gulp.task('bower:dist', ['bower:dev'], function() {
  return gulp.src( $.config.paths.bower.toUse + '/**/*' )
    .pipe( gulp.dest( $.config.paths.dist ) );
});

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

$.streams.jshint = $.lazypipe()
  .pipe( $.cached, 'jshint' )
  .pipe( $.jshint )
  .pipe( $.jshint.reporter, 'jshint-stylish' )
  .pipe( $.jshint.reporter, 'fail' );

gulp.task('jshint:tools', function() {
  return gulp.src( $.config.tools )
    .pipe( $.streams.jshint() );
});

gulp.task('jshint:project', function() {
  return gulp.src( $.config.project.js )
    .pipe( $.streams.jshint() );
});

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

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

$.streams.lintspaces = $.lazypipe()
  .pipe( $.cached, 'lintspaces' )
  .pipe( $.lintspaces, { editorconfig: $.config.paths.editorconfig } )
  .pipe( $.lintspaces.reporter );

gulp.task('lintspaces:tools', function() {
  return gulp.src( $.config.tools )
    .pipe( $.streams.lintspaces() );
});

gulp.task('lintspaces:project:js', function() {
  return gulp.src( $.config.project.js )
    .pipe( $.streams.lintspaces() );
});

gulp.task('lintspaces:project:styles', function() {
  return gulp.src( $.config.project.styles )
    .pipe( $.streams.lintspaces() );
});

gulp.task('lintspaces:project:html', function() {
  return gulp.src( $.config.project.html )
    .pipe( $.streams.lintspaces() );
});

gulp.task('lintspaces:project', [
  'lintspaces:project:js',
  'lintspaces:project:styles',
  'lintspaces:project:html'
]);

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

// @end: lintspaces
//------------------------------------------------------------------------------

gulp.task('validate', ['jshint', 'lintspaces']);

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

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

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

  return gulp.src( $.config.project.index )
    .pipe( userefAssets ) // Concatenate with gulp-useref
    .pipe( jsFilter )
    .pipe( $.uglify() ) // Minify any javascript sources
    .pipe( jsFilter.restore() )
    .pipe( stylesFilter )
    .pipe( $.csso() ) // Minify any CSS sources
    .pipe( stylesFilter.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( $.config.paths.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: $.config.webserver.port,
    server:{
      baseDir: $.config.paths.dist
    }
  });

});

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

  $.browserSync({
    port: $.config.webserver.port,
    server:{
      baseDir: [
        $.config.paths.src,
        $.config.paths.bower.toUse
      ]
    }
  });

});

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

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

  gulp.watch( $.config.project.html, ['wf:project:html']);

  gulp.watch( $.config.project.js, ['wf:project:js']);

  gulp.watch( $.config.project.styles, ['wf:project:styles']);

});

gulp.task('wf:bs:reload', function() {
  $.reload();
});

gulp.task('wf:bs:reload:stream', function() {
  return gulp.src( $.config.project.styles )
    .pipe( $.cached( 'styles' ) )
    .pipe( $.reload({ stream: true }) );
});

gulp.task('wf:project:html', function( done ) {
  $.sequence(
    'lintspaces:project:html',
    'wf:bs:reload',
    done
  );
});

gulp.task('wf:project:js', function( done ) {
  $.sequence(
    [
      'jshint:project',
      'lintspaces:project:js'
    ],
    'wf:bs:reload',
    done
  );
});

gulp.task('wf:project:styles', function( done ) {
  $.sequence(
    'lintspaces:project:styles',
    'wf:bs:reload:stream',
    done
  );
});

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

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

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

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

// @end: main / default
//==============================================================================
// @end: gulp tasks ============================================================
//==============================================================================
<commit_msg>gulp step 03 - require utils (gulp/$.js) on gulpfile.js<commit_after>
var gulp      = require('gulp'),
    $         = require('./gulp/$');

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

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

gulp.task('clean:bower', $.del.bind(null, [ $.config.paths.bower.toUse ]));

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

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

gulp.task('bower:jquery', function() {
  return gulp.src( $.config.paths.bower.downloaded + '/jquery/dist/*.{js,map}' )
    .pipe( gulp.dest( $.config.paths.bower.toUse + '/vendor/jquery' ) );
});

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

gulp.task('bower:dist', ['bower:dev'], function() {
  return gulp.src( $.config.paths.bower.toUse + '/**/*' )
    .pipe( gulp.dest( $.config.paths.dist ) );
});

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

$.streams.jshint = $.lazypipe()
  .pipe( $.cached, 'jshint' )
  .pipe( $.jshint )
  .pipe( $.jshint.reporter, 'jshint-stylish' )
  .pipe( $.jshint.reporter, 'fail' );

gulp.task('jshint:tools', function() {
  return gulp.src( $.config.tools )
    .pipe( $.streams.jshint() );
});

gulp.task('jshint:project', function() {
  return gulp.src( $.config.project.js )
    .pipe( $.streams.jshint() );
});

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

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

$.streams.lintspaces = $.lazypipe()
  .pipe( $.cached, 'lintspaces' )
  .pipe( $.lintspaces, { editorconfig: $.config.paths.editorconfig } )
  .pipe( $.lintspaces.reporter );

gulp.task('lintspaces:tools', function() {
  return gulp.src( $.config.tools )
    .pipe( $.streams.lintspaces() );
});

gulp.task('lintspaces:project:js', function() {
  return gulp.src( $.config.project.js )
    .pipe( $.streams.lintspaces() );
});

gulp.task('lintspaces:project:styles', function() {
  return gulp.src( $.config.project.styles )
    .pipe( $.streams.lintspaces() );
});

gulp.task('lintspaces:project:html', function() {
  return gulp.src( $.config.project.html )
    .pipe( $.streams.lintspaces() );
});

gulp.task('lintspaces:project', [
  'lintspaces:project:js',
  'lintspaces:project:styles',
  'lintspaces:project:html'
]);

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

// @end: lintspaces
//------------------------------------------------------------------------------

gulp.task('validate', ['jshint', 'lintspaces']);

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

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

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

  return gulp.src( $.config.project.index )
    .pipe( userefAssets ) // Concatenate with gulp-useref
    .pipe( jsFilter )
    .pipe( $.uglify() ) // Minify any javascript sources
    .pipe( jsFilter.restore() )
    .pipe( stylesFilter )
    .pipe( $.csso() ) // Minify any CSS sources
    .pipe( stylesFilter.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( $.config.paths.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: $.config.webserver.port,
    server:{
      baseDir: $.config.paths.dist
    }
  });

});

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

  $.browserSync({
    port: $.config.webserver.port,
    server:{
      baseDir: [
        $.config.paths.src,
        $.config.paths.bower.toUse
      ]
    }
  });

});

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

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

  gulp.watch( $.config.project.html, ['wf:project:html']);

  gulp.watch( $.config.project.js, ['wf:project:js']);

  gulp.watch( $.config.project.styles, ['wf:project:styles']);

});

gulp.task('wf:bs:reload', function() {
  $.reload();
});

gulp.task('wf:bs:reload:stream', function() {
  return gulp.src( $.config.project.styles )
    .pipe( $.cached( 'styles' ) )
    .pipe( $.reload({ stream: true }) );
});

gulp.task('wf:project:html', function( done ) {
  $.sequence(
    'lintspaces:project:html',
    'wf:bs:reload',
    done
  );
});

gulp.task('wf:project:js', function( done ) {
  $.sequence(
    [
      'jshint:project',
      'lintspaces:project:js'
    ],
    'wf:bs:reload',
    done
  );
});

gulp.task('wf:project:styles', function( done ) {
  $.sequence(
    'lintspaces:project:styles',
    'wf:bs:reload:stream',
    done
  );
});

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

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

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

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

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


<commit_before>/*
(function ($, rho, rhoUtil) {
    'use strict';

    var moduleNS = 'Rho.Application';

    var defaultNativeMenu = function() {
        return [];
    }

    rhoUtil.namespace(moduleNS, Application, true);

})(jQuery, Rho, Rho.util);
*/<commit_msg>update Rho.Application.js<commit_after>/*
TODO: add read-only property defaultNativeMenu
(function ($, rho, rhoUtil) {
    'use strict';

    function defaultNativeMenu() {
      return
       { 'Home' : 'home', 'Refresh' : 'refresh',
      	 'Sync' : 'sync', 'Settings' : 'options',
      	 'Log': 'log', 'separator' : '',
      	 'Exit' : 'close'
       };
    }

    rhoUtil.namespace('Rho.Application', {defaultNativeMenu: defaultNativeMenu}, true);

})(jQuery, Rho, Rho.util);
*/<|endoftext|>


<commit_before>/**
 * This is a straight rip-off of the React.js ReactPropTypes.js proptype validators,
 * modified to make it possible to validate Immutable.js data.
 *     ImmutableTypes.listOf is patterned after React.PropTypes.arrayOf, but for Immutable.List
 *     ImmutableTypes.shape  is based on React.PropTypes.shape, but for any Immutable.Iterable
 */
var Immutable = require('immutable');

var ANONYMOUS = '<<anonymous>>';

var ImmutablePropTypes = {
  listOf:       createListOfTypeChecker,
  mapOf:        createMapOfTypeChecker,
  orderedMapOf: createOrderedMapOfTypeChecker,
  setOf:        createSetOfTypeChecker,
  orderedSetOf: createOrderedSetOfTypeChecker,
  stackOf:      createStackOfTypeChecker,
  iterableOf:   createIterableOfTypeChecker,
  recordOf:     createRecordOfTypeChecker,
  shape:        createShapeChecker,
  contains:     createShapeChecker,
  mapContains:  createMapContainsChecker,
  // Primitive Types
  list:       createImmutableTypeChecker('List', Immutable.List.isList),
  map:        createImmutableTypeChecker('Map', Immutable.Map.isMap),
  orderedMap: createImmutableTypeChecker('OrderedMap', Immutable.OrderedMap.isOrderedMap),
  set:        createImmutableTypeChecker('Set', Immutable.Set.isSet),
  orderedSet: createImmutableTypeChecker('OrderedSet', Immutable.OrderedSet.isOrderedSet),
  stack:      createImmutableTypeChecker('Stack', Immutable.Stack.isStack),
  seq:        createImmutableTypeChecker('Seq', Immutable.Seq.isSeq),
  record:     createImmutableTypeChecker('Record', function(isRecord) { return isRecord instanceof Immutable.Record; }),
  iterable:   createImmutableTypeChecker('Iterable', Immutable.Iterable.isIterable)
};

function getPropType(propValue) {
  var propType = typeof propValue;
  if (Array.isArray(propValue)) {
    return 'array';
  }
  if (propValue instanceof RegExp) {
    // Old webkits (at least until Android 4.0) return 'function' rather than
    // 'object' for typeof a RegExp. We'll normalize this here so that /bla/
    // passes PropTypes.object.
    return 'object';
  }
  if (propValue instanceof Immutable.Iterable) {
    return 'Immutable.' + propValue.toSource().split(' ')[0];
  }
  return propType;
}

function createChainableTypeChecker(validate) {
  function checkType(isRequired, props, propName, componentName, location, propFullName) {
    propFullName = propFullName || propName;
    componentName = componentName || ANONYMOUS;
    if (props[propName] == null) {
      var locationName = location;
      if (isRequired) {
        return new Error(
          `Required ${locationName} \`${propFullName}\` was not specified in ` +
          `\`${componentName}\`.`
        );
      }
    } else {
      return validate(props, propName, componentName, location, propFullName);
    }
  }

  var chainedCheckType = checkType.bind(null, false);
  chainedCheckType.isRequired = checkType.bind(null, true);

  return chainedCheckType;
}

function createImmutableTypeChecker(immutableClassName, immutableClassTypeValidator) {
  function validate(props, propName, componentName, location, propFullName) {
    var propValue = props[propName];
    if(!immutableClassTypeValidator(propValue)) {
      var propType = getPropType(propValue);
      return new Error(
        `Invalid ${location} \`${propFullName}\` of type \`${propType}\` ` +
        `supplied to \`${componentName}\`, expected \`${immutableClassName}\`.`
      );
    }
    return null;
  }
  return createChainableTypeChecker(validate);
}

function createIterableTypeChecker(typeChecker, immutableClassName, immutableClassTypeValidator) {

  function validate(props, propName, componentName, location, propFullName) {
    var propValue = props[propName];
    if (!immutableClassTypeValidator(propValue)) {
      var locationName = location;
      var propType = getPropType(propValue);
      return new Error(
        `Invalid ${locationName} \`${propFullName}\` of type ` +
        `\`${propType}\` supplied to \`${componentName}\`, expected an Immutable.js ${immutableClassName}.`
      );
    }

    if (typeof typeChecker !== 'function') {
      return new Error(
        `Invalid typeChecker supplied to \`${componentName}\` ` +
        `for propType \`${propFullName}\`, expected a function.`
      );
    }

    var propValues = propValue.toArray();
    for (var i = 0, len = propValues.length; i < len; i++) {
      var error = typeChecker(propValues, i, componentName, location, `${propFullName}[${i}]`);
      if (error instanceof Error) {
        return error;
      }
    }
  }
  return createChainableTypeChecker(validate);
}

function createListOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'List', Immutable.List.isList);
}

function createMapOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'Map', Immutable.Map.isMap);
}

function createOrderedMapOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'OrderedMap', Immutable.OrderedMap.isOrderedMap);
}

function createSetOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'Set', Immutable.Set.isSet);
}

function createOrderedSetOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'OrderedSet', Immutable.OrderedSet.isOrderedSet);
}

function createStackOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'Stack', Immutable.Stack.isStack);
}

function createIterableOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'Iterable', Immutable.Iterable.isIterable);
}

function createRecordOfTypeChecker(recordKeys) {
  function validate(props, propName, componentName, location, propFullName) {
    var propValue = props[propName];
    var propType = getPropType(propValue);
    if (!(propValue instanceof Immutable.Record)) {
      var locationName = location;
      return new Error(
        `Invalid ${locationName} \`${propFullName}\` of type \`${propType}\` ` +
        `supplied to \`${componentName}\`, expected an Immutable.js Record.`
      );
    }
    for (var key in recordKeys) {
      var checker = recordKeys[key];
      if (!checker) {
        continue;
      }
      var mutablePropValue = propValue.toObject();
      var error = checker(mutablePropValue, key, componentName, location, `${propFullName}.${key}`);
      if (error) {
        return error;
      }
    }
  }
  return createChainableTypeChecker(validate);
}

// there is some irony in the fact that shapeTypes is a standard hash and not an immutable collection
function createShapeTypeChecker(shapeTypes, immutableClassName = 'Iterable', immutableClassTypeValidator = Immutable.Iterable.isIterable) {
  function validate(props, propName, componentName, location, propFullName) {
    var propValue = props[propName];
    var propType = getPropType(propValue);
    if (!immutableClassTypeValidator(propValue)) {
      var locationName = location;
      return new Error(
        `Invalid ${locationName} \`${propFullName}\` of type \`${propType}\` ` +
        `supplied to \`${componentName}\`, expected an Immutable.js ${immutableClassName}.`
      );
    }
    var mutablePropValue = propValue.toObject();
    for (var key in shapeTypes) {
      var checker = shapeTypes[key];
      if (!checker) {
        continue;
      }
      var error = checker(mutablePropValue, key, componentName, location, `${propFullName}.${key}`);
      if (error) {
        return error;
      }
    }
  }
  return createChainableTypeChecker(validate);
}

function createShapeChecker(shapeTypes) {
  return createShapeTypeChecker(shapeTypes);
}

function createMapContainsChecker(shapeTypes) {
  return createShapeTypeChecker(shapeTypes, 'Map', Immutable.Map.isMap);
}

module.exports = ImmutablePropTypes;
<commit_msg>Don't call getPropType until error detected as it is slow for large data structures<commit_after>/**
 * This is a straight rip-off of the React.js ReactPropTypes.js proptype validators,
 * modified to make it possible to validate Immutable.js data.
 *     ImmutableTypes.listOf is patterned after React.PropTypes.arrayOf, but for Immutable.List
 *     ImmutableTypes.shape  is based on React.PropTypes.shape, but for any Immutable.Iterable
 */
var Immutable = require('immutable');

var ANONYMOUS = '<<anonymous>>';

var ImmutablePropTypes = {
  listOf:       createListOfTypeChecker,
  mapOf:        createMapOfTypeChecker,
  orderedMapOf: createOrderedMapOfTypeChecker,
  setOf:        createSetOfTypeChecker,
  orderedSetOf: createOrderedSetOfTypeChecker,
  stackOf:      createStackOfTypeChecker,
  iterableOf:   createIterableOfTypeChecker,
  recordOf:     createRecordOfTypeChecker,
  shape:        createShapeChecker,
  contains:     createShapeChecker,
  mapContains:  createMapContainsChecker,
  // Primitive Types
  list:       createImmutableTypeChecker('List', Immutable.List.isList),
  map:        createImmutableTypeChecker('Map', Immutable.Map.isMap),
  orderedMap: createImmutableTypeChecker('OrderedMap', Immutable.OrderedMap.isOrderedMap),
  set:        createImmutableTypeChecker('Set', Immutable.Set.isSet),
  orderedSet: createImmutableTypeChecker('OrderedSet', Immutable.OrderedSet.isOrderedSet),
  stack:      createImmutableTypeChecker('Stack', Immutable.Stack.isStack),
  seq:        createImmutableTypeChecker('Seq', Immutable.Seq.isSeq),
  record:     createImmutableTypeChecker('Record', function(isRecord) { return isRecord instanceof Immutable.Record; }),
  iterable:   createImmutableTypeChecker('Iterable', Immutable.Iterable.isIterable)
};

function getPropType(propValue) {
  var propType = typeof propValue;
  if (Array.isArray(propValue)) {
    return 'array';
  }
  if (propValue instanceof RegExp) {
    // Old webkits (at least until Android 4.0) return 'function' rather than
    // 'object' for typeof a RegExp. We'll normalize this here so that /bla/
    // passes PropTypes.object.
    return 'object';
  }
  if (propValue instanceof Immutable.Iterable) {
    return 'Immutable.' + propValue.toSource().split(' ')[0];
  }
  return propType;
}

function createChainableTypeChecker(validate) {
  function checkType(isRequired, props, propName, componentName, location, propFullName) {
    propFullName = propFullName || propName;
    componentName = componentName || ANONYMOUS;
    if (props[propName] == null) {
      var locationName = location;
      if (isRequired) {
        return new Error(
          `Required ${locationName} \`${propFullName}\` was not specified in ` +
          `\`${componentName}\`.`
        );
      }
    } else {
      return validate(props, propName, componentName, location, propFullName);
    }
  }

  var chainedCheckType = checkType.bind(null, false);
  chainedCheckType.isRequired = checkType.bind(null, true);

  return chainedCheckType;
}

function createImmutableTypeChecker(immutableClassName, immutableClassTypeValidator) {
  function validate(props, propName, componentName, location, propFullName) {
    var propValue = props[propName];
    if(!immutableClassTypeValidator(propValue)) {
      var propType = getPropType(propValue);
      return new Error(
        `Invalid ${location} \`${propFullName}\` of type \`${propType}\` ` +
        `supplied to \`${componentName}\`, expected \`${immutableClassName}\`.`
      );
    }
    return null;
  }
  return createChainableTypeChecker(validate);
}

function createIterableTypeChecker(typeChecker, immutableClassName, immutableClassTypeValidator) {

  function validate(props, propName, componentName, location, propFullName) {
    var propValue = props[propName];
    if (!immutableClassTypeValidator(propValue)) {
      var locationName = location;
      var propType = getPropType(propValue);
      return new Error(
        `Invalid ${locationName} \`${propFullName}\` of type ` +
        `\`${propType}\` supplied to \`${componentName}\`, expected an Immutable.js ${immutableClassName}.`
      );
    }

    if (typeof typeChecker !== 'function') {
      return new Error(
        `Invalid typeChecker supplied to \`${componentName}\` ` +
        `for propType \`${propFullName}\`, expected a function.`
      );
    }

    var propValues = propValue.toArray();
    for (var i = 0, len = propValues.length; i < len; i++) {
      var error = typeChecker(propValues, i, componentName, location, `${propFullName}[${i}]`);
      if (error instanceof Error) {
        return error;
      }
    }
  }
  return createChainableTypeChecker(validate);
}

function createListOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'List', Immutable.List.isList);
}

function createMapOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'Map', Immutable.Map.isMap);
}

function createOrderedMapOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'OrderedMap', Immutable.OrderedMap.isOrderedMap);
}

function createSetOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'Set', Immutable.Set.isSet);
}

function createOrderedSetOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'OrderedSet', Immutable.OrderedSet.isOrderedSet);
}

function createStackOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'Stack', Immutable.Stack.isStack);
}

function createIterableOfTypeChecker(typeChecker) {
  return createIterableTypeChecker(typeChecker, 'Iterable', Immutable.Iterable.isIterable);
}

function createRecordOfTypeChecker(recordKeys) {
  function validate(props, propName, componentName, location, propFullName) {
    var propValue = props[propName];
    if (!(propValue instanceof Immutable.Record)) {
      var propType = getPropType(propValue);
      var locationName = location;
      return new Error(
        `Invalid ${locationName} \`${propFullName}\` of type \`${propType}\` ` +
        `supplied to \`${componentName}\`, expected an Immutable.js Record.`
      );
    }
    for (var key in recordKeys) {
      var checker = recordKeys[key];
      if (!checker) {
        continue;
      }
      var mutablePropValue = propValue.toObject();
      var error = checker(mutablePropValue, key, componentName, location, `${propFullName}.${key}`);
      if (error) {
        return error;
      }
    }
  }
  return createChainableTypeChecker(validate);
}

// there is some irony in the fact that shapeTypes is a standard hash and not an immutable collection
function createShapeTypeChecker(shapeTypes, immutableClassName = 'Iterable', immutableClassTypeValidator = Immutable.Iterable.isIterable) {
  function validate(props, propName, componentName, location, propFullName) {
    var propValue = props[propName];
    if (!immutableClassTypeValidator(propValue)) {
      var propType = getPropType(propValue);
      var locationName = location;
      return new Error(
        `Invalid ${locationName} \`${propFullName}\` of type \`${propType}\` ` +
        `supplied to \`${componentName}\`, expected an Immutable.js ${immutableClassName}.`
      );
    }
    var mutablePropValue = propValue.toObject();
    for (var key in shapeTypes) {
      var checker = shapeTypes[key];
      if (!checker) {
        continue;
      }
      var error = checker(mutablePropValue, key, componentName, location, `${propFullName}.${key}`);
      if (error) {
        return error;
      }
    }
  }
  return createChainableTypeChecker(validate);
}

function createShapeChecker(shapeTypes) {
  return createShapeTypeChecker(shapeTypes);
}

function createMapContainsChecker(shapeTypes) {
  return createShapeTypeChecker(shapeTypes, 'Map', Immutable.Map.isMap);
}

module.exports = ImmutablePropTypes;
<|endoftext|>


<commit_before>'use strict';

describe('Controller: demande', function() {
  let $controller;

  const RequestService = {
    getCompletion() {
      return true;
    },

    postAction() {
      return {
        then() {
          return true;
        }
      };
    }
  };

  const toastr = {
    error() {}
  };

  const $state = {
    go() {}
  };

  let request = {
    user: 'userId',
    prestations: [],
    status: 'en_cours',
    $update() {}
  };

  const currentUser = {};

  const samplePrestations = {
      cartestationnement: {
        id: 'cartestationnement'
      },
      carteinvalidite: {
        id: 'carteinvalidite',
      },
      aeeh: {
        id: 'aeeh',
      },
      aah: {
        id: 'aah',
      },
      complement: {
        id: 'complement',
      },
      pch: {
        id: 'pch',
      },
      rqth: {
        id: 'rqth',
      },
      crp_cpo_ueros: {
        id: 'crp_cpo_ueros',
      },
      esat: {
        id: 'esat',
      },
      marche_travail: {
        id: 'marche_travail',
      },
      marche_travail_acc: {
        id: 'marche_travail_acc',
      },
      av: {
        id: 'av',
      },
      ems: {
        id: 'ems',
      },
      pps: {
        id: 'pps',
      },
      orp: {
        id: 'orp',
      },
      formation: {
        id: 'formation',
      },
      sms: {
        id: 'sms',
      },
      sms_enfant: {
        id: 'sms_enfant',
      },
      ac: {
        id: 'ac',
      },
      acfp: {
        id: 'acfp',
      }
    };

  // load the service's module
  beforeEach(module('impactApp'));

  beforeEach(inject(function(_$controller_) {
    $controller = _$controller_;
  }));

  describe('prestations list', () => {
    let controller;

    //given
    let $scope = {};

    beforeEach(function() {
      controller = $controller('DemandeCtrl', {
        $state,
        $scope,
        currentUser,
        request,
        RequestService,
        toastr,
        prestations: samplePrestations
      });
    });

    it('should have 16 prestations', function() {
      expect(controller.prestations.length, 16);
    });
  });

  describe('prestations request', () => {
    let controller;

    //given
    let $scope = {};

    beforeEach(function() {
      controller = $controller('DemandeCtrl', {
        $state,
        $scope,
        currentUser,
        request,
        RequestService,
        toastr,
        prestations: samplePrestations
      });
    });

    it('should select the right prestations', function() {
      //given
      controller.cartestationnement = _.assign(controller.cartestationnement, {choice: true});
      controller.carteinvalidite = _.assign(controller.carteinvalidite, {choice: true, renouvellement: true});

      console.log('$scope', $scope);

      $scope.submit({$valid: true});

      //then
      expect($scope.request.renouvellements[0]).toEqual('carteinvalidite');
      expect($scope.request.prestations[0]).toEqual('cartestationnement');
    });

  });

});
<commit_msg>Remove unwanted log<commit_after>'use strict';

describe('Controller: demande', function() {
  let $controller;

  const RequestService = {
    getCompletion() {
      return true;
    },

    postAction() {
      return {
        then() {
          return true;
        }
      };
    }
  };

  const toastr = {
    error() {}
  };

  const $state = {
    go() {}
  };

  let request = {
    user: 'userId',
    prestations: [],
    status: 'en_cours',
    $update() {}
  };

  const currentUser = {};

  const samplePrestations = {
      cartestationnement: {
        id: 'cartestationnement'
      },
      carteinvalidite: {
        id: 'carteinvalidite',
      },
      aeeh: {
        id: 'aeeh',
      },
      aah: {
        id: 'aah',
      },
      complement: {
        id: 'complement',
      },
      pch: {
        id: 'pch',
      },
      rqth: {
        id: 'rqth',
      },
      crp_cpo_ueros: {
        id: 'crp_cpo_ueros',
      },
      esat: {
        id: 'esat',
      },
      marche_travail: {
        id: 'marche_travail',
      },
      marche_travail_acc: {
        id: 'marche_travail_acc',
      },
      av: {
        id: 'av',
      },
      ems: {
        id: 'ems',
      },
      pps: {
        id: 'pps',
      },
      orp: {
        id: 'orp',
      },
      formation: {
        id: 'formation',
      },
      sms: {
        id: 'sms',
      },
      sms_enfant: {
        id: 'sms_enfant',
      },
      ac: {
        id: 'ac',
      },
      acfp: {
        id: 'acfp',
      }
    };

  // load the service's module
  beforeEach(module('impactApp'));

  beforeEach(inject(function(_$controller_) {
    $controller = _$controller_;
  }));

  describe('prestations list', () => {
    let controller;

    //given
    let $scope = {};

    beforeEach(function() {
      controller = $controller('DemandeCtrl', {
        $state,
        $scope,
        currentUser,
        request,
        RequestService,
        toastr,
        prestations: samplePrestations
      });
    });

    it('should have 16 prestations', function() {
      expect(controller.prestations.length, 16);
    });
  });

  describe('prestations request', () => {
    let controller;

    //given
    let $scope = {};

    beforeEach(function() {
      controller = $controller('DemandeCtrl', {
        $state,
        $scope,
        currentUser,
        request,
        RequestService,
        toastr,
        prestations: samplePrestations
      });
    });

    it('should select the right prestations', function() {
      //given
      controller.cartestationnement = _.assign(controller.cartestationnement, {choice: true});
      controller.carteinvalidite = _.assign(controller.carteinvalidite, {choice: true, renouvellement: true});

      $scope.submit({$valid: true});

      //then
      expect($scope.request.renouvellements[0]).toEqual('carteinvalidite');
      expect($scope.request.prestations[0]).toEqual('cartestationnement');
    });

  });

});
<|endoftext|>


<commit_before>'use strict';

var $animateMinErr = minErr('$animate');

/**
 * @ngdoc provider
 * @name  $animateProvider
 *
 * @description
 * Default implementation of $animate that doesn't perform any animations, instead just
 * synchronously performs DOM
 * updates and calls done() callbacks.
 *
 * In order to enable animations the ngAnimate module has to be loaded.
 *
 * To see the functional implementation check out src/ngAnimate/animate.js
 */
var $AnimateProvider = ['$provide', function($provide) {

  this.$$selectors = {};

  /**
   * @ngdoc method
   * @name register
   * @memberof $animate
   *
   * @description
   * Registers a new injectable animation factory function. The factory function produces the
   * animation object which contains callback functions for each event that is expected to be
   * animated.
   *
   *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
   *   must be called once the element animation is complete. If a function is returned then the
   *   animation service will use this function to cancel the animation whenever a cancel event is
   *   triggered.
   *
   *
   *

   *   return {
     *     eventFn : function(element, done) {
     *       //code to run the animation
     *       //once complete, then run done()
     *       return function cancellationFunction() {
     *         //code to cancel the animation
     *       }
     *     }
     *   }
   *

   *
   * @param {string} name The name of the animation.
   * @param {function} factory The factory function that will be executed to return the animation
   *                           object.
   */
  this.register = function(name, factory) {
    var key = name + '-animation';
    if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
        "Expecting class selector starting with '.' got '{0}'.", name);
    this.$$selectors[name.substr(1)] = key;
    $provide.factory(key, factory);
  };

  /**
   * @ngdoc method
   * @name classNameFilter
   * @memberof $animate
   *
   * @description
   * Sets and/or returns the CSS class regular expression that is checked when performing
   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
   * therefore enable $animate to attempt to perform an animation on any element.
   * When setting the classNameFilter value, animations will only be performed on elements
   * that successfully match the filter expression. This in turn can boost performance
   * for low-powered devices as well as applications containing a lot of structural operations.
   * @param {RegExp=} expression The className expression which will be checked against all animations
   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
   */
  this.classNameFilter = function(expression) {
    if(arguments.length === 1) {
      this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
    }
    return this.$$classNameFilter;
  };

  this.$get = ['$timeout', function($timeout) {

    /**
     *
     * @ngdoc service
     * @name $animate
     * @description The $animate service provides rudimentary DOM manipulation functions to
     * insert, remove and move elements within the DOM, as well as adding and removing classes.
     * This service is the core service used by the ngAnimate $animator service which provides
     * high-level animation hooks for CSS and JavaScript.
     *
     * $animate is available in the AngularJS core, however, the ngAnimate module must be included
     * to enable full out animation support. Otherwise, $animate will only perform simple DOM
     * manipulation operations.
     *
     * To learn more about enabling animation support, click here to visit the {@link module:ngAnimate
     * ngAnimate module page} as well as the {@link module:ngAnimate.$animate ngAnimate $animate service
     * page}.
     */
    return {

      /**
       *
       * @ngdoc method
       * @name enter
       * @memberof $animate
       *
       * @description Inserts the element into the DOM either after the `after` element or within
       *   the `parent` element. Once complete, the done() callback will be fired (if provided).
       * @param {jQuery/jqLite element} element the element which will be inserted into the DOM
       * @param {jQuery/jqLite element} parent the parent element which will append the element as
       *   a child (if the after element is not present)
       * @param {jQuery/jqLite element} after the sibling element which will append the element
       *   after itself
       * @param {function=} done callback function that will be called after the element has been
       *   inserted into the DOM
       */
      enter : function(element, parent, after, done) {
        if (after) {
          after.after(element);
        } else {
          if (!parent || !parent[0]) {
            parent = after.parent();
          }
          parent.append(element);
        }
        done && $timeout(done, 0, false);
      },

      /**
       *
       * @ngdoc method
       * @name leave
       * @memberof $animate
       *
       * @description Removes the element from the DOM. Once complete, the done() callback will be
       *   fired (if provided).
       * @param {jQuery/jqLite element} element the element which will be removed from the DOM
       * @param {function=} done callback function that will be called after the element has been
       *   removed from the DOM
       */
      leave : function(element, done) {
        element.remove();
        done && $timeout(done, 0, false);
      },

      /**
       *
       * @ngdoc method
       * @name move
       * @memberof $animate
       *
       * @description Moves the position of the provided element within the DOM to be placed
       * either after the `after` element or inside of the `parent` element. Once complete, the
       * done() callback will be fired (if provided).
       *
       * @param {jQuery/jqLite element} element the element which will be moved around within the
       *   DOM
       * @param {jQuery/jqLite element} parent the parent element where the element will be
       *   inserted into (if the after element is not present)
       * @param {jQuery/jqLite element} after the sibling element where the element will be
       *   positioned next to
       * @param {function=} done the callback function (if provided) that will be fired after the
       *   element has been moved to its new position
       */
      move : function(element, parent, after, done) {
        // Do not remove element before insert. Removing will cause data associated with the
        // element to be dropped. Insert will implicitly do the remove.
        this.enter(element, parent, after, done);
      },

      /**
       *
       * @ngdoc method
       * @name addClass
       * @memberof $animate
       *
       * @description Adds the provided className CSS class value to the provided element. Once
       * complete, the done() callback will be fired (if provided).
       * @param {jQuery/jqLite element} element the element which will have the className value
       *   added to it
       * @param {string} className the CSS class which will be added to the element
       * @param {function=} done the callback function (if provided) that will be fired after the
       *   className value has been added to the element
       */
      addClass : function(element, className, done) {
        className = isString(className) ?
                      className :
                      isArray(className) ? className.join(' ') : '';
        forEach(element, function (element) {
          jqLiteAddClass(element, className);
        });
        done && $timeout(done, 0, false);
      },

      /**
       *
       * @ngdoc method
       * @name removeClass
       * @memberof $animate
       *
       * @description Removes the provided className CSS class value from the provided element.
       * Once complete, the done() callback will be fired (if provided).
       * @param {jQuery/jqLite element} element the element which will have the className value
       *   removed from it
       * @param {string} className the CSS class which will be removed from the element
       * @param {function=} done the callback function (if provided) that will be fired after the
       *   className value has been removed from the element
       */
      removeClass : function(element, className, done) {
        className = isString(className) ?
                      className :
                      isArray(className) ? className.join(' ') : '';
        forEach(element, function (element) {
          jqLiteRemoveClass(element, className);
        });
        done && $timeout(done, 0, false);
      },

      enabled : noop
    };
  }];
}];
<commit_msg>docs(example): fixed memberof tag<commit_after>'use strict';

var $animateMinErr = minErr('$animate');

/**
 * @ngdoc provider
 * @name  $animateProvider
 *
 * @description
 * Default implementation of $animate that doesn't perform any animations, instead just
 * synchronously performs DOM
 * updates and calls done() callbacks.
 *
 * In order to enable animations the ngAnimate module has to be loaded.
 *
 * To see the functional implementation check out src/ngAnimate/animate.js
 */
var $AnimateProvider = ['$provide', function($provide) {

  this.$$selectors = {};

  /**
   * @ngdoc method
   * @name register
   * @memberof $animateProvider
   *
   * @description
   * Registers a new injectable animation factory function. The factory function produces the
   * animation object which contains callback functions for each event that is expected to be
   * animated.
   *
   *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
   *   must be called once the element animation is complete. If a function is returned then the
   *   animation service will use this function to cancel the animation whenever a cancel event is
   *   triggered.
   *
   *
   *

   *   return {
     *     eventFn : function(element, done) {
     *       //code to run the animation
     *       //once complete, then run done()
     *       return function cancellationFunction() {
     *         //code to cancel the animation
     *       }
     *     }
     *   }
   *

   *
   * @param {string} name The name of the animation.
   * @param {function} factory The factory function that will be executed to return the animation
   *                           object.
   */
  this.register = function(name, factory) {
    var key = name + '-animation';
    if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
        "Expecting class selector starting with '.' got '{0}'.", name);
    this.$$selectors[name.substr(1)] = key;
    $provide.factory(key, factory);
  };

  /**
   * @ngdoc method
   * @name classNameFilter
   * @memberof $animateProvider
   *
   * @description
   * Sets and/or returns the CSS class regular expression that is checked when performing
   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
   * therefore enable $animate to attempt to perform an animation on any element.
   * When setting the classNameFilter value, animations will only be performed on elements
   * that successfully match the filter expression. This in turn can boost performance
   * for low-powered devices as well as applications containing a lot of structural operations.
   * @param {RegExp=} expression The className expression which will be checked against all animations
   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
   */
  this.classNameFilter = function(expression) {
    if(arguments.length === 1) {
      this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
    }
    return this.$$classNameFilter;
  };

  this.$get = ['$timeout', function($timeout) {

    /**
     *
     * @ngdoc service
     * @name $animate
     * @description The $animate service provides rudimentary DOM manipulation functions to
     * insert, remove and move elements within the DOM, as well as adding and removing classes.
     * This service is the core service used by the ngAnimate $animator service which provides
     * high-level animation hooks for CSS and JavaScript.
     *
     * $animate is available in the AngularJS core, however, the ngAnimate module must be included
     * to enable full out animation support. Otherwise, $animate will only perform simple DOM
     * manipulation operations.
     *
     * To learn more about enabling animation support, click here to visit the {@link module:ngAnimate
     * ngAnimate module page} as well as the {@link module:ngAnimate.$animate ngAnimate $animate service
     * page}.
     */
    return {

      /**
       *
       * @ngdoc method
       * @name enter
       * @memberof $animate
       *
       * @description Inserts the element into the DOM either after the `after` element or within
       *   the `parent` element. Once complete, the done() callback will be fired (if provided).
       * @param {jQuery/jqLite element} element the element which will be inserted into the DOM
       * @param {jQuery/jqLite element} parent the parent element which will append the element as
       *   a child (if the after element is not present)
       * @param {jQuery/jqLite element} after the sibling element which will append the element
       *   after itself
       * @param {function=} done callback function that will be called after the element has been
       *   inserted into the DOM
       */
      enter : function(element, parent, after, done) {
        if (after) {
          after.after(element);
        } else {
          if (!parent || !parent[0]) {
            parent = after.parent();
          }
          parent.append(element);
        }
        done && $timeout(done, 0, false);
      },

      /**
       *
       * @ngdoc method
       * @name leave
       * @memberof $animate
       *
       * @description Removes the element from the DOM. Once complete, the done() callback will be
       *   fired (if provided).
       * @param {jQuery/jqLite element} element the element which will be removed from the DOM
       * @param {function=} done callback function that will be called after the element has been
       *   removed from the DOM
       */
      leave : function(element, done) {
        element.remove();
        done && $timeout(done, 0, false);
      },

      /**
       *
       * @ngdoc method
       * @name move
       * @memberof $animate
       *
       * @description Moves the position of the provided element within the DOM to be placed
       * either after the `after` element or inside of the `parent` element. Once complete, the
       * done() callback will be fired (if provided).
       *
       * @param {jQuery/jqLite element} element the element which will be moved around within the
       *   DOM
       * @param {jQuery/jqLite element} parent the parent element where the element will be
       *   inserted into (if the after element is not present)
       * @param {jQuery/jqLite element} after the sibling element where the element will be
       *   positioned next to
       * @param {function=} done the callback function (if provided) that will be fired after the
       *   element has been moved to its new position
       */
      move : function(element, parent, after, done) {
        // Do not remove element before insert. Removing will cause data associated with the
        // element to be dropped. Insert will implicitly do the remove.
        this.enter(element, parent, after, done);
      },

      /**
       *
       * @ngdoc method
       * @name addClass
       * @memberof $animate
       *
       * @description Adds the provided className CSS class value to the provided element. Once
       * complete, the done() callback will be fired (if provided).
       * @param {jQuery/jqLite element} element the element which will have the className value
       *   added to it
       * @param {string} className the CSS class which will be added to the element
       * @param {function=} done the callback function (if provided) that will be fired after the
       *   className value has been added to the element
       */
      addClass : function(element, className, done) {
        className = isString(className) ?
                      className :
                      isArray(className) ? className.join(' ') : '';
        forEach(element, function (element) {
          jqLiteAddClass(element, className);
        });
        done && $timeout(done, 0, false);
      },

      /**
       *
       * @ngdoc method
       * @name removeClass
       * @memberof $animate
       *
       * @description Removes the provided className CSS class value from the provided element.
       * Once complete, the done() callback will be fired (if provided).
       * @param {jQuery/jqLite element} element the element which will have the className value
       *   removed from it
       * @param {string} className the CSS class which will be removed from the element
       * @param {function=} done the callback function (if provided) that will be fired after the
       *   className value has been removed from the element
       */
      removeClass : function(element, className, done) {
        className = isString(className) ?
                      className :
                      isArray(className) ? className.join(' ') : '';
        forEach(element, function (element) {
          jqLiteRemoveClass(element, className);
        });
        done && $timeout(done, 0, false);
      },

      enabled : noop
    };
  }];
}];
<|endoftext|>


<commit_before>/**
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * 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.
 */
'use strict';

// Create an all access Firebase Database reference.
var Firebase = require('firebase');
var env = require('./env');
var ref = new Firebase(env.get('firebase.database.url'), 'admin');
ref.auth(env.get('firebase.database.token'));

// Authenticate to gcloud.
// TODO: Make sure you add your Google Project ID, Private key and Email into env.json
var gcloudconfig = {
  projectId: env.get('google.project_id'),
  credentials: {
    private_key: env.get('google.private_key'),
    client_email: env.get('google.client_email')
  }
};
var gcloud = require('gcloud')(gcloudconfig);
var bigquery = gcloud.bigquery();
// TODO: Change <YOUR-DATASET-NAME> with your BigQuery dataset name.
var dataset = bigquery.dataset('<YOUR-DATASET-NAME>');
// TODO: Change <YOUR-TABLE-NAME> with your BigQuery table name.
var table = dataset.table('<YOUR-TABLE-NAME>');

// Copies the Firebase Database element to BigQuery
function addtobigquery(context, data) {
  ref.child(data.path).once('value', function (snap) {
    table.insert({
      ID: snap.key(),
      MESSAGE: snap.val().message,
      NUMBER: snap.val().number
    }, function(err, insertErr, resp) {
      if (err) {
        console.log(err);
        context.done(err);
      } else if (insertErr) {
        console.log(insertErr);
        context.done(insertErr);
      } else {
        context.done();
      }
    });
  });
}

module.exports = {
  addtobigquery: addtobigquery
}<commit_msg>Improved comment.<commit_after>/**
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * 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.
 */
'use strict';

// Create an all access Firebase Database reference.
var Firebase = require('firebase');
var env = require('./env');
var ref = new Firebase(env.get('firebase.database.url'), 'admin');
ref.auth(env.get('firebase.database.token'));

// Authenticate to gcloud.
// TODO: Make sure you add your Google Project ID, Private key and Email into the env.json file.
var gcloudconfig = {
  projectId: env.get('google.project_id'),
  credentials: {
    private_key: env.get('google.private_key'),
    client_email: env.get('google.client_email')
  }
};
var gcloud = require('gcloud')(gcloudconfig);
var bigquery = gcloud.bigquery();
// TODO: Change <YOUR-DATASET-NAME> with your BigQuery dataset name.
var dataset = bigquery.dataset('<YOUR-DATASET-NAME>');
// TODO: Change <YOUR-TABLE-NAME> with your BigQuery table name.
var table = dataset.table('<YOUR-TABLE-NAME>');

// Copies the Firebase Database element to BigQuery
function addtobigquery(context, data) {
  ref.child(data.path).once('value', function (snap) {
    table.insert({
      ID: snap.key(),
      MESSAGE: snap.val().message,
      NUMBER: snap.val().number
    }, function(err, insertErr, resp) {
      if (err) {
        console.log(err);
        context.done(err);
      } else if (insertErr) {
        console.log(insertErr);
        context.done(insertErr);
      } else {
        context.done();
      }
    });
  });
}

module.exports = {
  addtobigquery: addtobigquery
}<|endoftext|>


<commit_before>import express from 'express';
import React from 'react';
import ReactDOM from 'react-dom/server';
import compression from 'compression';
import http from 'http';
import proxy from 'http-proxy-middleware';
import path from 'path';
import PrettyError from 'pretty-error';
import createHistory from 'react-router/lib/createMemoryHistory';
import { match } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import { ReduxAsyncConnect, loadOnServer } from 'redux-connect';
import { Provider } from 'react-redux';

import ApiClient from './helpers/ApiClient';
import config from './config';
import createStore from './redux/create';
import baseRoute from './routes';
import BaseHtml from './helpers/BaseHtml';

import './base.scss';

const baseUrl = `http://${config.internalApiHost}:${config.internalApiPort}`;
const app = new express();
const pretty = new PrettyError();
const server = new http.Server(app);
const bypassUrls = [
  '/api',
  '/_(reportissues|set_session|clear_session)',
  '/_new*',
];

// TODO: use nginx
app.use(express.static(path.join(__dirname, '..', 'static')));

if (__DEVELOPMENT__) {
  app.use('/shared', express.static(path.join(__dirname, 'shared')));

  // Proxy client API requets to server for now to avoid
  // CORS during port 3000 development
  app.use(bypassUrls, proxy({ target: baseUrl, logLevel: 'debug' }));
}

app.use(compression());

// intercept favicon.ico
app.use('/favicon.ico', (req, res) => {
  res.status(404).send('Not Found');
});

app.use((req, res) => {
  if (__DEVELOPMENT__) {
    // Do not cache webpack stats: the script file would change since
    // hot module replacement is enabled in the development env
    webpackIsomorphicTools.refresh();
  }
  const client = new ApiClient(req);
  const memoryHistory = createHistory(req.originalUrl);
  const store = createStore(memoryHistory, client);

  const createSelectLocationState = () => {
    let prevRoutingState;
    let prevRoutingStateJS;
    return (state) => {
      const routingState = state.get('routing'); // or state.routing
      if (typeof prevRoutingState === 'undefined' || prevRoutingState !== routingState) {
        prevRoutingState = routingState;
        prevRoutingStateJS = routingState.toJS();
      }
      return prevRoutingStateJS;
    };
  };

  const history = syncHistoryWithStore(memoryHistory, store, {
    selectLocationState: createSelectLocationState()
  });

  function hydrateOnClient() {
    res.send(`<!doctype html>\n
      ${ReactDOM.renderToString(<BaseHtml assets={webpackIsomorphicTools.assets()} store={store} />)}`);
  }

  if (__DISABLE_SSR__) {
    hydrateOnClient();
    return;
  }

  match({ history, routes: baseRoute(store), location: req.originalUrl }, (error, redirectLocation, renderProps) => {
    if (redirectLocation) {
      res.redirect(redirectLocation.pathname + redirectLocation.search);
    } else if (error) {
      console.error('ROUTER ERROR:', pretty.render(error));
      res.status(500);
      hydrateOnClient();
    } else if (renderProps) {
      loadOnServer({ ...renderProps, store }).then(() => {
        const component = (
          <Provider store={store} key="provider">
            <ReduxAsyncConnect {...renderProps} />
          </Provider>
        );

        res.status(200);

        global.navigator = { userAgent: req.headers['user-agent'] };

        res.send(`<!doctype html>\n
          ${ReactDOM.renderToString(<BaseHtml assets={webpackIsomorphicTools.assets()} component={component} store={store} />)}`); // eslint-disable-line max-len
      });
    } else {
      res.status(404).send('Not found');
    }
  });
});

if (config.port) {
  server.listen(config.port, (err) => {
    if (err) {
      console.error(err);
    }
    console.info('----\n==> ✅  %s is running, talking to API server on %s.', config.app.title, config.internalApiPort);
    console.info('==> 💻  Open http://%s:%s in a browser to view the app.', config.host, config.port);
  });
} else {
  console.error('==>     ERROR: No PORT environment variable has been specified');
}

process.on('unhandledRejection', (error) => {
  console.log('ERROR:', error);
});
<commit_msg>Proxy _message requests<commit_after>import express from 'express';
import React from 'react';
import ReactDOM from 'react-dom/server';
import compression from 'compression';
import http from 'http';
import proxy from 'http-proxy-middleware';
import path from 'path';
import PrettyError from 'pretty-error';
import createHistory from 'react-router/lib/createMemoryHistory';
import { match } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import { ReduxAsyncConnect, loadOnServer } from 'redux-connect';
import { Provider } from 'react-redux';

import ApiClient from './helpers/ApiClient';
import config from './config';
import createStore from './redux/create';
import baseRoute from './routes';
import BaseHtml from './helpers/BaseHtml';

import './base.scss';

const baseUrl = `http://${config.internalApiHost}:${config.internalApiPort}`;
const app = new express();
const pretty = new PrettyError();
const server = new http.Server(app);
const bypassUrls = [
  '/api',
  '/_(reportissues|set_session|clear_session)',
  '/_new*',
  '/_message'
];

// TODO: use nginx
app.use(express.static(path.join(__dirname, '..', 'static')));

if (__DEVELOPMENT__) {
  app.use('/shared', express.static(path.join(__dirname, 'shared')));

  // Proxy client API requets to server for now to avoid
  // CORS during port 3000 development
  app.use(bypassUrls, proxy({ target: baseUrl, logLevel: 'debug' }));
}

app.use(compression());

// intercept favicon.ico
app.use('/favicon.ico', (req, res) => {
  res.status(404).send('Not Found');
});

app.use((req, res) => {
  if (__DEVELOPMENT__) {
    // Do not cache webpack stats: the script file would change since
    // hot module replacement is enabled in the development env
    webpackIsomorphicTools.refresh();
  }
  const client = new ApiClient(req);
  const memoryHistory = createHistory(req.originalUrl);
  const store = createStore(memoryHistory, client);

  const createSelectLocationState = () => {
    let prevRoutingState;
    let prevRoutingStateJS;
    return (state) => {
      const routingState = state.get('routing'); // or state.routing
      if (typeof prevRoutingState === 'undefined' || prevRoutingState !== routingState) {
        prevRoutingState = routingState;
        prevRoutingStateJS = routingState.toJS();
      }
      return prevRoutingStateJS;
    };
  };

  const history = syncHistoryWithStore(memoryHistory, store, {
    selectLocationState: createSelectLocationState()
  });

  function hydrateOnClient() {
    res.send(`<!doctype html>\n
      ${ReactDOM.renderToString(<BaseHtml assets={webpackIsomorphicTools.assets()} store={store} />)}`);
  }

  if (__DISABLE_SSR__) {
    hydrateOnClient();
    return;
  }

  match({ history, routes: baseRoute(store), location: req.originalUrl }, (error, redirectLocation, renderProps) => {
    if (redirectLocation) {
      res.redirect(redirectLocation.pathname + redirectLocation.search);
    } else if (error) {
      console.error('ROUTER ERROR:', pretty.render(error));
      res.status(500);
      hydrateOnClient();
    } else if (renderProps) {
      loadOnServer({ ...renderProps, store }).then(() => {
        const component = (
          <Provider store={store} key="provider">
            <ReduxAsyncConnect {...renderProps} />
          </Provider>
        );

        res.status(200);

        global.navigator = { userAgent: req.headers['user-agent'] };

        res.send(`<!doctype html>\n
          ${ReactDOM.renderToString(<BaseHtml assets={webpackIsomorphicTools.assets()} component={component} store={store} />)}`); // eslint-disable-line max-len
      });
    } else {
      res.status(404).send('Not found');
    }
  });
});

if (config.port) {
  server.listen(config.port, (err) => {
    if (err) {
      console.error(err);
    }
    console.info('----\n==> ✅  %s is running, talking to API server on %s.', config.app.title, config.internalApiPort);
    console.info('==> 💻  Open http://%s:%s in a browser to view the app.', config.host, config.port);
  });
} else {
  console.error('==>     ERROR: No PORT environment variable has been specified');
}

process.on('unhandledRejection', (error) => {
  console.log('ERROR:', error);
});
<|endoftext|>


<commit_before>/**
 * Talisman clustering/k-means
 * ============================
 *
 * Function related to k-means clustering.
 *
 * [Reference]: https://en.wikipedia.org/wiki/K-means_clustering
 */
import euclidean from '../metrics/distance/euclidean';
import {vec} from '../helpers/vectors';
import {createRandom, createSample} from '../helpers/random';

/**
 * Default options for k-means clustering.
 */
const DEFAULTS = {
  k: 8,
  distance: euclidean,
  maxIterations: 300,
  initialCentroids: null,
  rng: Math.random
};

/**
 * Helpers.
 */
function compareCentroids(a, b) {
  for (let i = 0, l = a.length; i < l; i++) {
    for (let j = 0, m = a[i].length; j < m; j++) {
      if (a[i][j] !== b[i][j])
        return false;
    }
  }

  return true;
}

/**
 * KMeans class used to fine tune the clustering when needed & handling
 * the internal state of the process.
 *
 * @constructor
 * @param {array}          data                       - Array of vectors.
 * @param {object}         options                    - Possible options:
 * @param {number}         [options.k]                - Number of clusters.
 * @param {function}       [options.distance]         - Distance function.
 * @param {number}         [options.maxIterations]
 *   - Maximum number of iterations.
 * @param {array|function} [options.initialCentroids]
 *   - Either an array of initial centroids or a function computing them.
 * @param {function}       [options.sampler]          - Sampling function.
 * @param {function}       [options.rng]              - RNG function to use.
 */
export class KMeans {
  constructor(data, options = {}) {

    // Enforcing data validity
    if (!Array.isArray(data))
      throw Error('talisman/clustering/k-means: dataset should be an array of vectors.');

    // Properties
    this.data = data;
    this.dimension = this.data[0].length;
    this.iterations = 0;
    this.centroids = null;
    this.previousCentroids = null;

    // Options
    const rng = options.rng || DEFAULTS.rng;

    if (typeof rng !== 'function')
      throw new Error('talisman/clustering/k-means: `rng` should be a function.');

    this.k = options.k || DEFAULTS.k;
    this.distance = options.distance || DEFAULTS.distance;
    this.maxIterations = options.maxIterations || DEFAULTS.maxIterations;
    this.sampler = createSample(rng).bind(null, this.k);
    this.randomVectorIndex = createRandom(rng).bind(null, 0, this.data.length);

    // Enforcing correct options
    if (typeof this.k !== 'number' || this.k <= 0)
      throw Error('talisman/clustering/k-means: `k` should be > 0.');

    if (this.data.length < this.k)
      throw Error('talisman/clustering/k-means: k is greater than the number of provided vectors.');

    if (typeof this.distance !== 'function')
      throw Error('talisman/clustering/k-means: the `distance` option should be a function.');

    if (typeof this.maxIterations !== 'number' || this.maxIterations <= 0)
      throw Error('talisman/clustering/k-means: the `maxIterations` option should be > 0.');

    this.clusters = new Uint16Array(this.data.length);

    // Computing initial centroids
    let initialCentroids = options.initialCentroids;

    if (initialCentroids) {

      // The user is giving the initial centroids:
      if (typeof initialCentroids === 'function')
        initialCentroids = initialCentroids(this.data, {
          k: this.k,
          distance: this.distance,
          maxIterations: this.maxIterations
        });
    }
    else {

      // Else, we're gonna choose the initial centroids randomly
      initialCentroids = this.sampler(this.data);
    }

    // Ensuring the starting centroids are correct
    if (!Array.isArray(initialCentroids))
      throw Error('talisman/clustering/k-means: `initialCentroids` are not an array or the function you provided to compute them returned invalid data (could be your `sampler`).');

    if (initialCentroids.length !== this.k)
      throw Error(`talisman/clustering/k-means: you should provide k centroids (got ${initialCentroids.length} instead of ${this.k}).`);

    if (!initialCentroids.every(centroid => Array.isArray(centroid) && centroid.length === this.dimension))
      throw Error('talisman/clustering/k-means: at least one of the provided or computed centroids is not of the correct dimension.');

    this.centroids = initialCentroids;
  }

  /**
   * Method used to perform one iteration of the clustering algorithm.
   *
   * @return {KMeans} - Returns itself for chaining.
   */
  iterate() {

    // If the clustering has already converged, we break
    if (this.converged)
      return this;

    // Initializing clusters states
    const clusterStates = new Uint8Array(this.k);

    // Iterating through the dataset's vectors
    for (let i = 0, l = this.data.length; i < l; i++) {
      const vector = this.data[i];

      // Finding the closest centroid
      let min = Infinity,
          centroidIndex = 0;

      for (let j = 0; j < this.k; j++) {
        const d = this.distance(vector, this.centroids[j]);

        if (d < min) {
          min = d;
          centroidIndex = j;
        }
      }

      // Mapping the vector to the correct centroid index
      this.clusters[i] = centroidIndex;

      // Indicating our cluster isn't empty anymore
      clusterStates[centroidIndex] = 1;
    }

    // If any of the clusters is empty, we need to give it a random vector
    for (let i = 0; i < this.k; i++) {
      if (!clusterStates[i]) {

        // Finding a random vector
        const randomVectorIndex = this.randomVectorIndex();

        // Let's put it in our empty cluster
        this.clusters[randomVectorIndex] = i;
      }
    }

    // We now find the new centroids
    this.previousCentroids = this.centroids;
    this.centroids = new Array(this.k);

    for (let i = 0; i < this.k; i++)
      this.centroids[i] = vec(this.dimension, 0);

    const sizes = vec(this.dimension, 0);

    for (let i = 0, l = this.data.length; i < l; i++) {
      const vector = this.data[i],
            clusterIndex = this.clusters[i];

      for (let j = 0; j < this.dimension; j++)
        this.centroids[clusterIndex][j] += vector[j];

      sizes[clusterIndex]++;
    }

    for (let i = 0; i < this.k; i++) {
      for (let j = 0; j < this.dimension; j++)
        this.centroids[i][j] /= sizes[i];
    }

    this.iterations++;

    // Checking if the clustering has converged
    this.converged = compareCentroids(this.previousCentroids, this.centroids);

    return this;
  }

  /**
   * Method used to start the clustering process.
   *
   * @return {array} - The resulting clusters.
   */
  run() {

    // While we don't converge or haven't performed the allowed iterations:
    while (!this.converged && this.iterations < this.maxIterations)
      this.iterate();

    // Now we need to "compile" the clusters
    const clusters = new Array(this.k);

    for (let i = 0; i < this.k; i++)
      clusters[i] = [];

    for (let i = 0, l = this.data.length; i < l; i++)
      clusters[this.clusters[i]].push(this.data[i]);

    return clusters;
  }
}

/**
 * Exporting a convenient function to perform simple k-means clustering.
 *
 * @param  {object} options - Clustering options.
 * @param  {array}  data    - Target dataset.
 * @param  {array}          - Resulting clusters.
 */
export default function kMeans(options, data) {
  const clusterer = new KMeans(data, options);

  const clusters = clusterer.run();

  return clusters;
}
<commit_msg>Fixing k-means edge case<commit_after>/**
 * Talisman clustering/k-means
 * ============================
 *
 * Function related to k-means clustering.
 *
 * [Reference]: https://en.wikipedia.org/wiki/K-means_clustering
 */
import euclidean from '../metrics/distance/euclidean';
import {vec} from '../helpers/vectors';
import {createRandom, createSample} from '../helpers/random';

/**
 * Default options for k-means clustering.
 */
const DEFAULTS = {
  k: 8,
  distance: euclidean,
  maxIterations: 300,
  initialCentroids: null,
  rng: Math.random
};

/**
 * Helpers.
 */
function compareCentroids(a, b) {
  for (let i = 0, l = a.length; i < l; i++) {
    for (let j = 0, m = a[i].length; j < m; j++) {
      if (a[i][j] !== b[i][j])
        return false;
    }
  }

  return true;
}

/**
 * KMeans class used to fine tune the clustering when needed & handling
 * the internal state of the process.
 *
 * @constructor
 * @param {array}          data                       - Array of vectors.
 * @param {object}         options                    - Possible options:
 * @param {number}         [options.k]                - Number of clusters.
 * @param {function}       [options.distance]         - Distance function.
 * @param {number}         [options.maxIterations]
 *   - Maximum number of iterations.
 * @param {array|function} [options.initialCentroids]
 *   - Either an array of initial centroids or a function computing them.
 * @param {function}       [options.sampler]          - Sampling function.
 * @param {function}       [options.rng]              - RNG function to use.
 */
export class KMeans {
  constructor(data, options = {}) {

    // Enforcing data validity
    if (!Array.isArray(data))
      throw Error('talisman/clustering/k-means: dataset should be an array of vectors.');

    // Properties
    this.data = data;
    this.dimension = this.data[0].length;
    this.iterations = 0;
    this.centroids = null;
    this.previousCentroids = null;

    // Options
    const rng = options.rng || DEFAULTS.rng;

    if (typeof rng !== 'function')
      throw new Error('talisman/clustering/k-means: `rng` should be a function.');

    this.k = options.k || DEFAULTS.k;
    this.distance = options.distance || DEFAULTS.distance;
    this.maxIterations = options.maxIterations || DEFAULTS.maxIterations;
    this.sampler = createSample(rng).bind(null, this.k);
    this.randomVectorIndex = createRandom(rng).bind(null, 0, this.data.length);

    // Enforcing correct options
    if (typeof this.k !== 'number' || this.k <= 0)
      throw Error('talisman/clustering/k-means: `k` should be > 0.');

    if (this.data.length < this.k)
      throw Error('talisman/clustering/k-means: k is greater than the number of provided vectors.');

    if (typeof this.distance !== 'function')
      throw Error('talisman/clustering/k-means: the `distance` option should be a function.');

    if (typeof this.maxIterations !== 'number' || this.maxIterations <= 0)
      throw Error('talisman/clustering/k-means: the `maxIterations` option should be > 0.');

    this.clusters = new Uint16Array(this.data.length);

    // Computing initial centroids
    let initialCentroids = options.initialCentroids;

    if (initialCentroids) {

      // The user is giving the initial centroids:
      if (typeof initialCentroids === 'function')
        initialCentroids = initialCentroids(this.data, {
          k: this.k,
          distance: this.distance,
          maxIterations: this.maxIterations
        });
    }
    else {

      // Else, we're gonna choose the initial centroids randomly
      initialCentroids = this.sampler(this.data);
    }

    // Ensuring the starting centroids are correct
    if (!Array.isArray(initialCentroids))
      throw Error('talisman/clustering/k-means: `initialCentroids` are not an array or the function you provided to compute them returned invalid data (could be your `sampler`).');

    if (initialCentroids.length !== this.k)
      throw Error(`talisman/clustering/k-means: you should provide k centroids (got ${initialCentroids.length} instead of ${this.k}).`);

    if (!initialCentroids.every(centroid => Array.isArray(centroid) && centroid.length === this.dimension))
      throw Error('talisman/clustering/k-means: at least one of the provided or computed centroids is not of the correct dimension.');

    this.centroids = initialCentroids;
  }

  /**
   * Method used to perform one iteration of the clustering algorithm.
   *
   * @return {KMeans} - Returns itself for chaining.
   */
  iterate() {

    // If the clustering has already converged, we break
    if (this.converged)
      return this;

    // Initializing clusters states
    const clusterStates = new Uint8Array(this.k);

    // Iterating through the dataset's vectors
    for (let i = 0, l = this.data.length; i < l; i++) {
      const vector = this.data[i];

      // Finding the closest centroid
      let min = Infinity,
          centroidIndex = 0;

      for (let j = 0; j < this.k; j++) {
        const d = this.distance(vector, this.centroids[j]);

        if (d < min) {
          min = d;
          centroidIndex = j;
        }
      }

      // Mapping the vector to the correct centroid index
      this.clusters[i] = centroidIndex;

      // Indicating our cluster isn't empty anymore
      clusterStates[centroidIndex] = 1;
    }

    // If any of the clusters is empty, we need to give it a random vector
    const alreadyPluckedVectors = new Set();

    for (let i = 0; i < this.k; i++) {
      if (!clusterStates[i]) {

        // Finding a random vector
        let randomVectorIndex;
        do {
          randomVectorIndex = this.randomVectorIndex();
        }
        while (alreadyPluckedVectors.has(randomVectorIndex));

        alreadyPluckedVectors.add(randomVectorIndex);

        // Let's put it in our empty cluster
        this.clusters[randomVectorIndex] = i;
      }
    }

    // We now find the new centroids
    this.previousCentroids = this.centroids;
    this.centroids = new Array(this.k);

    for (let i = 0; i < this.k; i++)
      this.centroids[i] = vec(this.dimension, 0);

    const sizes = vec(this.dimension, 0);

    for (let i = 0, l = this.data.length; i < l; i++) {
      const vector = this.data[i],
            clusterIndex = this.clusters[i];

      for (let j = 0; j < this.dimension; j++)
        this.centroids[clusterIndex][j] += vector[j];

      sizes[clusterIndex]++;
    }

    for (let i = 0; i < this.k; i++) {
      for (let j = 0; j < this.dimension; j++)
        this.centroids[i][j] /= sizes[i];
    }

    this.iterations++;

    // Checking if the clustering has converged
    this.converged = compareCentroids(this.previousCentroids, this.centroids);

    return this;
  }

  /**
   * Method used to start the clustering process.
   *
   * @return {array} - The resulting clusters.
   */
  run() {

    // While we don't converge or haven't performed the allowed iterations:
    while (!this.converged && this.iterations < this.maxIterations)
      this.iterate();

    // Now we need to "compile" the clusters
    const clusters = new Array(this.k);

    for (let i = 0; i < this.k; i++)
      clusters[i] = [];

    for (let i = 0, l = this.data.length; i < l; i++)
      clusters[this.clusters[i]].push(this.data[i]);

    return clusters;
  }
}

/**
 * Exporting a convenient function to perform simple k-means clustering.
 *
 * @param  {object} options - Clustering options.
 * @param  {array}  data    - Target dataset.
 * @param  {array}          - Resulting clusters.
 */
export default function kMeans(options, data) {
  const clusterer = new KMeans(data, options);

  const clusters = clusterer.run();

  return clusters;
}
<|endoftext|>


<commit_before>Router.map(function () {
	this.route('frameSchedule', {
		path: '/frame/schedule',
		layoutTemplate: 'frameLayout',
	});
});

Template.frameSchedule.onCreated(function() {
	var filter = Filtering(EventPredicates);

	var instance = this;
	instance.interval = new ReactiveVar(60);
	instance.scheduleStart = new ReactiveVar(moment());
	instance.separators = new ReactiveVar([]);
	instance.repeatingOnly = new ReactiveVar(false);

	// Read query params
	this.autorun(function() {
		var query = Router.current().params.query;

		instance.repeatingOnly.set(Object.hasOwnProperty(query, 'repeating'));

		var scheduleStart;
		if (query.start) scheduleStart = moment(query.start);
		if (!scheduleStart || !scheduleStart.isValid()) scheduleStart = moment(minuteTime.get()).startOf('week');
		instance.scheduleStart.set(scheduleStart);

		var rawSeps = (query.sep || "").split(',');
		var seps = [];
		_.each(rawSeps, function(rawSep) {
			if (rawSep.length === 0) {
				return;
			}

			if (rawSep.length < 3) {
				rawSep = rawSep + "00";
			}

			var hm = parseInt(rawSep, 10);
			if (!isNaN(hm)) {
				var h = Math.floor(hm/100);
				var m = hm % 100;
				seps.push(h*60+m);
			}
		});
		var separators = _.uniq(seps);
		instance.separators.set(separators);

		var readInterval = parseInt(query.interval, 10);
		if (!isNaN(readInterval) && readInterval > 0) {
			instance.interval.set(readInterval);
		} else {
			if (separators.length > 0) {
				instance.interval.set(24*60);
			} else {
				instance.interval.set(60);
			}
		}

		filter.clear().read(query);
		filter.add('after', scheduleStart);
		filter.add('end', moment(scheduleStart).add(4, 'week'));
		filter.done();
	});

	this.autorun(function() {
		subs.subscribe('eventsFind', filter.toQuery(), 100);
	});

	instance.days = new ReactiveVar([]);
	instance.intervals = new ReactiveVar([]);
	instance.slots = new ReactiveVar({});
	instance.kindMap = function() { return 0; };

	this.autorun(function() {
		var scheduleStart = moment(filter.get('after'));
		var end = moment(filter.get('end'));
		var dayCount = end.diff(scheduleStart, 'days');
		var interval = instance.interval.get();

		// Track repeating events so we know how often they occur.
		// The key to this dict is a combination of courseId, weekday and start time.
		var repetitionCount = {};

		// Load events but keep only the first when they repeat on the same
		// weekday at the same time.
		var dedupedEvents = [];
		eventsFind(filter.toQuery(), 200).forEach(function(event) {
			var repKey = event.start.getDay()+'-'+event.start.getHours()+'-'+ event.start.getMinutes()+'-';

			// If there is no courseId, we fall back to replicationId, then _id.
			if (event.courseId) {
				repKey += event.courseId;
			} else if (event.replicaOf) {
				repKey += event.replicaOf;
			} else {
				repKey += event._id;
			}

			if (repetitionCount[repKey] >= 1) {
				repetitionCount[repKey] += 1;
			} else {
				repetitionCount[repKey] = 1;

				event.repKey = repKey;
				dedupedEvents.push(event);
			}
		});

		// Because we need to find the closest separator later on we create a
		// reversed copy which is easier to search.
		var separators = instance.separators.get().slice().reverse();

		// List of intervals where events or separators are placed
		var intervals = _.reduce(separators, function(intervals, separator) {
			intervals[separator] = separator;
			return intervals;
		}, {});

		// List of days where events where found
		var days = {};

		// Map of slots where events were found. Each slot holds a list of events.
		var slots = {};

		// Count occurences of first few chars in event titles
		// This helps coloring the events so they're easier to scan.
		var kinds = {};

		// Place found events into the slots
		_.each(dedupedEvents, function(event) {
			event.repCount = repetitionCount[event.repKey];
			if (event.repCount < 2 && instance.repeatingOnly.get()) {
				// Skip
				return;
			}

			var eventStart = moment(event.start);
			var dayStart = moment(eventStart).startOf('day');

			var day = dayStart.diff(scheduleStart, 'days') % 7;
			days[day] = day;

			var minuteDiff = eventStart.diff(dayStart, 'minutes');
			var intervalStart = Math.floor(minuteDiff / interval) * interval;
			var closestSeparator = _.find(separators, function(sep) {
				return sep <= minuteDiff;
			});

			var mins = Math.max(intervalStart, closestSeparator || 0);
			intervals[mins] = mins;

			if (!slots[mins]) slots[mins] = [];
			if (!slots[mins][day]) slots[mins][day] = [];
			slots[mins][day].push(event);

			var kindId = event.title.substr(0, 5);
			if (!kinds[kindId]) kinds[kindId] = 1;
			kinds[kindId] += 1;
		});

		var numCmp = function(a, b) { return a - b; };
		instance.days.set(_.values(days).sort(numCmp));
		instance.intervals.set(_.values(intervals).sort(numCmp));
		instance.slots.set(slots);

		// Build list of most used titles (first few chars)
		var mostUsedKinds = _.sortBy(_.pairs(kinds), function(kv) { return -kv[1]; });
		var kindRank = _.object(_.map(mostUsedKinds.slice(0, 15), function(kv, rank) {
			return [kv[0], rank+1];
		}));
		instance.kindMap = function(title) {
			var kindId = title.substr(0, 5);
			if (kindRank[kindId]) return kindRank[kindId];
			return 0;
		};
	});
});

Template.frameSchedule.helpers({
	month: function() {
		var instance = Template.instance();
		return moment(instance.scheduleStart.get()).format('MMMM');
	},

	days: function() {
		var instance = Template.instance();
		var scheduleStart = instance.scheduleStart.get();
		return _.map(Template.instance().days.get(), function(day) {
			return moment(scheduleStart).add(day, 'days').format('dddd');
		});
	},

	intervals: function() {
		var slots = Template.instance().slots.get();

		return _.map(Template.instance().intervals.get(), function(mins) {
			return {
				interval: moment().hour(0).minute(mins).format('LT'),
				slots: _.map(Template.instance().days.get(), function(day) {
					return slots[mins] && slots[mins][day];
				})
			};
		});
	},

	type: function() {
		return Template.instance().kindMap(this.title);
	},

	customStartTime: function(interval) {
		var event = this;
		var startTime = moment(event.start).format('LT');
		return (interval !== startTime) ? startTime : false;
	},

	single: function() {
		return this.repCount < 2;
	},

	showDate: function() {
		// The date is shown if an event has now repetitions...
		if (this.repCount < 2) return true;

		// ... or if it doesn't occur this week.
		var thisWeek = moment().startOf('week');
		var eventWeek = moment(this.start).startOf('week');
		return eventWeek.isAfter(thisWeek);
	}
});
<commit_msg>increase event limit so that big schedules still show all events<commit_after>Router.map(function () {
	this.route('frameSchedule', {
		path: '/frame/schedule',
		layoutTemplate: 'frameLayout',
	});
});

Template.frameSchedule.onCreated(function() {
	var filter = Filtering(EventPredicates);

	var instance = this;
	instance.interval = new ReactiveVar(60);
	instance.scheduleStart = new ReactiveVar(moment());
	instance.separators = new ReactiveVar([]);
	instance.repeatingOnly = new ReactiveVar(false);

	// Read query params
	this.autorun(function() {
		var query = Router.current().params.query;

		instance.repeatingOnly.set(Object.hasOwnProperty(query, 'repeating'));

		var scheduleStart;
		if (query.start) scheduleStart = moment(query.start);
		if (!scheduleStart || !scheduleStart.isValid()) scheduleStart = moment(minuteTime.get()).startOf('week');
		instance.scheduleStart.set(scheduleStart);

		var rawSeps = (query.sep || "").split(',');
		var seps = [];
		_.each(rawSeps, function(rawSep) {
			if (rawSep.length === 0) {
				return;
			}

			if (rawSep.length < 3) {
				rawSep = rawSep + "00";
			}

			var hm = parseInt(rawSep, 10);
			if (!isNaN(hm)) {
				var h = Math.floor(hm/100);
				var m = hm % 100;
				seps.push(h*60+m);
			}
		});
		var separators = _.uniq(seps);
		instance.separators.set(separators);

		var readInterval = parseInt(query.interval, 10);
		if (!isNaN(readInterval) && readInterval > 0) {
			instance.interval.set(readInterval);
		} else {
			if (separators.length > 0) {
				instance.interval.set(24*60);
			} else {
				instance.interval.set(60);
			}
		}

		filter.clear().read(query);
		filter.add('after', scheduleStart);
		filter.add('end', moment(scheduleStart).add(4, 'week'));
		filter.done();
	});

	this.autorun(function() {
		subs.subscribe('eventsFind', filter.toQuery(), 500);
	});

	instance.days = new ReactiveVar([]);
	instance.intervals = new ReactiveVar([]);
	instance.slots = new ReactiveVar({});
	instance.kindMap = function() { return 0; };

	this.autorun(function() {
		var scheduleStart = moment(filter.get('after'));
		var end = moment(filter.get('end'));
		var dayCount = end.diff(scheduleStart, 'days');
		var interval = instance.interval.get();

		// Track repeating events so we know how often they occur.
		// The key to this dict is a combination of courseId, weekday and start time.
		var repetitionCount = {};

		// Load events but keep only the first when they repeat on the same
		// weekday at the same time.
		var dedupedEvents = [];
		eventsFind(filter.toQuery()).forEach(function(event) {
			var repKey = event.start.getDay()+'-'+event.start.getHours()+'-'+ event.start.getMinutes()+'-';

			// If there is no courseId, we fall back to replicationId, then _id.
			if (event.courseId) {
				repKey += event.courseId;
			} else if (event.replicaOf) {
				repKey += event.replicaOf;
			} else {
				repKey += event._id;
			}

			if (repetitionCount[repKey] >= 1) {
				repetitionCount[repKey] += 1;
			} else {
				repetitionCount[repKey] = 1;

				event.repKey = repKey;
				dedupedEvents.push(event);
			}
		});

		// Because we need to find the closest separator later on we create a
		// reversed copy which is easier to search.
		var separators = instance.separators.get().slice().reverse();

		// List of intervals where events or separators are placed
		var intervals = _.reduce(separators, function(intervals, separator) {
			intervals[separator] = separator;
			return intervals;
		}, {});

		// List of days where events where found
		var days = {};

		// Map of slots where events were found. Each slot holds a list of events.
		var slots = {};

		// Count occurences of first few chars in event titles
		// This helps coloring the events so they're easier to scan.
		var kinds = {};

		// Place found events into the slots
		_.each(dedupedEvents, function(event) {
			event.repCount = repetitionCount[event.repKey];
			if (event.repCount < 2 && instance.repeatingOnly.get()) {
				// Skip
				return;
			}

			var eventStart = moment(event.start);
			var dayStart = moment(eventStart).startOf('day');

			var day = dayStart.diff(scheduleStart, 'days') % 7;
			days[day] = day;

			var minuteDiff = eventStart.diff(dayStart, 'minutes');
			var intervalStart = Math.floor(minuteDiff / interval) * interval;
			var closestSeparator = _.find(separators, function(sep) {
				return sep <= minuteDiff;
			});

			var mins = Math.max(intervalStart, closestSeparator || 0);
			intervals[mins] = mins;

			if (!slots[mins]) slots[mins] = [];
			if (!slots[mins][day]) slots[mins][day] = [];
			slots[mins][day].push(event);

			var kindId = event.title.substr(0, 5);
			if (!kinds[kindId]) kinds[kindId] = 1;
			kinds[kindId] += 1;
		});

		var numCmp = function(a, b) { return a - b; };
		instance.days.set(_.values(days).sort(numCmp));
		instance.intervals.set(_.values(intervals).sort(numCmp));
		instance.slots.set(slots);

		// Build list of most used titles (first few chars)
		var mostUsedKinds = _.sortBy(_.pairs(kinds), function(kv) { return -kv[1]; });
		var kindRank = _.object(_.map(mostUsedKinds.slice(0, 15), function(kv, rank) {
			return [kv[0], rank+1];
		}));
		instance.kindMap = function(title) {
			var kindId = title.substr(0, 5);
			if (kindRank[kindId]) return kindRank[kindId];
			return 0;
		};
	});
});

Template.frameSchedule.helpers({
	month: function() {
		var instance = Template.instance();
		return moment(instance.scheduleStart.get()).format('MMMM');
	},

	days: function() {
		var instance = Template.instance();
		var scheduleStart = instance.scheduleStart.get();
		return _.map(Template.instance().days.get(), function(day) {
			return moment(scheduleStart).add(day, 'days').format('dddd');
		});
	},

	intervals: function() {
		var slots = Template.instance().slots.get();

		return _.map(Template.instance().intervals.get(), function(mins) {
			return {
				interval: moment().hour(0).minute(mins).format('LT'),
				slots: _.map(Template.instance().days.get(), function(day) {
					return slots[mins] && slots[mins][day];
				})
			};
		});
	},

	type: function() {
		return Template.instance().kindMap(this.title);
	},

	customStartTime: function(interval) {
		var event = this;
		var startTime = moment(event.start).format('LT');
		return (interval !== startTime) ? startTime : false;
	},

	single: function() {
		return this.repCount < 2;
	},

	showDate: function() {
		// The date is shown if an event has now repetitions...
		if (this.repCount < 2) return true;

		// ... or if it doesn't occur this week.
		var thisWeek = moment().startOf('week');
		var eventWeek = moment(this.start).startOf('week');
		return eventWeek.isAfter(thisWeek);
	}
});
<|endoftext|>