<commit_before>var gulp        = require('gulp');
var $           = require('gulp-load-plugins')();
var browserSync = require('browser-sync');
var cache       = require('gulp-cache');
var cachebust   = require('gulp-cache-bust');
var concat      = require('gulp-concat');
var cp          = require('child_process');
var del         = require('del');
var es          = require('event-stream');
var footer      = require('gulp-footer');
var header      = require('gulp-header');
var minifyCss   = require('gulp-minify-css');
var pagespeed   = require('psi');
var pkg         = require('./package.json');
var prefix      = require('gulp-autoprefixer');
var rename      = require('gulp-rename');
var runSequence = require('run-sequence');
var sass        = require('gulp-sass');
var server      = require('gulp-develop-server');
var shell       = require('gulp-shell');
var uglify      = require('gulp-uglify');
var del          = require('del');

var bustingCache = false;

var messages = {
  jekyllBuild: 'Running: $ jekyll build'
};

var AUTOPREFIXER_BROWSERS = [
  'ie >= 10',
  'ff >= 45',
  'chrome >= 54',
  'safari >= 9',
  'opera >= 23',
  'ios >= 9',
  'android >= 4.4'
];
var closureStart =
  '/*!\n' +
  ' * Ionic IO\n' +
  ' * Copyright ' + new Date().getYear() + ' Drifty Co. http://drifty.com/\n' +
  ' */\n' +
  '(function() {\n';
var closureEnd = '\n})();\n';
var version = pkg.version;

function bustCache() {

  function cacheBust(path, fileName) {
    return gulp.src(path + fileName)
      .pipe(cachebust({
        basePath: 'content'
      }))
      .pipe(gulp.dest('./' + path))
  }

  var bustArray = function() {
    return [
      cacheBust('content/_includes/', 'head_includes.html'),
      cacheBust('content/_includes/v2_fluid/','head.html'),
      cacheBust('content/_includes/v2_fluid/','footer_tags.html')
    ]
  }

  return es.concat(bustArray());
}

function bustCacheAndReload(done) {

  bustCache().on('end', function() {
    browserSync.reload();
    done();
    // apply the template change in the background
    // gulp.start('jekyll-build.incremental');
  });
}

gulp.task('styles:v2', function() {
  // For best performance, don't add Sass partials to `gulp.src`
  return gulp.src('assets/scss/styles.scss')
    // .pipe($.sourcemaps.init())
    .pipe(sass({
      precision: 10,
      onError: console.error.bind(console, 'Sass error:')
    }))
    .pipe($.autoprefixer({browsers: AUTOPREFIXER_BROWSERS}))
    //
    // .pipe($.sourcemaps.write())
    .pipe(gulp.dest('content/css/'))
    .pipe(gulp.dest('_site/css/'))

    // .pipe($.sourcemaps.write('./css/'))
    // Concatenate and minify styles
    .pipe(minifyCss({
      keepSpecialComments: 0
    }))
    .pipe(rename({extname: '.min.css'}))
    .pipe(gulp.dest('content/css/'))
    .pipe(gulp.dest('_site/css/'))
    .pipe($.size({title: 'styles'}));
});

gulp.task('styles:v1', function(done) {
  return gulp.src('content/scss/**/*.scss')
    .pipe(sass({onError: browserSync.notify}))
    .pipe($.autoprefixer({browsers: AUTOPREFIXER_BROWSERS}))
    .pipe(gulp.dest('content/css/'))
    .pipe(gulp.dest('_site/css/'))
    .pipe(minifyCss({
      keepSpecialComments: 0
    }))
    .pipe(rename({extname: '.min.css'}))
    .pipe(gulp.dest('content/css/'))
    .pipe(gulp.dest('_site/css/'));
});

// Optimize images
gulp.task('images', function() {
  return gulp.src('assets/img/**/*')
    .pipe(cache($.imagemin({
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('content/img'))
    .pipe(gulp.dest('_site/img'))
    .pipe($.size({title: 'images'}));
});

// compress and concat JS
gulp.task('js', function() {
  return gulp.src(['assets/js/**/*.js'])
    .pipe(concat('ionic-site.js'))
    .pipe(header(closureStart))
    .pipe(footer(closureEnd))
    .pipe(gulp.dest('content/js'))
    .pipe(gulp.dest('_site/js'))
    .pipe(uglify())
    .pipe(rename({extname: '.min.js'}))
    .pipe(gulp.dest('content/js'))
    .pipe(gulp.dest('_site/js'))
    .pipe($.size({title: 'js'}));
});

/**
 * Build the Jekyll Site
 */
gulp.task('jekyll-build', [], function(done) {
  browserSync.notify(messages.jekyllBuild);
  return cp.spawn('jekyll',
                  ['build', '-I', '--config', '_config_development.yml'],
                  {stdio: 'inherit'})
           .on('close', function(){
             done()
           })
           .on('error', function( err ){ throw err });
});

gulp.task('jekyll-build.clean', [], function(done) {
  browserSync.notify(messages.jekyllBuild);
  return cp.spawn('jekyll',
                  ['build', '--config', '_config.yml'],
                  {stdio: 'inherit'})
           .on('close', done)
           .on('error', function( err ){ throw err });
});

/**
 * Run Generate linkchecker page
 */
gulp.task('linkchecker', ['build'],
  shell.task('_scripts/linkchecker.sh',{verbose: true})
);

/**
 * Rebuild Jekyll & do page reload
 */
gulp.task('jekyll-rebuild', ['jekyll-build'], function() {
  browserSync.reload();
});

gulp.task('server-listen', function() {
  return server.listen({ 'path': './server.js', 'execArgv': ['--harmony'] },
  function(error) {
    if (!error) {
      browserSync({ 'proxy': 'http://localhost:3000', 'port': 3003 });
    }
  });
});

/**
 * Wait for jekyll-build, then launch the Server
 */
gulp.task('server', function() {
  return runSequence('build', 'server-listen');
});

gulp.task('server:server', function() {
  server.restart(function(err) {
    if (!err) {
      browserSync.reload();
    }
  });
});

gulp.task('server:ionicons', ['ionicons'], bustCacheAndReload);
gulp.task('server:stylesv1', ['styles:v1'], bustCacheAndReload);
gulp.task('server:stylesv2', ['styles:v2'], bustCacheAndReload);
gulp.task('server:js', ['js'], bustCacheAndReload);

gulp.task('watch', ['server'], function() {
  gulp.watch(['server.js','server/**/*'], ['server:server']);
  gulp.watch('content/scss/**.scss', ['server:stylesv1']);
  gulp.watch(['assets/scss/**/*.scss'], ['server:stylesv2']);
  gulp.watch(['assets/img/**/*.{jpg,png,gif}'], ['images']);
  gulp.watch(['assets/js/**/*.js', 'submit-issue/*/*.js'], ['server:js']);
  gulp.watch(['content/**/*.{md,html}','content/docs/**/*.{js,css,json}'
  ], ['jekyll-rebuild']);
});

gulp.task('watch.min', ['server'], function() {
  gulp.watch(['assets/js/**/*.js'], ['server:js']);
  gulp.watch(['assets/scss/**/*.scss'], ['server:stylesv2']);
  gulp.watch(['content/_layouts/*/*','content/_includes/**/*',
              'content/docs/v2/**/*.{md,html}'], ['server:jekyll']);

});
gulp.task('cli-docs', function() {
  try {
    var fs = require('fs');
    var cliTasks = JSON.stringify(require('../ionic-cli/lib/tasks/cliTasks'));
    fs.writeFileSync('_data/cliData.json', cliTasks);
  } catch (e) {
    console.error('Cannot find module cliTasks, please make sure the ionic-' +
                  'cli repo is cloned locally. ionic-site and ionic-cli ' +
                  'should be sibling directories.');
  }
});

gulp.task('docs.index', function() {
  var lunr = require('lunr');
  var gutil = require('gulp-util');
  var es = require('event-stream');
  var yaml = require('js-yaml');
  var htmlparser = require('htmlparser2');
  var mkdirp = require('mkdirp');
  var fs = require('fs');

  var idx = lunr(function() {
    this.field('path');
    this.field('title', {boost: 10});
    this.field('body');
    this.ref('id');
  });
  var ref = {};
  var refId = 0;

  function addToIndex(path, title, layout, body) {
    // Add the data to the indexer and ref object
    idx.add({'path': path, 'body': body, 'title': title, id: refId});
    ref[refId] = {'p': path, 't': title, 'l': layout};
    refId++;
  }

  var docPath = 'content/docs/v2';
  gutil.log('Reading docs from', gutil.colors.cyan(docPath));

  return gulp.src([
    docPath + '/{api,cli,components,faq,getting-started,native,resources,theming,utils}/**/*.{md,html,markdown}',
    docPath + '/index.md',
  ])
  .pipe(es.map(function(file, callback) {
    //docs for gulp file objects: https://github.com/wearefractal/vinyl
    var contents = file.contents.toString(); //was buffer

    // Grab relative path from ionic-site root
    var relpath = file.path.replace(RegExp('^.*?' + docPath.replace('/content/docs/v2', '') + '/'), '');

    // Read out the yaml portion of the Jekyll file
    var yamlStartIndex = contents.indexOf('---');

    if (yamlStartIndex === -1) {
      return callback();
    }

    // read Jekyll's page yaml variables at the top of the file
    var yamlEndIndex = contents.indexOf('---', yamlStartIndex+3); //starting from start
    var yamlRaw = contents.substring(yamlStartIndex+3, yamlEndIndex);

    var pageData =  yaml.safeLoad(yamlRaw);
    if(!pageData.title || !pageData.layout) {
      return callback();
    }

    // manually set to not be searchable, or for a blog post, manually set to be searchable
    if(pageData.searchable === false || (pageData.layout == 'post' && pageData.searchable !== true)) {
      return callback();
    }

    // clean up some content so code variables are searchable too
    contents = contents.substring(yamlEndIndex+3);
    contents = contents.replace(//gi, '');
    contents = contents.replace(/<\/code>/gi, '');
    contents = contents.replace(/</gi, '');
    contents = contents.replace(/><\/code>/gi, '');
    contents = contents.replace(/`</gi, '');
    contents = contents.replace(/>`/gi, '');

    // create a clean path to the URL
    var path = '/' + relpath.replace('index.md', '')
                            .replace('index.html', '')
                            .replace('.md', '.html')
                            .replace('.markdown', '.html');
    if(pageData.layout == 'post') {
      path = '/blog/' + path.substring(19).replace('.html', '/');
    }

    var parser;
    if(pageData.search_sections === true) {
      // each section within the content should be its own search result
      var section = { body: '', title: '' };
      var isTitleOpen = false;

      parser = new htmlparser.Parser({
        ontext: function(text){
          if(isTitleOpen) {
            section.title += text; // get the title of this section
          } else {
            section.body += text.replace(/{%.*%}/, '', 'g'); // Ignore any Jekyll expressions
          }
        },
        onopentag: function(name, attrs) {
          if(name == 'section' && attrs.id) {
            // start building new section data
            section = { body: '', path: path + '#' + attrs.id, title: '' };
          } else if( (name == 'h1' || name == 'h2' || name == 'h3') && attrs.class == 'title') {
            isTitleOpen = true; // the next text will be this sections title
          }
        },
        onclosetag: function(name) {
          if(name == 'section') {
            // section closed, index this section then clear it out
            addToIndex(section.path, section.title, pageData.layout, section.body);
            section = { body: '', title: '' };
          } else if( (name == 'h1' || name == 'h2' || name == 'h3') && isTitleOpen) {
            isTitleOpen = false;
          }
        }
      });
      parser.write(contents);
      parser.end();

    } else {
      // index the entire page
      var body = '';
      parser = new htmlparser.Parser({
        ontext: function(text){
          body += text.replace(/{%.*%}/, '', 'g'); // Ignore any Jekyll expressions
        }
      });
      parser.write(contents);
      parser.end();

      addToIndex(path, pageData.title, pageData.layout, body);
    }

    callback();

  })).on('end', function() {
    // Write out as one json file
    mkdirp.sync(docPath + '/data');
    fs.writeFileSync(
      docPath + '/data/index.json',
      JSON.stringify({'ref': ref, 'index': idx.toJSON()})
    );
  });
});

gulp.task('ionicons', function() {
  gulp.src('node_modules/ionicons/dist/data/ionicons.json')
    .pipe(rename('site_data.json'))
    .pipe(gulp.dest('_site/docs/v2/resources/ionicons/'))
    .pipe(gulp.dest('content/docs/v2/resources/ionicons/'));

  gulp.src('node_modules/ionicons/dist/data/mode-icons.json')
    .pipe(gulp.dest('_site/docs/v2/resources/ionicons/data/'))
    .pipe(gulp.dest('content/docs/v2/resources/ionicons/data/'));

  gulp.src('node_modules/ionicons/dist/data/logo-icons.json')
    .pipe(rename('generic-icons.json'))
    .pipe(gulp.dest('_site/docs/v2/resources/ionicons/data/'))
    .pipe(gulp.dest('content/docs/v2/resources/ionicons/data/'));

  gulp.src('node_modules/ionicons/dist/css/ionicons.min.css')
    .pipe(gulp.dest('_site/css/v2-demos/ionicons/'))
    .pipe(gulp.dest('content/css/v2-demos/ionicons/'));

  return gulp.src('node_modules/ionicons/dist/fonts/*{eot,svg,ttf,woff}')
    .pipe(gulp.dest('_site/css/v2-demos/fonts/'))
    .pipe(gulp.dest('content/css/v2-demos/fonts/'));
});

gulp.task('build', ['build-prep'], function(done) {
  runSequence('jekyll-build', function() {
    done();
  })
});

gulp.task('build.clean', ['build-prep'], function(done) {
  runSequence('jekyll-build.clean', function() {
    done();
  })
});

gulp.task('slug.prep', function () {
  return del(['assets', 'content']);
});

gulp.task('build-prep', ['ionicons', 'cli-docs', 'styles:v1', 'styles:v2', 'images', 'js', 'docs.index'], bustCache);

gulp.task('default', ['build']);
<commit_msg>speeding up watch times<commit_after>var gulp        = require('gulp');
var $           = require('gulp-load-plugins')();
var browserSync = require('browser-sync');
var cache       = require('gulp-cache');
var cachebust   = require('gulp-cache-bust');
var concat      = require('gulp-concat');
var cp          = require('child_process');
var del         = require('del');
var es          = require('event-stream');
var footer      = require('gulp-footer');
var header      = require('gulp-header');
var minifyCss   = require('gulp-minify-css');
var pagespeed   = require('psi');
var pkg         = require('./package.json');
var prefix      = require('gulp-autoprefixer');
var rename      = require('gulp-rename');
var runSequence = require('run-sequence');
var sass        = require('gulp-sass');
var server      = require('gulp-develop-server');
var shell       = require('gulp-shell');
var uglify      = require('gulp-uglify');
var del          = require('del');

var bustingCache = false;

var messages = {
  jekyllBuild: 'Running: $ jekyll build'
};

var AUTOPREFIXER_BROWSERS = [
  'ie >= 10',
  'ff >= 45',
  'chrome >= 54',
  'safari >= 9',
  'opera >= 23',
  'ios >= 9',
  'android >= 4.4'
];
var closureStart =
  '/*!\n' +
  ' * Ionic IO\n' +
  ' * Copyright ' + new Date().getYear() + ' Drifty Co. http://drifty.com/\n' +
  ' */\n' +
  '(function() {\n';
var closureEnd = '\n})();\n';
var version = pkg.version;

function bustCache() {

  function cacheBust(path, fileName) {
    return gulp.src(path + fileName)
      .pipe(cachebust({
        basePath: 'content'
      }))
      .pipe(gulp.dest('./' + path))
  }

  var bustArray = function() {
    return [
      cacheBust('content/_includes/', 'head_includes.html'),
      cacheBust('content/_includes/v2_fluid/','head.html'),
      cacheBust('content/_includes/v2_fluid/','footer_tags.html')
    ]
  }

  return es.concat(bustArray());
}

function bustCacheAndReload(done) {

  bustCache().on('end', function() {
    browserSync.reload();
    done();
    // apply the template change in the background
    // gulp.start('jekyll-build.incremental');
  });
}

gulp.task('styles:v2', function() {
  // For best performance, don't add Sass partials to `gulp.src`
  return gulp.src('assets/scss/styles.scss')
    // .pipe($.sourcemaps.init())
    .pipe(sass({
      precision: 10,
      onError: console.error.bind(console, 'Sass error:')
    }))
    .pipe($.autoprefixer({browsers: AUTOPREFIXER_BROWSERS}))
    //
    // .pipe($.sourcemaps.write())
    .pipe(gulp.dest('content/css/'))
    .pipe(gulp.dest('_site/css/'))

    // .pipe($.sourcemaps.write('./css/'))
    // Concatenate and minify styles
    .pipe(minifyCss({
      keepSpecialComments: 0
    }))
    .pipe(rename({extname: '.min.css'}))
    .pipe(gulp.dest('content/css/'))
    .pipe(gulp.dest('_site/css/'))
    .pipe($.size({title: 'styles'}));
});

gulp.task('styles:v1', function() {
  return gulp.src('content/scss/**/*.scss')
    .pipe(sass({onError: browserSync.notify}))
    .pipe($.autoprefixer({browsers: AUTOPREFIXER_BROWSERS}))
    .pipe(gulp.dest('content/css/'))
    .pipe(gulp.dest('_site/css/'))
    .pipe(minifyCss({
      keepSpecialComments: 0
    }))
    .pipe(rename({extname: '.min.css'}))
    .pipe(gulp.dest('content/css/'))
    .pipe(gulp.dest('_site/css/'));
});

// Optimize images
gulp.task('images', function() {
  return gulp.src('assets/img/**/*')
    .pipe(cache($.imagemin({
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('content/img'))
    .pipe(gulp.dest('_site/img'))
    .pipe($.size({title: 'images'}));
});

// compress and concat JS
gulp.task('js', function() {
  return gulp.src(['assets/js/**/*.js'])
    .pipe(concat('ionic-site.js'))
    .pipe(header(closureStart))
    .pipe(footer(closureEnd))
    .pipe(gulp.dest('content/js'))
    .pipe(gulp.dest('_site/js'))
    .pipe(uglify())
    .pipe(rename({extname: '.min.js'}))
    .pipe(gulp.dest('content/js'))
    .pipe(gulp.dest('_site/js'))
    .pipe($.size({title: 'js'}));
});

/**
 * Build the Jekyll Site
 */
gulp.task('jekyll-build', [], function(done) {
  browserSync.notify(messages.jekyllBuild);
  cp.spawn('jekyll',
                  ['build', '-I', '--config', '_config_development.yml'],
                  {stdio: 'inherit'})
           .on('close', function(){
             done()
           })
           .on('error', function( err ){ throw err });
});

gulp.task('jekyll-build.clean', [], function(done) {
  browserSync.notify(messages.jekyllBuild);
  cp.spawn('jekyll',
                  ['build', '--config', '_config.yml'],
                  {stdio: 'inherit'})
           .on('close', done)
           .on('error', function( err ){ throw err });
});

/**
 * Run Generate linkchecker page
 */
gulp.task('linkchecker', ['build'],
  shell.task('_scripts/linkchecker.sh',{verbose: true})
);

/**
 * Rebuild Jekyll & do page reload
 */
gulp.task('jekyll-rebuild', ['jekyll-build'], function() {
  browserSync.reload();
});

gulp.task('server-listen', function() {
  return server.listen({ 'path': './server.js', 'execArgv': ['--harmony'] },
  function(error) {
    if (!error) {
      browserSync({ 'proxy': 'http://localhost:3000', 'port': 3003 });
    }
  });
});

/**
 * Wait for jekyll-build, then launch the Server
 */
gulp.task('server', ['build'], function() {
  return runSequence('server-listen');
});

gulp.task('server:server', function() {
  server.restart(function(err) {
    if (!err) {
      browserSync.reload();
    }
  });
});

gulp.task('server:ionicons', ['ionicons'], bustCacheAndReload);
gulp.task('server:stylesv1', ['styles:v1'], bustCacheAndReload);
gulp.task('server:stylesv2', ['styles:v2'], bustCacheAndReload);
gulp.task('server:js', ['js'], bustCacheAndReload);

gulp.task('watch', ['server'], function() {
  gulp.watch(['server.js','server/**/*'], ['server:server']);
  gulp.watch('content/scss/**.scss', ['server:stylesv1']);
  gulp.watch(['assets/scss/**/*.scss'], ['server:stylesv2']);
  gulp.watch(['assets/img/**/*.{jpg,png,gif}'], ['images']);
  gulp.watch(['assets/js/**/*.js', 'submit-issue/*/*.js'], ['server:js']);
  gulp.watch(['content/**/*.{md,html}','content/docs/**/*.{js,css,json}'
  ], ['jekyll-rebuild']);
});

gulp.task('watch.min', ['server'], function() {
  gulp.watch(['assets/js/**/*.js'], ['server:js']);
  gulp.watch(['assets/scss/**/*.scss'], ['server:stylesv2']);
  gulp.watch(['content/_layouts/*/*','content/_includes/**/*',
              'content/docs/v2/**/*.{md,html}'], ['server:jekyll']);

});
gulp.task('cli-docs', function() {
  try {
    var fs = require('fs');
    var cliTasks = JSON.stringify(require('../ionic-cli/lib/tasks/cliTasks'));
    fs.writeFileSync('_data/cliData.json', cliTasks);
  } catch (e) {
    console.error('Cannot find module cliTasks, please make sure the ionic-' +
                  'cli repo is cloned locally. ionic-site and ionic-cli ' +
                  'should be sibling directories.');
  }
});

gulp.task('docs.index', function() {
  var lunr = require('lunr');
  var gutil = require('gulp-util');
  var es = require('event-stream');
  var yaml = require('js-yaml');
  var htmlparser = require('htmlparser2');
  var mkdirp = require('mkdirp');
  var fs = require('fs');

  var idx = lunr(function() {
    this.field('path');
    this.field('title', {boost: 10});
    this.field('body');
    this.ref('id');
  });
  var ref = {};
  var refId = 0;

  function addToIndex(path, title, layout, body) {
    // Add the data to the indexer and ref object
    idx.add({'path': path, 'body': body, 'title': title, id: refId});
    ref[refId] = {'p': path, 't': title, 'l': layout};
    refId++;
  }

  var docPath = 'content/docs/v2';
  gutil.log('Reading docs from', gutil.colors.cyan(docPath));

  return gulp.src([
    docPath + '/{api,cli,components,faq,getting-started,native,resources,theming,utils}/**/*.{md,html,markdown}',
    docPath + '/index.md',
  ])
  .pipe(es.map(function(file, callback) {
    //docs for gulp file objects: https://github.com/wearefractal/vinyl
    var contents = file.contents.toString(); //was buffer

    // Grab relative path from ionic-site root
    var relpath = file.path.replace(RegExp('^.*?' + docPath.replace('/content/docs/v2', '') + '/'), '');

    // Read out the yaml portion of the Jekyll file
    var yamlStartIndex = contents.indexOf('---');

    if (yamlStartIndex === -1) {
      return callback();
    }

    // read Jekyll's page yaml variables at the top of the file
    var yamlEndIndex = contents.indexOf('---', yamlStartIndex+3); //starting from start
    var yamlRaw = contents.substring(yamlStartIndex+3, yamlEndIndex);

    var pageData =  yaml.safeLoad(yamlRaw);
    if(!pageData.title || !pageData.layout) {
      return callback();
    }

    // manually set to not be searchable, or for a blog post, manually set to be searchable
    if(pageData.searchable === false || (pageData.layout == 'post' && pageData.searchable !== true)) {
      return callback();
    }

    // clean up some content so code variables are searchable too
    contents = contents.substring(yamlEndIndex+3);
    contents = contents.replace(//gi, '');
    contents = contents.replace(/<\/code>/gi, '');
    contents = contents.replace(/</gi, '');
    contents = contents.replace(/><\/code>/gi, '');
    contents = contents.replace(/`</gi, '');
    contents = contents.replace(/>`/gi, '');

    // create a clean path to the URL
    var path = '/' + relpath.replace('index.md', '')
                            .replace('index.html', '')
                            .replace('.md', '.html')
                            .replace('.markdown', '.html');
    if(pageData.layout == 'post') {
      path = '/blog/' + path.substring(19).replace('.html', '/');
    }

    var parser;
    if(pageData.search_sections === true) {
      // each section within the content should be its own search result
      var section = { body: '', title: '' };
      var isTitleOpen = false;

      parser = new htmlparser.Parser({
        ontext: function(text){
          if(isTitleOpen) {
            section.title += text; // get the title of this section
          } else {
            section.body += text.replace(/{%.*%}/, '', 'g'); // Ignore any Jekyll expressions
          }
        },
        onopentag: function(name, attrs) {
          if(name == 'section' && attrs.id) {
            // start building new section data
            section = { body: '', path: path + '#' + attrs.id, title: '' };
          } else if( (name == 'h1' || name == 'h2' || name == 'h3') && attrs.class == 'title') {
            isTitleOpen = true; // the next text will be this sections title
          }
        },
        onclosetag: function(name) {
          if(name == 'section') {
            // section closed, index this section then clear it out
            addToIndex(section.path, section.title, pageData.layout, section.body);
            section = { body: '', title: '' };
          } else if( (name == 'h1' || name == 'h2' || name == 'h3') && isTitleOpen) {
            isTitleOpen = false;
          }
        }
      });
      parser.write(contents);
      parser.end();

    } else {
      // index the entire page
      var body = '';
      parser = new htmlparser.Parser({
        ontext: function(text){
          body += text.replace(/{%.*%}/, '', 'g'); // Ignore any Jekyll expressions
        }
      });
      parser.write(contents);
      parser.end();

      addToIndex(path, pageData.title, pageData.layout, body);
    }

    callback();

  })).on('end', function() {
    // Write out as one json file
    mkdirp.sync(docPath + '/data');
    fs.writeFileSync(
      docPath + '/data/index.json',
      JSON.stringify({'ref': ref, 'index': idx.toJSON()})
    );
  });
});

gulp.task('ionicons', function() {
  gulp.src('node_modules/ionicons/dist/data/ionicons.json')
    .pipe(rename('site_data.json'))
    .pipe(gulp.dest('_site/docs/v2/resources/ionicons/'))
    .pipe(gulp.dest('content/docs/v2/resources/ionicons/'));

  gulp.src('node_modules/ionicons/dist/data/mode-icons.json')
    .pipe(gulp.dest('_site/docs/v2/resources/ionicons/data/'))
    .pipe(gulp.dest('content/docs/v2/resources/ionicons/data/'));

  gulp.src('node_modules/ionicons/dist/data/logo-icons.json')
    .pipe(rename('generic-icons.json'))
    .pipe(gulp.dest('_site/docs/v2/resources/ionicons/data/'))
    .pipe(gulp.dest('content/docs/v2/resources/ionicons/data/'));

  gulp.src('node_modules/ionicons/dist/css/ionicons.min.css')
    .pipe(gulp.dest('_site/css/v2-demos/ionicons/'))
    .pipe(gulp.dest('content/css/v2-demos/ionicons/'));

  return gulp.src('node_modules/ionicons/dist/fonts/*{eot,svg,ttf,woff}')
    .pipe(gulp.dest('_site/css/v2-demos/fonts/'))
    .pipe(gulp.dest('content/css/v2-demos/fonts/'));
});

gulp.task('build', ['build-prep'], function(done) {
  runSequence('jekyll-build', function() {
    done();
  })
});

gulp.task('build.clean', ['build-prep'], function(done) {
  runSequence('jekyll-build.clean', function() {
    done();
  })
});

gulp.task('slug.prep', function () {
  return del(['assets', 'content']);
});

gulp.task('build-prep', ['ionicons', 'cli-docs', 'styles:v1', 'styles:v2', 'images', 'js', 'docs.index'], bustCache);

gulp.task('default', ['build']);
<|endoftext|>


<commit_before>var config = require('./../../config');
var mongojs = require("mongojs");
var db = mongojs.connect(config.security.dbName, [ config.security.usersCollection ]);
var User = {
    byId: function(id,done){
        db.users.findOne( { '_id': mongojs.ObjectId(id) }, function(err, user){
            done(user)
        });
    },

    byEmail: function(email,done){
        db.users.findOne( { email: email }, function(err, user){
            done(user)
        });
    },

    all: function(query, done){
        db.users.find( query, function(err, users){
            done(users)
        });
    },

    createOrUpdate: function(params, done){
        var id = params['_id'];
        delete params['_id'];
        db.users.findAndModify( { query: { "_id": id }, update: { $set: params } , new:true, upsert: true  }, function(err, user){
            done(user);
        });
    },

    delete: function(id,done){
        db.users.remove( { '_id': mongojs.ObjectId(id) }, function(err){
            done()
        });
    }
};
module.exports = User;<commit_msg>fix user create or update<commit_after>var config = require('./../../config');
var mongojs = require("mongojs");
var db = mongojs.connect(config.security.dbName, [ config.security.usersCollection ]);
var User = {
    byId: function(id,done){
        db.users.findOne( { '_id': mongojs.ObjectId(id) }, function(err, user){
            done(user)
        });
    },

    byEmail: function(email,done){
        db.users.findOne( { email: email }, function(err, user){
            done(user)
        });
    },

    all: function(query, done){
        db.users.find( query, function(err, users){
            done(users)
        });
    },

    createOrUpdate: function(params, done){
        var id = params['_id'];
        delete params['_id'];
        db.users.findAndModify( { query: { "_id": mongojs.ObjectId(id) }, update: { $set: params } , new:true, upsert: true  }, function(err, user){
            done(user);
        });
    },

    delete: function(id,done){
        db.users.remove( { '_id': mongojs.ObjectId(id) }, function(err){
            done()
        });
    }
};
module.exports = User;<|endoftext|>


<commit_before>const async = require('async');
const moment = require('moment');
const Loggly = require('loggly');
const loggingTools = require('auth0-log-extension-tools');
const config = require('../lib/config');
const logger = require('../lib/logger');

module.exports = (storage) =>
  (req, res, next) => {
    const wtBody = (req.webtaskContext && req.webtaskContext.body) || req.body || {};
    const wtHead = (req.webtaskContext && req.webtaskContext.headers) || {};
    const isCron = (wtBody.schedule && wtBody.state === 'active') || (wtHead.referer === `${config('AUTH0_MANAGE_URL')}/` && wtHead['if-none-match']);

    if (!isCron) {
      return next();
    }

    const loggly = Loggly.createClient({
      token: config('LOGGLY_CUSTOMER_TOKEN'),
      subdomain: config('LOGGLY_SUBDOMAIN') || '-',
      tags: ['auth0']
    });

    const onLogsReceived = (logs, callback) => {
      if (!logs || !logs.length) {
        return callback();
      }

      logger.info(`Sending ${logs.length} logs to Loggly.`);

      loggly.log(logs, (err) => {
        if (err) {
          logger.info('Error sending logs to Loggly', err);
          return callback(err);
        }

        logger.info('Upload complete.');

        return callback();
      });
    };

    const slack = new loggingTools.reporters.SlackReporter({
      hook: config('SLACK_INCOMING_WEBHOOK_URL'),
      username: 'auth0-logs-to-loggly',
      title: 'Logs To Loggly'
    });

    const options = {
      domain: config('AUTH0_DOMAIN'),
      clientId: config('AUTH0_CLIENT_ID'),
      clientSecret: config('AUTH0_CLIENT_SECRET'),
      batchSize: config('BATCH_SIZE'),
      startFrom: config('START_FROM'),
      logLevel: config('LOG_LEVEL'),
      logTypes: config('LOG_TYPES')
    };

    if (!options.batchSize || options.batchSize > 100) {
      options.batchSize = 100;
    }

    const auth0logger = new loggingTools.LogsProcessor(storage, options);

    const sendDailyReport = (lastReportDate) => {
      const current = new Date();

      const end = current.getTime();
      const start = end - 86400000;
      auth0logger.getReport(start, end)
        .then(report => slack.send(report, report.checkpoint))
        .then(() => storage.read())
        .then((data) => {
          data.lastReportDate = lastReportDate;
          return storage.write(data);
        });
    };

    const checkReportTime = () => {
      storage.read()
        .then((data) => {
          const now = moment().format('DD-MM-YYYY');
          const reportTime = config('DAILY_REPORT_TIME') || 16;

          if (data.lastReportDate !== now && new Date().getHours() >= reportTime) {
            sendDailyReport(now);
          }
        })
    };

    return auth0logger
      .run(onLogsReceived)
      .then(result => {
        if (result && result.status && result.status.error) {
          slack.send(result.status, result.checkpoint);
        } else if (config('SLACK_SEND_SUCCESS') === true || config('SLACK_SEND_SUCCESS') === 'true') {
          slack.send(result.status, result.checkpoint);
        }
        checkReportTime();
        res.json(result);
      })
      .catch(err => {
        slack.send({ error: err, logsProcessed: 0 }, null);
        checkReportTime();
        next(err);
      });
  };
<commit_msg>filter fix<commit_after>const async = require('async');
const moment = require('moment');
const Loggly = require('loggly');
const loggingTools = require('auth0-log-extension-tools');
const config = require('../lib/config');
const logger = require('../lib/logger');

module.exports = (storage) =>
  (req, res, next) => {
    const wtBody = (req.webtaskContext && req.webtaskContext.body) || req.body || {};
    const wtHead = (req.webtaskContext && req.webtaskContext.headers) || {};
    const isCron = (wtBody.schedule && wtBody.state === 'active') || (wtHead.referer === `${config('AUTH0_MANAGE_URL')}/` && wtHead['if-none-match']);

    if (!isCron) {
      return next();
    }

    const loggly = Loggly.createClient({
      token: config('LOGGLY_CUSTOMER_TOKEN'),
      subdomain: config('LOGGLY_SUBDOMAIN') || '-',
      tags: ['auth0']
    });

    const onLogsReceived = (logs, callback) => {
      if (!logs || !logs.length) {
        return callback();
      }

      logger.info(`Sending ${logs.length} logs to Loggly.`);

      loggly.log(logs, (err) => {
        if (err) {
          logger.info('Error sending logs to Loggly', err);
          return callback(err);
        }

        logger.info('Upload complete.');

        return callback();
      });
    };

    const slack = new loggingTools.reporters.SlackReporter({
      hook: config('SLACK_INCOMING_WEBHOOK_URL'),
      username: 'auth0-logs-to-loggly',
      title: 'Logs To Loggly'
    });

    const options = {
      domain: config('AUTH0_DOMAIN'),
      clientId: config('AUTH0_CLIENT_ID'),
      clientSecret: config('AUTH0_CLIENT_SECRET'),
      batchSize: config('BATCH_SIZE'),
      startFrom: config('START_FROM'),
      logLevel: config('LOG_LEVEL'),
      logTypes: config('LOG_TYPES')
    };

    if (!options.batchSize || options.batchSize > 100) {
      options.batchSize = 100;
    }

    if (options.logTypes && !Array.isArray(options.logTypes)) {
      options.logTypes = options.logTypes.replace(/\s/g, '').split(',');
    }

    const auth0logger = new loggingTools.LogsProcessor(storage, options);

    const sendDailyReport = (lastReportDate) => {
      const current = new Date();

      const end = current.getTime();
      const start = end - 86400000;
      auth0logger.getReport(start, end)
        .then(report => slack.send(report, report.checkpoint))
        .then(() => storage.read())
        .then((data) => {
          data.lastReportDate = lastReportDate;
          return storage.write(data);
        });
    };

    const checkReportTime = () => {
      storage.read()
        .then((data) => {
          const now = moment().format('DD-MM-YYYY');
          const reportTime = config('DAILY_REPORT_TIME') || 16;

          if (data.lastReportDate !== now && new Date().getHours() >= reportTime) {
            sendDailyReport(now);
          }
        })
    };

    return auth0logger
      .run(onLogsReceived)
      .then(result => {
        if (result && result.status && result.status.error) {
          slack.send(result.status, result.checkpoint);
        } else if (config('SLACK_SEND_SUCCESS') === true || config('SLACK_SEND_SUCCESS') === 'true') {
          slack.send(result.status, result.checkpoint);
        }
        checkReportTime();
        res.json(result);
      })
      .catch(err => {
        slack.send({ error: err, logsProcessed: 0 }, null);
        checkReportTime();
        next(err);
      });
  };
<|endoftext|>


<commit_before>/*
 * MelonJS Game Engine
 * Copyright (C) 2011 - 2015, Olivier Biot, Jason Oster, Aaron McLeod
 * http://www.melonjs.org
 *
 * Font / Bitmap font
 *
 * ASCII Table
 * http://www.asciitable.com/
 * [ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz]
 *
 * -> first char " " 32d (0x20);
 */
(function () {
    /**
     * a generic system font object.
     * @class
     * @extends me.Renderable
     * @memberOf me
     * @constructor
     * @param {String} font a CSS font name
     * @param {Number|String} size size, or size + suffix (px, em, pt)
     * @param {me.Color|String} fillStyle a CSS color value
     * @param {String} [textAlign="left"] horizontal alignment
     */
    me.Font = me.Renderable.extend(
    /** @scope me.Font.prototype */ {

        /** @ignore */
        init : function (font, size, fillStyle, textAlign) {
            // private font properties
            /** @ignore */
            this.fontSize = new me.Vector2d();

            /**
             * defines the color used to draw the font.

             * @public
             * @type me.Color
             * @default black
             * @name me.Font#fillStyle
             */
            this.fillStyle = new me.Color().copy(fillStyle);

            /**
             * defines the color used to draw the font stroke.

             * @public
             * @type me.Color
             * @default black
             * @name me.Font#strokeStyle
             */
            this.strokeStyle = new me.Color(0, 0, 0);

            /**
             * sets the current line width, in pixels, when drawing stroke
             * @public
             * @type Number
             * @default 1
             * @name me.Font#lineWidth
             */
            this.lineWidth = 1;

            /**
             * Set the default text alignment (or justification),

             * possible values are "left", "right", and "center".

             * @public
             * @type String
             * @default "left"
             * @name me.Font#textAlign
             */
            this.textAlign = textAlign || "left";

            /**
             * Set the text baseline (e.g. the Y-coordinate for the draw operation),

             * possible values are "top", "hanging, "middle, "alphabetic, "ideographic, "bottom"

             * @public
             * @type String
             * @default "top"
             * @name me.Font#textBaseline
             */
            this.textBaseline = "top";

            /**
             * Set the line spacing height (when displaying multi-line strings).

             * Current font height will be multiplied with this value to set the line height.
             * @public
             * @type Number
             * @default 1.0
             * @name me.Font#lineHeight
             */
            this.lineHeight = 1.0;

            // super constructor
            this._super(me.Renderable, "init", [0, 0, 0, 0]);

            // font name and type
            this.setFont(font, size, fillStyle, textAlign);

            if (!this.gid) {
                this.gid = me.utils.createGUID();
            }
        },

        /**
         * make the font bold
         * @name bold
         * @memberOf me.Font
         * @function
         */
        bold : function () {
            this.font = "bold " + this.font;
        },

        /**
         * make the font italic
         * @name italic
         * @memberOf me.Font
         * @function
         */
        italic : function () {
            this.font = "italic " + this.font;
        },

        /**
         * Change the font settings
         * @name setFont
         * @memberOf me.Font
         * @function
         * @param {String} font a CSS font name
         * @param {Number|String} size size, or size + suffix (px, em, pt)
         * @param {me.Color|String} fillStyle a CSS color value
         * @param {String} [textAlign="left"] horizontal alignment
         * @example
         * font.setFont("Arial", 20, "white");
         * font.setFont("Arial", "1.5em", "white");
         */
        setFont : function (font, size, fillStyle, textAlign) {
            // font name and type
            var font_names = font.split(",").map(function (value) {
                value = value.trim();
                return (
                    !/(^".*"$)|(^'.*'$)/.test(value)
                ) ? "\"" + value + "\"" : value;
            });

            this.fontSize.y = +size;
            this.height = this.fontSize.y;

            if (typeof size === "number") {
                size += "px";
            }
            this.font = size + " " + font_names.join(",");
            if (typeof(fillStyle) !== "undefined") {
                this.fillStyle.copy(fillStyle);
            }
            if (textAlign) {
                this.textAlign = textAlign;
            }
        },

        /**
         * measure the given text size in pixels
         * @name measureText
         * @memberOf me.Font
         * @function
         * @param {me.CanvasRenderer|me.WebGLRenderer} renderer Reference to the destination renderer instance
         * @param {String} text
         * @return {Object} returns an object, with two attributes: width (the width of the text) and height (the height of the text).
         */
        measureText : function (renderer, text) {
            var context = renderer.fontContext2D;

            // draw the text
            context.font = this.font;
            context.fillStyle = this.fillStyle.toRGBA();
            context.textAlign = this.textAlign;
            context.textBaseline = this.textBaseline;

            this.height = this.width = 0;

            var strings = ("" + text).split("\n");
            for (var i = 0; i < strings.length; i++) {
                this.width = Math.max(context.measureText(strings[i].trimRight()).width, this.width);
                this.height += this.fontSize.y * this.lineHeight;
            }
            return {
                width : this.width,
                height : this.height
            };
        },

        /**
         * draw a text at the specified coord
         * @name draw
         * @memberOf me.Font
         * @function
         * @param {me.CanvasRenderer|me.WebGLRenderer} renderer Reference to the destination renderer instance
         * @param {String} text
         * @param {Number} x
         * @param {Number} y
         */

        draw : function (renderer, text, x, y) {
            x = ~~x;
            y = ~~y;

            // save the previous global alpha value
            var _alpha = renderer.globalAlpha();
            renderer.setGlobalAlpha(_alpha * this.getOpacity());

            // update initial position
            this.pos.set(x, y, this.pos.z);  // TODO: z ?
            // draw the text
            renderer.drawFont(this._drawFont(renderer.fontContext2D, text, x, y, false));

            // restore the previous global alpha value
            renderer.setGlobalAlpha(_alpha);
        },

        /**
         * draw a stroke text at the specified coord, as defined

         * by the `lineWidth` and `fillStroke` properties.

         * Note : using drawStroke is not recommended for performance reasons
         * @name drawStroke
         * @memberOf me.Font
         * @function
         * @param {me.CanvasRenderer|me.WebGLRenderer} renderer Reference to the destination renderer instance
         * @param {String} text
         * @param {Number} x
         * @param {Number} y
         */
        drawStroke : function (renderer, text, x, y) {
            x = ~~x;
            y = ~~y;

            // save the previous global alpha value
            var _alpha = renderer.globalAlpha();
            renderer.setGlobalAlpha(_alpha * this.getOpacity());

            // update initial position
            this.pos.set(x, y, this.pos.z); // TODO: z ?
            // draw the text
            renderer.drawFont(this._drawFont(renderer.fontContext2D, text, x, y, true));

            // restore the previous global alpha value
            renderer.setGlobalAlpha(_alpha);
        },

        /**
         * @ignore
         */
        _drawFont : function (context, text, x, y, stroke) {
            context.font = this.font;
            context.fillStyle = this.fillStyle.toRGBA();
            if (stroke) {
                context.strokeStyle = this.strokeStyle.toRGBA();
                context.lineWidth = this.lineWidth;
            }
            context.textAlign = this.textAlign;
            context.textBaseline = this.textBaseline;

            var strings = ("" + text).split("\n"), string = "";
            var dw = 0;
            var dy = y;
            var lineHeight = this.fontSize.y * this.lineHeight;
            for (var i = 0; i < strings.length; i++) {
                string = strings[i].trimRight();
                // measure the string
                dw = Math.max(dw, context.measureText(string).width);
                // draw the string
                context[stroke ? "strokeText" : "fillText"](string, x, y);
                // add leading space
                y += lineHeight;
            }

            // compute bounds
            var dx = (this.textAlign === "right" ? x - dw : (
                this.textAlign === "center" ? x - ~~(dw / 2) : x
            ));
            dy = (this.textBaseline.search(/^(top|hanging)$/) === 0) ? dy : (
                this.textBaseline === "middle" ? dy - ~~(lineHeight / 2) : dy - lineHeight
            );

            return {
                x: ~~dx,
                y: ~~dy,
                w: ~~(dw + 0.5),
                h: ~~(strings.length * lineHeight + 0.5)
            };
        }
    });
})();
<commit_msg>Why is the font position being set when drawing?<commit_after>/*
 * MelonJS Game Engine
 * Copyright (C) 2011 - 2015, Olivier Biot, Jason Oster, Aaron McLeod
 * http://www.melonjs.org
 *
 * Font / Bitmap font
 *
 * ASCII Table
 * http://www.asciitable.com/
 * [ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz]
 *
 * -> first char " " 32d (0x20);
 */
(function () {
    /**
     * a generic system font object.
     * @class
     * @extends me.Renderable
     * @memberOf me
     * @constructor
     * @param {String} font a CSS font name
     * @param {Number|String} size size, or size + suffix (px, em, pt)
     * @param {me.Color|String} fillStyle a CSS color value
     * @param {String} [textAlign="left"] horizontal alignment
     */
    me.Font = me.Renderable.extend(
    /** @scope me.Font.prototype */ {

        /** @ignore */
        init : function (font, size, fillStyle, textAlign) {
            // private font properties
            /** @ignore */
            this.fontSize = new me.Vector2d();

            /**
             * defines the color used to draw the font.

             * @public
             * @type me.Color
             * @default black
             * @name me.Font#fillStyle
             */
            this.fillStyle = new me.Color().copy(fillStyle);

            /**
             * defines the color used to draw the font stroke.

             * @public
             * @type me.Color
             * @default black
             * @name me.Font#strokeStyle
             */
            this.strokeStyle = new me.Color(0, 0, 0);

            /**
             * sets the current line width, in pixels, when drawing stroke
             * @public
             * @type Number
             * @default 1
             * @name me.Font#lineWidth
             */
            this.lineWidth = 1;

            /**
             * Set the default text alignment (or justification),

             * possible values are "left", "right", and "center".

             * @public
             * @type String
             * @default "left"
             * @name me.Font#textAlign
             */
            this.textAlign = textAlign || "left";

            /**
             * Set the text baseline (e.g. the Y-coordinate for the draw operation),

             * possible values are "top", "hanging, "middle, "alphabetic, "ideographic, "bottom"

             * @public
             * @type String
             * @default "top"
             * @name me.Font#textBaseline
             */
            this.textBaseline = "top";

            /**
             * Set the line spacing height (when displaying multi-line strings).

             * Current font height will be multiplied with this value to set the line height.
             * @public
             * @type Number
             * @default 1.0
             * @name me.Font#lineHeight
             */
            this.lineHeight = 1.0;

            // super constructor
            this._super(me.Renderable, "init", [0, 0, 0, 0]);

            // font name and type
            this.setFont(font, size, fillStyle, textAlign);

            if (!this.gid) {
                this.gid = me.utils.createGUID();
            }
        },

        /**
         * make the font bold
         * @name bold
         * @memberOf me.Font
         * @function
         */
        bold : function () {
            this.font = "bold " + this.font;
        },

        /**
         * make the font italic
         * @name italic
         * @memberOf me.Font
         * @function
         */
        italic : function () {
            this.font = "italic " + this.font;
        },

        /**
         * Change the font settings
         * @name setFont
         * @memberOf me.Font
         * @function
         * @param {String} font a CSS font name
         * @param {Number|String} size size, or size + suffix (px, em, pt)
         * @param {me.Color|String} fillStyle a CSS color value
         * @param {String} [textAlign="left"] horizontal alignment
         * @example
         * font.setFont("Arial", 20, "white");
         * font.setFont("Arial", "1.5em", "white");
         */
        setFont : function (font, size, fillStyle, textAlign) {
            // font name and type
            var font_names = font.split(",").map(function (value) {
                value = value.trim();
                return (
                    !/(^".*"$)|(^'.*'$)/.test(value)
                ) ? "\"" + value + "\"" : value;
            });

            this.fontSize.y = +size;
            this.height = this.fontSize.y;

            if (typeof size === "number") {
                size += "px";
            }
            this.font = size + " " + font_names.join(",");
            if (typeof(fillStyle) !== "undefined") {
                this.fillStyle.copy(fillStyle);
            }
            if (textAlign) {
                this.textAlign = textAlign;
            }
        },

        /**
         * measure the given text size in pixels
         * @name measureText
         * @memberOf me.Font
         * @function
         * @param {me.CanvasRenderer|me.WebGLRenderer} renderer Reference to the destination renderer instance
         * @param {String} text
         * @return {Object} returns an object, with two attributes: width (the width of the text) and height (the height of the text).
         */
        measureText : function (renderer, text) {
            var context = renderer.fontContext2D;

            // draw the text
            context.font = this.font;
            context.fillStyle = this.fillStyle.toRGBA();
            context.textAlign = this.textAlign;
            context.textBaseline = this.textBaseline;

            this.height = this.width = 0;

            var strings = ("" + text).split("\n");
            for (var i = 0; i < strings.length; i++) {
                this.width = Math.max(context.measureText(strings[i].trimRight()).width, this.width);
                this.height += this.fontSize.y * this.lineHeight;
            }
            return {
                width : this.width,
                height : this.height
            };
        },

        /**
         * draw a text at the specified coord
         * @name draw
         * @memberOf me.Font
         * @function
         * @param {me.CanvasRenderer|me.WebGLRenderer} renderer Reference to the destination renderer instance
         * @param {String} text
         * @param {Number} x
         * @param {Number} y
         */

        draw : function (renderer, text, x, y) {
            x = ~~x;
            y = ~~y;

            // save the previous global alpha value
            var _alpha = renderer.globalAlpha();
            renderer.setGlobalAlpha(_alpha * this.getOpacity());

            // draw the text
            renderer.drawFont(this._drawFont(renderer.fontContext2D, text, x, y, false));

            // restore the previous global alpha value
            renderer.setGlobalAlpha(_alpha);
        },

        /**
         * draw a stroke text at the specified coord, as defined

         * by the `lineWidth` and `fillStroke` properties.

         * Note : using drawStroke is not recommended for performance reasons
         * @name drawStroke
         * @memberOf me.Font
         * @function
         * @param {me.CanvasRenderer|me.WebGLRenderer} renderer Reference to the destination renderer instance
         * @param {String} text
         * @param {Number} x
         * @param {Number} y
         */
        drawStroke : function (renderer, text, x, y) {
            x = ~~x;
            y = ~~y;

            // save the previous global alpha value
            var _alpha = renderer.globalAlpha();
            renderer.setGlobalAlpha(_alpha * this.getOpacity());

            // draw the text
            renderer.drawFont(this._drawFont(renderer.fontContext2D, text, x, y, true));

            // restore the previous global alpha value
            renderer.setGlobalAlpha(_alpha);
        },

        /**
         * @ignore
         */
        _drawFont : function (context, text, x, y, stroke) {
            context.font = this.font;
            context.fillStyle = this.fillStyle.toRGBA();
            if (stroke) {
                context.strokeStyle = this.strokeStyle.toRGBA();
                context.lineWidth = this.lineWidth;
            }
            context.textAlign = this.textAlign;
            context.textBaseline = this.textBaseline;

            var strings = ("" + text).split("\n"), string = "";
            var dw = 0;
            var dy = y;
            var lineHeight = this.fontSize.y * this.lineHeight;
            for (var i = 0; i < strings.length; i++) {
                string = strings[i].trimRight();
                // measure the string
                dw = Math.max(dw, context.measureText(string).width);
                // draw the string
                context[stroke ? "strokeText" : "fillText"](string, x, y);
                // add leading space
                y += lineHeight;
            }

            // compute bounds
            var dx = (this.textAlign === "right" ? x - dw : (
                this.textAlign === "center" ? x - ~~(dw / 2) : x
            ));
            dy = (this.textBaseline.search(/^(top|hanging)$/) === 0) ? dy : (
                this.textBaseline === "middle" ? dy - ~~(lineHeight / 2) : dy - lineHeight
            );

            return {
                x: ~~dx,
                y: ~~dy,
                w: ~~(dw + 0.5),
                h: ~~(strings.length * lineHeight + 0.5)
            };
        }
    });
})();
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import Tenants from '/imports/collections/tenants';

Meteor.methods({
	findTenantBySubdomain(subdomain) {
		check(subdomain, String);
		return Tenants.findOne({ subdomain });
	},
});
<commit_msg>Tenants listing method added<commit_after>import { Meteor } from 'meteor/meteor';
import Tenants from '/imports/collections/tenants';

Meteor.methods({
	findTenantBySubdomain(subdomain) {
		check(subdomain, String);
		return Tenants.findOne({ subdomain });
	},
      tenants() {
        return Tenants.find().fetch();
      }
});
<|endoftext|>


<commit_before>import { iter } from "./access";

// iter form and replace fieldset types
export function process(node){
	iter.bind(this)(node,function(node){
		if(node.type == 6){
			// this is mutative
			if (node.inode.dataset.appearance == "hidden") {
				node.inode.disabled = true;
				node.inode.hidden = true;
			}
		}
	});
}
<commit_msg>return node as well<commit_after>import { ensureDoc } from "./doc";
import { iter } from "./access";

// iter form and replace fieldset types
export function process(node){
	iter.bind(this)(node,function(node){
		if(node.type == 6){
			// this is mutative
			if (node.inode.dataset.appearance == "hidden") {
				node.inode.disabled = true;
				node.inode.hidden = true;
			}
		}
	});
	return ensureDoc.bind(this)(node);
}
<|endoftext|>


<commit_before>//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Form Element shell
//------------------------------------------------------------------------------
d3plus.form = function() {

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Initialize the global variable object.
  //----------------------------------------------------------------------------
  var vars = { "shell": "form" }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Create the main drawing function.
  //----------------------------------------------------------------------------
  vars.self = function( selection ) {

    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // Set timing to 0 if it's the first time running this function or if the
    // data length is longer than the "large" limit
    //--------------------------------------------------------------------------
    var large = vars.data.value instanceof Array
                && vars.data.value.length > vars.data.large

    vars.draw.timing = vars.draw.first || large || d3plus.ie
                     ? 0 : vars.timing.ui

    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // Create/update the UI element
    //--------------------------------------------------------------------------
    if ( vars.data.value instanceof Array ) {

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Sort the data, if needed.
      //------------------------------------------------------------------------
      if ( vars.order.value && (vars.data.changed || vars.order.changed || vars.order.sort.changed) ) {

        var sort = vars.order.value || vars.id.value
          , order = vars.order.sort.value

        vars.data.value.sort(function(a,b){

          a = a[sort]
          b = b[sort]

          if (sort === vars.color.value) {

            a = d3.rgb(a_value).hsl()
            b = d3.rgb(b_value).hsl()

            if (a.s == 0) a = 361
            else a = a.h
            if (b.s == 0) b = 361
            else b = b.h

          }

          if (typeof a === "string") {
            a = a.toLowerCase()
          }

          if (typeof b === "string") {
            b = b.toLowerCase()
          }

          if(a < b) return order === "asc" ? -1 : 1;
          if(a > b) return order === "asc" ? 1 : -1;

        })

      }

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Set first element in data as focus if there is no focus set.
      //------------------------------------------------------------------------
      if ( !vars.focus.value && vars.data.value.length ) {

        vars.focus.value = vars.data.value[0][vars.id.value]
        if (vars.dev.value) d3plus.console.log("\"value\" set to \""+vars.focus+"\"")

      }

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Run these things if the data has changed.
      //------------------------------------------------------------------------
      if ( vars.data.changed ) {

        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        // Determine if search box is needed.
        //----------------------------------------------------------------------
        if ( vars.search.value === "auto" ) {

          if (vars.data.value.length > 10) {
            vars.search.enabled = true
            if (vars.dev.value) d3plus.console.log("Search enabled.")
          }
          else {
            vars.search.enabled = false
            if (vars.dev.value) d3plus.console.log("Search disabled.")
          }

        }
        else {

          vars.search.enabled = vars.search.value

        }

        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        // Update OPTION elements with the new data.
        //----------------------------------------------------------------------
        if ( vars.data.element && vars.type.value === "drop" ) {

          options = vars.data.element.selectAll("option")
            .data(vars.data.value,function(d){
              return d ? d.value : false
            })

          options.enter().append("option")
            .each(function(d){

              for (k in d) {
                if ( k === vars.text.value ) {
                  d3.select(this).html(d[k])
                }
                if ( ["alt","value"].indexOf(k) >= 0 ) {
                  d3.select(this).attr(k,d[k])
                }
                else {
                  d3.select(this).attr("data-"+k,d[k])
                }
              }

              if (d[vars.id.value] === vars.focus) {
                this.selected = true
              }
              else {
                this.selected = false
              }

            })

          options.exit().remove()

        }

      }

      if (vars.draw.first) {

        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        // Select container DIV for UI element
        //----------------------------------------------------------------------
        vars.container.ui = vars.container.value
          .selectAll("div#d3plus_"+vars.type.value+"_"+vars.container.id)
          .data(["container"])

        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        // Create container DIV for UI element
        //----------------------------------------------------------------------
        var before = vars.data.element && vars.data.element.node().id
                   ? "#"+vars.data.element.node().id : null

        vars.container.ui.enter()
          .insert("div",before)
          .attr("id","d3plus_"+vars.type.value+"_"+vars.container.id)
          .style("position","relative")
          .style("overflow","visible")
          .style("vertical-align","top")

      }

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Update Container
      //------------------------------------------------------------------------
      vars.container.ui.transition().duration(vars.draw.timing)
        .style("display",vars.ui.display.value)
        .style("margin",vars.ui.margin+"px")

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Create title, if available.
      //------------------------------------------------------------------------
      var title = vars.container.ui.selectAll("div.d3plus_title")
        .data(vars.title.value ? [vars.title.value] : [])

      title.enter().insert("div","#d3plus_"+vars.type.value+"_"+vars.container.id)
        .attr("class","d3plus_title")

      title.transition().duration(vars.draw.timing)
        .style("display",vars.ui.display.value)
        .style("color",vars.font.color)
        .style("font-family",vars.font.family.value)
        .style("font-size",vars.font.size+"px")
        .style("font-weight",vars.font.weight)
        .style("padding",vars.ui.padding+"px")
        .style("border-color","transparent")
        .style("border-style","solid")
        .style("border-width",vars.ui.border+"px")
        .text(String)

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Call specific UI element type, if there is data.
      //------------------------------------------------------------------------
      if ( vars.data.value.length ) {

        if (vars.dev.value) d3plus.console.group("drawing \""+vars.type.value+"\"")
        d3plus.input[vars.type.value]( vars )
        if (vars.dev.value) d3plus.console.groupEnd()

      }
      else if ( vars.data.url && (!vars.data.loaded || vars.data.stream) ) {

        d3plus.data.json( vars , "data" , vars.self.draw )

      }

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Initialization complete
      //------------------------------------------------------------------------
      d3plus.data.reset( vars )

    }

  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Define methods and expose public variables.
  //----------------------------------------------------------------------------
  var methods = [ "alt" , "color" , "container" , "dev" , "data" , "draw"
                , "focus" , "format" , "height" , "hover" , "icon" , "id"
                , "keywords" , "open" , "order" , "remove" , "search"
                , "select" , "selectAll" , "text" , "title" , "type" , "width" ]
    , styles  = [ "drop" , "font" , "icon" , "timing" , "title" , "ui" ]

  d3plus.method( vars , methods , styles )

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Finally, return the main UI function to the user
  //----------------------------------------------------------------------------
  return vars.self

}
<commit_msg>fixed select options not updating when data is loaded/changed<commit_after>//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Form Element shell
//------------------------------------------------------------------------------
d3plus.form = function() {

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Initialize the global variable object.
  //----------------------------------------------------------------------------
  var vars = { "shell": "form" }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Create the main drawing function.
  //----------------------------------------------------------------------------
  vars.self = function( selection ) {

    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // Set timing to 0 if it's the first time running this function or if the
    // data length is longer than the "large" limit
    //--------------------------------------------------------------------------
    var large = vars.data.value instanceof Array
                && vars.data.value.length > vars.data.large

    vars.draw.timing = vars.draw.first || large || d3plus.ie
                     ? 0 : vars.timing.ui

    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // Create/update the UI element
    //--------------------------------------------------------------------------
    if ( vars.data.value instanceof Array ) {

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Sort the data, if needed.
      //------------------------------------------------------------------------
      if ( vars.order.value && (vars.data.changed || vars.order.changed || vars.order.sort.changed) ) {

        var sort = vars.order.value || vars.id.value
          , order = vars.order.sort.value

        vars.data.value.sort(function(a,b){

          a = a[sort]
          b = b[sort]

          if (sort === vars.color.value) {

            a = d3.rgb(a_value).hsl()
            b = d3.rgb(b_value).hsl()

            if (a.s == 0) a = 361
            else a = a.h
            if (b.s == 0) b = 361
            else b = b.h

          }

          if (typeof a === "string") {
            a = a.toLowerCase()
          }

          if (typeof b === "string") {
            b = b.toLowerCase()
          }

          if(a < b) return order === "asc" ? -1 : 1;
          if(a > b) return order === "asc" ? 1 : -1;

        })

      }

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Set first element in data as focus if there is no focus set.
      //------------------------------------------------------------------------
      if ( !vars.focus.value && vars.data.value.length ) {

        vars.focus.value = vars.data.value[0][vars.id.value]
        if (vars.dev.value) d3plus.console.log("\"value\" set to \""+vars.focus+"\"")

      }

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Run these things if the data has changed.
      //------------------------------------------------------------------------
      if ( vars.data.changed ) {

        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        // Determine if search box is needed.
        //----------------------------------------------------------------------
        if ( vars.search.value === "auto" ) {

          if (vars.data.value.length > 10) {
            vars.search.enabled = true
            if (vars.dev.value) d3plus.console.log("Search enabled.")
          }
          else {
            vars.search.enabled = false
            if (vars.dev.value) d3plus.console.log("Search disabled.")
          }

        }
        else {

          vars.search.enabled = vars.search.value

        }

        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        // Update OPTION elements with the new data.
        //----------------------------------------------------------------------
        if ( vars.data.element && vars.data.element.node().tagName === "SELECT" ) {

          options = vars.data.element.selectAll("option")
            .data(vars.data.value,function(d){
              return d ? d[vars.id.value] : false
            })

          options.exit().remove()

          options.enter().append("option")

          options
            .each(function(d){

              for (k in d) {
                if ( k === vars.text.value ) {
                  d3.select(this).html(d[k])
                }
                if ( ["alt","value"].indexOf(k) >= 0 ) {
                  d3.select(this).attr(k,d[k])
                }
                else {
                  d3.select(this).attr("data-"+k,d[k])
                }
              }

              if (d[vars.id.value] === vars.focus) {
                this.selected = true
              }
              else {
                this.selected = false
              }

            })

        }

      }

      if (vars.draw.first) {

        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        // Select container DIV for UI element
        //----------------------------------------------------------------------
        vars.container.ui = vars.container.value
          .selectAll("div#d3plus_"+vars.type.value+"_"+vars.container.id)
          .data(["container"])

        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        // Create container DIV for UI element
        //----------------------------------------------------------------------
        var before = vars.data.element && vars.data.element.node().id
                   ? "#"+vars.data.element.node().id : null

        vars.container.ui.enter()
          .insert("div",before)
          .attr("id","d3plus_"+vars.type.value+"_"+vars.container.id)
          .style("position","relative")
          .style("overflow","visible")
          .style("vertical-align","top")

      }

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Update Container
      //------------------------------------------------------------------------
      vars.container.ui.transition().duration(vars.draw.timing)
        .style("display",vars.ui.display.value)
        .style("margin",vars.ui.margin+"px")

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Create title, if available.
      //------------------------------------------------------------------------
      var title = vars.container.ui.selectAll("div.d3plus_title")
        .data(vars.title.value ? [vars.title.value] : [])

      title.enter().insert("div","#d3plus_"+vars.type.value+"_"+vars.container.id)
        .attr("class","d3plus_title")

      title.transition().duration(vars.draw.timing)
        .style("display",vars.ui.display.value)
        .style("color",vars.font.color)
        .style("font-family",vars.font.family.value)
        .style("font-size",vars.font.size+"px")
        .style("font-weight",vars.font.weight)
        .style("padding",vars.ui.padding+"px")
        .style("border-color","transparent")
        .style("border-style","solid")
        .style("border-width",vars.ui.border+"px")
        .text(String)

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Call specific UI element type, if there is data.
      //------------------------------------------------------------------------
      if ( vars.data.value.length ) {

        if (vars.dev.value) d3plus.console.group("drawing \""+vars.type.value+"\"")
        d3plus.input[vars.type.value]( vars )
        if (vars.dev.value) d3plus.console.groupEnd()

      }
      else if ( vars.data.url && (!vars.data.loaded || vars.data.stream) ) {

        d3plus.data.json( vars , "data" , vars.self.draw )

      }

      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      // Initialization complete
      //------------------------------------------------------------------------
      d3plus.data.reset( vars )

    }

  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Define methods and expose public variables.
  //----------------------------------------------------------------------------
  var methods = [ "alt" , "color" , "container" , "dev" , "data" , "draw"
                , "focus" , "format" , "height" , "hover" , "icon" , "id"
                , "keywords" , "open" , "order" , "remove" , "search"
                , "select" , "selectAll" , "text" , "title" , "type" , "width" ]
    , styles  = [ "drop" , "font" , "icon" , "timing" , "title" , "ui" ]

  d3plus.method( vars , methods , styles )

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Finally, return the main UI function to the user
  //----------------------------------------------------------------------------
  return vars.self

}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */
foam.CLASS({
  package: 'foam.nanos.auth',
  name: 'User',

  implements: [
    'foam.nanos.auth.EnabledAware',
    'foam.nanos.auth.LastModifiedAware',
    'foam.nanos.auth.LastModifiedByAware'
  ],

  requires: [
    'foam.nanos.auth.Phone',
    'foam.nanos.auth.Address'
  ],

  documentation: '',

  tableColumns: [
    'id', 'enabled', 'type', 'group', 'firstName', 'lastName', 'organization', 'email'
  ],

  properties: [
    {
      class: 'Long',
      name: 'id',
      max: 999,
      tableWidth: 45
    },
    {
      class: 'String',
      // class: 'SPID',
      label: 'Service Provider',
      name: 'spid',
      documentation: "User's service provider."
    },
    {
      class: 'DateTime',
      name: 'lastLogin'
    },
    {
      class: 'String',
      name: 'firstName',
      tableWidth: 160
    },
    {
      class: 'String',
      name: 'middleName'
    },
    {
      class: 'String',
      name: 'lastName',
      tableWidth: 160
    },
    {
      class: 'String',
      name: 'organization',
      width: 175,
      tableWidth: 160
    },
    {
      class: 'String',
      name: 'department',
      width: 50
    },
    {
      class: 'EMail',
      name: 'email',
      width: 200,
      preSet: function (_, val) {
        return val.toLowerCase();
      },
      javaSetter:
`email_ = val.toLowerCase();
emailIsSet_ = true;`
    },
    {
      class: 'FObjectProperty',
      of: 'foam.nanos.auth.Phone',
      name: 'phone',
      factory: function() { return this.Phone.create(); },
      view: 'foam.nanos.auth.PhoneDetailView'
    },
    {
      class: 'FObjectProperty',
      of: 'foam.nanos.auth.Phone',
      name: 'mobile',
      factory: function() { return this.Phone.create(); },
      view: 'foam.nanos.auth.PhoneDetailView'
    },
    {
      class: 'String',
      name: 'type',
      tableWidth: 91,
      view: {
        class: 'foam.u2.view.ChoiceView',
        choices: [ 'Personal', 'Business', 'Shopper', 'Merchant', 'Broker', 'Bank' ]
      }
    },
    {
      class: 'Date',
      name: 'birthday'
    },
    {
      class: 'Blob',
      name: 'profilePicture',
      tableCellFormatter: function (value) {
        this.tag({ class: 'foam.u2.view.ImageBlobView' });
      }
    },
    {
      class: 'FObjectProperty',
      of: 'foam.nanos.auth.Address',
      name: 'address',
      factory: function() { return this.Address.create(); },
      view: 'foam.nanos.auth.AddressDetailView'
    },
    {
      class: 'FObjectArray',
      of: 'foam.core.FObject',
      name: 'accounts',
      hidden: true
    },
    {
      class: 'Reference',
      name: 'language',
      of: 'foam.nanos.auth.Language',
      value: 'en'
    },
    {
      class: 'String',
      name: 'timeZone',
      width: 5
      // TODO: create custom view or DAO
    },
    {
      class: 'Password',
      name: 'password',
      displayWidth: 30,
      width: 100
    },
    {
      class: 'Password',
      name: 'previousPassword',
      hidden: true,
      displayWidth: 30,
      width: 100
    },
    {
      class: 'DateTime',
      name: 'passwordLastModified'
    },
    // TODO: startDate, endDate,
    // TODO: do we want to replace 'note' with a simple ticket system?
    {
      class: 'String',
      name: 'note',
      displayWidth: 70,
      view: { class: 'foam.u2.tag.TextArea', rows: 4, cols: 100 }
    },
    // TODO: remove after demo
    {
      class: 'String',
      name: 'businessName',
      documentation: 'Name of the business',
      width: 50
    },
    {
      class: 'String',
      name: 'businessIdentificationNumber',
      width: 35,
      documentation: 'Business Identification Number (BIN)'
    },
    {
      class: 'String',
      name: 'issuingAuthority',
      width: 35
    },
    {
      class: 'String',
      name: 'bankIdentificationCode',
      width: 20,
      documentation: 'Bank Identification Code (BIC)'
    },
    {
      class: 'URL',
      name: 'website',
      width: 50
    }
  ],

  methods: [
    function label() {
      return this.organization || ( this.firstName + ' ' + this.lastName );
    }
  ]
});
<commit_msg>Undid changes to User.js<commit_after>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */
foam.CLASS({
  package: 'foam.nanos.auth',
  name: 'User',

  implements: [
    'foam.nanos.auth.EnabledAware',
    'foam.nanos.auth.LastModifiedAware',
    'foam.nanos.auth.LastModifiedByAware'
  ],

  requires: [
    'foam.nanos.auth.Phone',
    'foam.nanos.auth.Address'
  ],

  documentation: '',

  tableColumns: [
    'id', 'enabled', 'type', 'group', 'firstName', 'lastName', 'organization', 'email'
  ],

  properties: [
    {
      class: 'Long',
      name: 'id',
      max: 999,
      tableWidth: 45
    },
    {
      class: 'String',
      // class: 'SPID',
      label: 'Service Provider',
      name: 'spid',
      documentation: "User's service provider."
    },
    {
      class: 'DateTime',
      name: 'lastLogin'
    },
    {
      class: 'String',
      name: 'firstName',
      tableWidth: 160
    },
    {
      class: 'String',
      name: 'middleName'
    },
    {
      class: 'String',
      name: 'lastName',
      tableWidth: 160
    },
    {
      class: 'String',
      name: 'organization',
      width: 175,
      tableWidth: 160
    },
    {
      class: 'String',
      name: 'department',
      width: 50
    },
    {
      class: 'EMail',
      name: 'email',
      width: 200,
      preSet: function (_, val) {
        return val.toLowerCase();
      },
      javaSetter:
`email_ = val.toLowerCase();
emailIsSet_ = true;`
    },
    {
      class: 'FObjectProperty',
      of: 'foam.nanos.auth.Phone',
      name: 'phone',
      factory: function() { return this.Phone.create(); },
      view: 'foam.nanos.auth.PhoneDetailView'
    },
    {
      class: 'FObjectProperty',
      of: 'foam.nanos.auth.Phone',
      name: 'mobile',
      factory: function() { return this.Phone.create(); },
      view: 'foam.nanos.auth.PhoneDetailView'
    },
    {
      class: 'String',
      name: 'type',
      tableWidth: 91,
      view: {
        class: 'foam.u2.view.ChoiceView',
        choices: [ 'Personal', 'Business', 'Merchant', 'Broker', 'Bank' ]
      }
    },
    {
      class: 'Date',
      name: 'birthday'
    },
    {
      class: 'Blob',
      name: 'profilePicture',
      tableCellFormatter: function (value) {
        this.tag({ class: 'foam.u2.view.ImageBlobView' });
      }
    },
    {
      class: 'FObjectProperty',
      of: 'foam.nanos.auth.Address',
      name: 'address',
      factory: function() { return this.Address.create(); },
      view: 'foam.nanos.auth.AddressDetailView'
    },
    {
      class: 'FObjectArray',
      of: 'foam.core.FObject',
      name: 'accounts',
      hidden: true
    },
    {
      class: 'Reference',
      name: 'language',
      of: 'foam.nanos.auth.Language',
      value: 'en'
    },
    {
      class: 'String',
      name: 'timeZone',
      width: 5
      // TODO: create custom view or DAO
    },
    {
      class: 'Password',
      name: 'password',
      displayWidth: 30,
      width: 100
    },
    {
      class: 'Password',
      name: 'previousPassword',
      hidden: true,
      displayWidth: 30,
      width: 100
    },
    {
      class: 'DateTime',
      name: 'passwordLastModified'
    },
    // TODO: startDate, endDate,
    // TODO: do we want to replace 'note' with a simple ticket system?
    {
      class: 'String',
      name: 'note',
      displayWidth: 70,
      view: { class: 'foam.u2.tag.TextArea', rows: 4, cols: 100 }
    },
    // TODO: remove after demo
    {
      class: 'String',
      name: 'businessName',
      documentation: 'Name of the business',
      width: 50
    },
    {
      class: 'String',
      name: 'businessIdentificationNumber',
      width: 35,
      documentation: 'Business Identification Number (BIN)'
    },
    {
      class: 'String',
      name: 'issuingAuthority',
      width: 35
    },
    {
      class: 'String',
      name: 'bankIdentificationCode',
      width: 20,
      documentation: 'Bank Identification Code (BIC)'
    },
    {
      class: 'URL',
      name: 'website',
      width: 2048
    }
  ],

  methods: [
    function label() {
      return this.organization || ( this.firstName + ' ' + this.lastName );
    }
  ]
});
<|endoftext|>


<commit_before>const Utils = {
  deleteProps(obj) {
    const object = obj;
    Object.keys(object).forEach((key) => {
      object[key] = null;
      delete object[key];
    });
  },
  nextTick(callback, delay = 0) {
    return setTimeout(callback, delay);
  },
  nextFrame(callback) {
    if (window.requestAnimationFrame) return window.requestAnimationFrame(callback);
    else if (window.webkitRequestAnimationFrame) return window.webkitRequestAnimationFrame(callback);
    return window.setTimeout(callback, 1000 / 60);
  },
  now() {
    return Date.now();
  },
  promise(handler) {
    let resolved = false;
    let rejected = false;
    let resolveArgs;
    let rejectArgs;
    const promiseHandlers = {
      then: undefined,
      catch: undefined,
    };
    const promise = {
      then(thenHandler) {
        if (resolved) {
          thenHandler(...resolveArgs);
        } else {
          promiseHandlers.then = thenHandler;
        }
        return promise;
      },
      catch(catchHandler) {
        if (rejected) {
          catchHandler(...rejectArgs);
        } else {
          promiseHandlers.catch = catchHandler;
        }
        return promise;
      },
    };

    function resolve(...args) {
      resolved = true;
      if (promiseHandlers.then) promiseHandlers.then(...args);
      else resolveArgs = args;
    }
    function reject(...args) {
      rejected = true;
      if (promiseHandlers.catch) promiseHandlers.catch(...args);
      else rejectArgs = args;
    }
    handler(resolve, reject);

    return promise;
  },
  requestAnimationFrame(callback) {
    if (window.requestAnimationFrame) return window.requestAnimationFrame(callback);
    else if (window.webkitRequestAnimationFrame) return window.webkitRequestAnimationFrame(callback);
    return window.setTimeout(callback, 1000 / 60);
  },
  cancelAnimationFrame(id) {
    if (window.cancelAnimationFrame) return window.cancelAnimationFrame(id);
    else if (window.webkitCancelAnimationFrame) return window.webkitCancelAnimationFrame(id);
    return window.clearTimeout(id);
  },
  parseUrlQuery(url) {
    const query = {};
    let urlToParse = url || window.location.href;
    let i;
    let params;
    let param;
    let length;
    if (typeof urlToParse === 'string' && urlToParse.length) {
      urlToParse = urlToParse.indexOf('?') > -1 ? urlToParse.replace(/\S*\?/, '') : '';
      params = urlToParse.split('&').filter(paramsPart => paramsPart !== '');
      length = params.length;

      for (i = 0; i < length; i += 1) {
        param = params[i].replace(/#\S+/g, '').split('=');
        query[decodeURIComponent(param[0])] = typeof param[1] === 'undefined' ? undefined : decodeURIComponent(param[1]) || '';
      }
    }
    return query;
  },
  extend(...args) {
    const to = Object(args[0]);
    for (let i = 1; i < args.length; i += 1) {
      const nextSource = args[i];
      if (nextSource !== undefined && nextSource !== null) {
        const keysArray = Object.keys(Object(nextSource));
        for (let nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex += 1) {
          const nextKey = keysArray[nextIndex];
          const desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            if (typeof to[nextKey] === 'object' && typeof nextSource[nextKey] === 'object') {
              Utils.extend(to[nextKey], nextSource[nextKey]);
            } else {
              to[nextKey] = nextSource[nextKey];
            }
          }
        }
      }
    }
    return to;
  },
};
export default Utils;
<commit_msg>getTranslate Util<commit_after>const Utils = {
  deleteProps(obj) {
    const object = obj;
    Object.keys(object).forEach((key) => {
      object[key] = null;
      delete object[key];
    });
  },
  nextTick(callback, delay = 0) {
    return setTimeout(callback, delay);
  },
  nextFrame(callback) {
    if (window.requestAnimationFrame) return window.requestAnimationFrame(callback);
    else if (window.webkitRequestAnimationFrame) return window.webkitRequestAnimationFrame(callback);
    return window.setTimeout(callback, 1000 / 60);
  },
  now() {
    return Date.now();
  },
  getTranslate(el, axis = 'x') {
    let matrix;
    let curTransform;
    let transformMatrix;

    const curStyle = window.getComputedStyle(el, null);

    if (window.WebKitCSSMatrix) {
      curTransform = curStyle.transform || curStyle.webkitTransform;
      if (curTransform.split(',').length > 6) {
        curTransform = curTransform.split(', ').map(a => a.replace(',', '.')).join(', ');
      }
      // Some old versions of Webkit choke when 'none' is passed; pass
      // empty string instead in this case
      transformMatrix = new window.WebKitCSSMatrix(curTransform === 'none' ? '' : curTransform);
    } else {
      transformMatrix = curStyle.MozTransform || curStyle.OTransform || curStyle.MsTransform || curStyle.msTransform || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');
      matrix = transformMatrix.toString().split(',');
    }

    if (axis === 'x') {
      // Latest Chrome and webkits Fix
      if (window.WebKitCSSMatrix) curTransform = transformMatrix.m41;
      // Crazy IE10 Matrix
      else if (matrix.length === 16) curTransform = parseFloat(matrix[12]);
      // Normal Browsers
      else curTransform = parseFloat(matrix[4]);
    }
    if (axis === 'y') {
      // Latest Chrome and webkits Fix
      if (window.WebKitCSSMatrix) curTransform = transformMatrix.m42;
      // Crazy IE10 Matrix
      else if (matrix.length === 16) curTransform = parseFloat(matrix[13]);
      // Normal Browsers
      else curTransform = parseFloat(matrix[5]);
    }
    return curTransform || 0;
  },
  promise(handler) {
    let resolved = false;
    let rejected = false;
    let resolveArgs;
    let rejectArgs;
    const promiseHandlers = {
      then: undefined,
      catch: undefined,
    };
    const promise = {
      then(thenHandler) {
        if (resolved) {
          thenHandler(...resolveArgs);
        } else {
          promiseHandlers.then = thenHandler;
        }
        return promise;
      },
      catch(catchHandler) {
        if (rejected) {
          catchHandler(...rejectArgs);
        } else {
          promiseHandlers.catch = catchHandler;
        }
        return promise;
      },
    };

    function resolve(...args) {
      resolved = true;
      if (promiseHandlers.then) promiseHandlers.then(...args);
      else resolveArgs = args;
    }
    function reject(...args) {
      rejected = true;
      if (promiseHandlers.catch) promiseHandlers.catch(...args);
      else rejectArgs = args;
    }
    handler(resolve, reject);

    return promise;
  },
  requestAnimationFrame(callback) {
    if (window.requestAnimationFrame) return window.requestAnimationFrame(callback);
    else if (window.webkitRequestAnimationFrame) return window.webkitRequestAnimationFrame(callback);
    return window.setTimeout(callback, 1000 / 60);
  },
  cancelAnimationFrame(id) {
    if (window.cancelAnimationFrame) return window.cancelAnimationFrame(id);
    else if (window.webkitCancelAnimationFrame) return window.webkitCancelAnimationFrame(id);
    return window.clearTimeout(id);
  },
  parseUrlQuery(url) {
    const query = {};
    let urlToParse = url || window.location.href;
    let i;
    let params;
    let param;
    let length;
    if (typeof urlToParse === 'string' && urlToParse.length) {
      urlToParse = urlToParse.indexOf('?') > -1 ? urlToParse.replace(/\S*\?/, '') : '';
      params = urlToParse.split('&').filter(paramsPart => paramsPart !== '');
      length = params.length;

      for (i = 0; i < length; i += 1) {
        param = params[i].replace(/#\S+/g, '').split('=');
        query[decodeURIComponent(param[0])] = typeof param[1] === 'undefined' ? undefined : decodeURIComponent(param[1]) || '';
      }
    }
    return query;
  },
  extend(...args) {
    const to = Object(args[0]);
    for (let i = 1; i < args.length; i += 1) {
      const nextSource = args[i];
      if (nextSource !== undefined && nextSource !== null) {
        const keysArray = Object.keys(Object(nextSource));
        for (let nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex += 1) {
          const nextKey = keysArray[nextIndex];
          const desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            if (typeof to[nextKey] === 'object' && typeof nextSource[nextKey] === 'object') {
              Utils.extend(to[nextKey], nextSource[nextKey]);
            } else {
              to[nextKey] = nextSource[nextKey];
            }
          }
        }
      }
    }
    return to;
  },
};
export default Utils;
<|endoftext|>


<commit_before>
var path = require('path'),
    i18n = require('i18n');

/*
  Config system:

  config/
    system/
      config.json
      config.js
    development/
      config.json
      config.js
    production /
      config.json
      config.js

  1 - Source config.json & merge ENV/config.json
  2 - Require system/config.js
  3 - Requrie ENV/config.js
 */

console.log('[Config] Loading config.json');
var config = require(path.resolve('config/system', 'config.json'));

// merge base config with environment config
var envConfig = require(path.resolve('config/' + process.env.NODE_ENV, 'config.json'));
config = Object.merge(config, envConfig);

// properties to be resolved
var resolveProps = 'models,views,controllers,routes,locales,static'.split(',');
resolveProps.forEach(function(prop){
  app.set(prop, path.resolve(config[prop]));
});

// static properties, everything else
Object.keys(config, function(prop, value) {
  if (resolveProps.indexOf(prop) > 0) return;
  app.set(prop, value);
});

console.log('[Config] Configure base middleware');
app.use( require('body-parser').urlencoded({ extended: true }) );
app.use( require('body-parser').json() );
app.use( require('cookie-parser')() );
app.use( require('method-override')() );
app.use( require('express-session')(app.settings['express-session']) );
app.use( require('csurf')() );

/* --------------------------
 * Localization
 * --------------------------------------- */
i18n.configure(Object.merge({directory: app.settings.locales}, app.settings.i18n || {} ));
app.use(i18n.init);

/* --------------------------
 * Dynamic locals
 * --------------------------------------- */
app.use(function(req, res, next) {
  res.locals.path = req.path;
  res.locals.url = req.url;
  res.locals.user = req.user;
  res.locals.csrftoken = req.csrfToken();
  next();
});

/* --------------------------
 * Static locals
 * --------------------------------------- */
app.locals = {
  title: app.settings.title,
  version: app.settings.version,
  environment: app.settings.environment,

  moment: require('moment')
};

// TODO: better config
// Inititalize a socket server
var server = require('http').Server(app);
app.io = require('socket.io')(server);
app.io.router = require('socket.io-events')();
<commit_msg>Fixed merge bug (need deep merge)<commit_after>
var path = require('path'),
    i18n = require('i18n');

/*
  Config system:

  config/
    system/
      config.json
      config.js
    development/
      config.json
      config.js
    production /
      config.json
      config.js

  1 - Source config.json & merge ENV/config.json
  2 - Require system/config.js
  3 - Requrie ENV/config.js
 */

console.log('[Config] Loading config.json');
var config = require(path.resolve('config/system', 'config.json'));

// merge base config with environment config
var envConfig = require(path.resolve('config/' + process.env.NODE_ENV, 'config.json'));
config = Object.merge(config, envConfig, true);

// properties to be resolved
var resolveProps = 'models,views,controllers,routes,locales,static'.split(',');
resolveProps.forEach(function(prop){
  app.set(prop, path.resolve(config[prop]));
});

// static properties, everything else
Object.keys(config, function(prop, value) {
  if (resolveProps.indexOf(prop) > 0) return;
  app.set(prop, value);
});

console.log('[Config] Configure base middleware');
app.use( require('body-parser').urlencoded({ extended: true }) );
app.use( require('body-parser').json() );
app.use( require('cookie-parser')() );
app.use( require('method-override')() );
app.use( require('express-session')(app.settings['express-session']) );
app.use( require('csurf')() );

/* --------------------------
 * Localization
 * --------------------------------------- */
i18n.configure(Object.merge({directory: app.settings.locales}, app.settings.i18n || {}, true ));
app.use(i18n.init);

/* --------------------------
 * Dynamic locals
 * --------------------------------------- */
app.use(function(req, res, next) {
  res.locals.path = req.path;
  res.locals.url = req.url;
  res.locals.user = req.user;
  res.locals.csrftoken = req.csrfToken();
  next();
});

/* --------------------------
 * Static locals
 * --------------------------------------- */
app.locals = {
  title: app.settings.title,
  version: app.settings.version,
  environment: app.settings.environment,

  moment: require('moment')
};

// TODO: better config
// Inititalize a socket server
var server = require('http').Server(app);
app.io = require('socket.io')(server);
app.io.router = require('socket.io-events')();
<|endoftext|>