<commit_before>// Generated on 2014-03-28 using generator-phaser-official 0.0.8-rc-2
'use strict';
var config = require('./config.json'),
    _ = require('underscore'),
    shell = require('shelljs'),
    LIVERELOAD_PORT = 35729,
    lrSnippet = require('connect-livereload')({port: LIVERELOAD_PORT});

_.str = require('underscore.string');
_.mixin(_.str.exports());

function mountFolder(connect, dir) {
  return connect.static(require('path').resolve(dir));
}

module.exports = function (grunt) {
  // load all grunt tasks
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

  grunt.initConfig({
    manifest: grunt.file.readJSON('manifest.json'),
    watch: {
      scripts: {
        files: [
          '!game/main.js',
          'game/**/*',
          'templates/*.tpl',
          'config.json',
          'css/**/*.css'
        ],
        options: {
          spawn: false,
          livereload: LIVERELOAD_PORT
        },
        tasks: ['build:serve']
      }
    },
    connect: {
      options: {
        port: 9000,
        // change this to '0.0.0.0' to access the server from outside
        hostname: 'localhost'
      },
      livereload: {
        options: {
          middleware: function (connect) {
            return [
              lrSnippet,
              mountFolder(connect, 'serve')
            ];
          }
        }
      }
    },
    open: {
      server: {
        path: 'http://localhost:9000'
      }
    },
    copy: {
      serve: {
        files: [
          // includes files within path and its sub-directories
          { expand: true, src: ['assets/**', 'fonts/**', 'css/**'], dest: 'serve/' },
          { expand: true, flatten: true, src: [
            'game/plugins/*{.js,.map}',
            'bower_components/*/build/*{.js,.map}',
            'bower_components/*/dist/*{.js,.map}',
            'game/index.html'
          ], dest: 'serve/' }
        ]
      },
      dist: {
        files: [
          // includes files within path and its sub-directories
          { expand: true, src: [
            'assets/**',
            'fonts/**',
            'css/**',
            'icon.png',
            'manifest.json'
          ], dest: 'dist/' },
          { expand: true, flatten: true, src: [
            'game/plugins/*{.js,.map}',
            'bower_components/*/build/*{.js,.map}',
            'bower_components/*/dist/*{.js,.map}',
            'game/index.html'
          ], dest: 'dist/' }
        ]
      },
      dev: {
        options: {
          process: function(content) {
            return grunt.template.process(content, {
              data: {
                dependencies: [
                  'cordova.js',
                  'phaser.js',
                  'phaser-state-transition-plugin.min.js',
                  'game.js'
                ]
              }
            });
          }
        },
        files: [
          { src: 'game/config/config.dev.json', dest: 'game/config.json' },
          { src: 'templates/_index.html.tpl', dest: 'game/index.html' }
        ]
      },
      prod: {
        options: {
          process: function(content) {
            return grunt.template.process(content, {
              data: {
                dependencies: [
                  'cordova.js',
                  'phaser.js',
                  'phaser-state-transition-plugin.min.js',
                  'game.js'
                ]
              }
            });
          }
        },
        files: [
          { src: 'game/config/config.prod.json', dest: 'game/config.json' },
          { src: 'templates/_index.html.tpl', dest: 'game/index.html' }
        ]
      }
    },
    browserify: {
      serve: {
        src: ['game/main.js'],
        dest: 'serve/game.js'
      },
      dist: {
        src: ['game/main.js'],
        dest: 'dist/game.js'
        // dest: '.cache/game.js'
      }
    },
    // DISABLED
    uglify: {
      dist: {
        // files: {
        //   'dist/game.min.js': ['.cache/game.js']
        // }
      },
      serve: {}
    },
    clean: {
      serve: ['serve'],
      dist: ['dist', 'build'],
    },
    shell: {
      options: {
        stderr: false
      },
      xwalkBuild: {
        command: [
          'python $CROSSWALK_HOME/make_apk.py',
          '--manifest=dist/manifest.json',
          '--package=<%= manifest.package %>',
          '--name=<%= manifest.name %>',
          '--target-dir=build',
          '--mode=' + grunt.option('mode', 'embedded'),
          grunt.option('enable-remote-debugging') ? '--enable-remote-debugging' : '',
          grunt.option('compressor') ? '--compressor=' + grunt.option('compressor', '') : '',
          grunt.option('verbose') ? '--verbose' : ''
        ].join(' ')
      },
      xwalkInstallx86: {
        command: 'adb install -r build/*_x86.apk'
      },
      xwalkInstallarm: {
        command: 'adb install -r build/*_arm.apk'
      },
      restartAdb: {
        command: [
          'sudo $(which adb) kill-server',
          'sudo $(which adb) start-server',
          'adb devices'
        ].join('&&')
      },
      cordovaPrepare: {
        command: [
          'rm -rf www',
          'cp -a dist www'
        ].join('&&')
      },
      cordovaSplashIcons: {
        command: [
          'cordova-icon',
          'cordova-splash'
        ].join('&&')
      }
    },
    bump: {
      options: {
        files: ['package.json', 'bower.json', 'manifest.json', 'config.xml'],
        updateConfigs: [],
        commit: true,
        commitMessage: 'Release %VERSION%',
        commitFiles: ['package.json', 'bower.json', 'manifest.json', 'config.xml'],
        createTag: false,
        tagName: '%VERSION%',
        tagMessage: 'Version %VERSION%',
        push: false,
        pushTo: 'upstream',
        gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d'
      }
    },
    jshint: {
      all: ['game/**/*.js', 'Gruntfile.js'],
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      }
    },
    jscs: {
      src: [
        'game/**/*.js',
        '!game/main.js',
        '!game/plugins/*'
      ],
      options: {
        config: '.jscsrc',
        reporter: require('jscs-stylish').path
      }
    },
    githooks: {
      all: {
        'pre-commit': 'jshint jscs',
      }
    },
    'notify_hooks': {
      options: {
        enabled: true,
        'max_jshint_notifications': 5, // maximum number of notifications from jshint output
        success: true, // whether successful grunt executions should be notified automatically
        duration: 3 // the duration of notification in seconds, for `notify-send only
      }
    },
  });

  // Register Grunt Tasks
  grunt.registerTask('default', 'serve');
  grunt.registerTask('buildBootstrapper', function() {
    var stateFiles = grunt.file.expand('game/states/*.js'),
        gameStates = [],
        statePattern = new RegExp(/(\w+).js$/),
        bootstrapper = grunt.file.read('templates/_main.js.tpl');

    stateFiles.forEach(function(file) {
      var state = file.match(statePattern)[1];
      if (!!state) {
        gameStates.push({shortName: state, stateName: _.capitalize(state) + 'State'});
      }
    });
    config.gameStates = gameStates;
    bootstrapper = grunt.template.process(bootstrapper, {data: config});
    grunt.file.write('game/main.js', bootstrapper);
  });
  grunt.registerTask('build', function(dest) {
    grunt.task.run([
      'buildBootstrapper',
      'browserify:' + (dest || 'dist'),
      'uglify:' + (dest || 'dist'),
      'copy:' + (dest || 'dist'),
      'notify_hooks'
    ]);
  });
  grunt.registerTask('serve', function(environment) {
    grunt.task.run([
      'githooks',
      'clean:serve',
      'copy:' + (environment || 'dev'),
      'build:serve',
      'connect:livereload',
      'open',
      'watch'
    ]);
  });
  grunt.registerTask('xwalkBuild', function(environment) {
    grunt.task.run([
      'clean:dist',
      'copy:' + (environment || 'prod'),
      'build:dist',
      'shell:xwalkBuild',
      'notify_hooks'
    ]);
  });
  grunt.registerTask('restartAdb', ['shell:restartAdb']);
  grunt.registerTask('xwalkInstall', function(arch) {
    // arch is x86 (Intel based tablets) or arm (non-Intel)
    grunt.task.run(['shell:xwalkInstall' + (arch || 'arm'), 'notify_hooks']);
  });
  grunt.registerTask('cordovaPlatformsPlugins', function() {
    var pkg = grunt.file.readJSON('package.json');
    if (!pkg.platforms) {
      return grunt.log.error('Platforms not found.');
    }
    _.forEach(pkg.platforms, function (platform) {
      grunt.log.writeln('Installing platform ' + platform);
      shell.exec('cordova platform add ' + platform);
    });
    _.forEach(pkg.plugins, function (plugin) {
      grunt.log.writeln('Installing plugin ' + plugin);
      shell.exec('cordova plugin add ' + plugin);
    });
  });
  grunt.registerTask('cordovaPrepare', function(environment) {
    var tasks = [
      'clean:dist',
      'copy:' + (environment || 'prod'),
      'build:dist',
      'shell:cordovaPrepare',
      'cordovaPlatformsPlugins'
    ];
    if (grunt.option('splashicons')) {
      tasks.push('shell:cordovaSplashIcons');
    }
    grunt.task.run(tasks);
  });
};
<commit_msg>feat(build): adds signing options for xwalk build<commit_after>// Generated on 2014-03-28 using generator-phaser-official 0.0.8-rc-2
'use strict';
var config = require('./config.json'),
    _ = require('underscore'),
    shell = require('shelljs'),
    LIVERELOAD_PORT = 35729,
    lrSnippet = require('connect-livereload')({port: LIVERELOAD_PORT});

_.str = require('underscore.string');
_.mixin(_.str.exports());

function mountFolder(connect, dir) {
  return connect.static(require('path').resolve(dir));
}

module.exports = function (grunt) {
  // load all grunt tasks
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

  grunt.initConfig({
    manifest: grunt.file.readJSON('manifest.json'),
    watch: {
      scripts: {
        files: [
          '!game/main.js',
          'game/**/*',
          'templates/*.tpl',
          'config.json',
          'css/**/*.css'
        ],
        options: {
          spawn: false,
          livereload: LIVERELOAD_PORT
        },
        tasks: ['build:serve']
      }
    },
    connect: {
      options: {
        port: 9000,
        // change this to '0.0.0.0' to access the server from outside
        hostname: 'localhost'
      },
      livereload: {
        options: {
          middleware: function (connect) {
            return [
              lrSnippet,
              mountFolder(connect, 'serve')
            ];
          }
        }
      }
    },
    open: {
      server: {
        path: 'http://localhost:9000'
      }
    },
    copy: {
      serve: {
        files: [
          // includes files within path and its sub-directories
          { expand: true, src: ['assets/**', 'fonts/**', 'css/**'], dest: 'serve/' },
          { expand: true, flatten: true, src: [
            'game/plugins/*{.js,.map}',
            'bower_components/*/build/*{.js,.map}',
            'bower_components/*/dist/*{.js,.map}',
            'game/index.html'
          ], dest: 'serve/' }
        ]
      },
      dist: {
        files: [
          // includes files within path and its sub-directories
          { expand: true, src: [
            'assets/**',
            'fonts/**',
            'css/**',
            'icon.png',
            'manifest.json'
          ], dest: 'dist/' },
          { expand: true, flatten: true, src: [
            'game/plugins/*{.js,.map}',
            'bower_components/*/build/*{.js,.map}',
            'bower_components/*/dist/*{.js,.map}',
            'game/index.html'
          ], dest: 'dist/' }
        ]
      },
      dev: {
        options: {
          process: function(content) {
            return grunt.template.process(content, {
              data: {
                dependencies: [
                  'cordova.js',
                  'phaser.js',
                  'phaser-state-transition-plugin.min.js',
                  'game.js'
                ]
              }
            });
          }
        },
        files: [
          { src: 'game/config/config.dev.json', dest: 'game/config.json' },
          { src: 'templates/_index.html.tpl', dest: 'game/index.html' }
        ]
      },
      prod: {
        options: {
          process: function(content) {
            return grunt.template.process(content, {
              data: {
                dependencies: [
                  'cordova.js',
                  'phaser.js',
                  'phaser-state-transition-plugin.min.js',
                  'game.js'
                ]
              }
            });
          }
        },
        files: [
          { src: 'game/config/config.prod.json', dest: 'game/config.json' },
          { src: 'templates/_index.html.tpl', dest: 'game/index.html' }
        ]
      }
    },
    browserify: {
      serve: {
        src: ['game/main.js'],
        dest: 'serve/game.js'
      },
      dist: {
        src: ['game/main.js'],
        dest: 'dist/game.js'
        // dest: '.cache/game.js'
      }
    },
    // DISABLED
    uglify: {
      dist: {
        // files: {
        //   'dist/game.min.js': ['.cache/game.js']
        // }
      },
      serve: {}
    },
    clean: {
      serve: ['serve'],
      dist: ['dist', 'build'],
    },
    shell: {
      options: {
        stderr: false
      },
      xwalkBuild: {
        command: [
          'python $CROSSWALK_HOME/make_apk.py',
          '--manifest=dist/manifest.json',
          '--package=<%= manifest.package %>',
          '--name=<%= manifest.name %>',
          '--target-dir=build',
          '--mode=' + grunt.option('mode', 'embedded'),
          grunt.option('enable-remote-debugging') ? '--enable-remote-debugging' : '',
          grunt.option('compressor') ? '--compressor=' + grunt.option('compressor', '') : '',
          grunt.option('verbose') ? '--verbose' : '',
          // Options for signing the apk for google play
          grunt.option('keystore-path') ? '--keystore-path=' + grunt.option('keystore-path') : '',
          grunt.option('keystore-alias') ? '--keystore-alias=' + grunt.option('keystore-alias') : '',
          grunt.option('keystore-passcode') ? '--keystore-passcode=' + grunt.option('keystore-passcode') : '',
          grunt.option('keystore-alias-passcode') ? '--keystore-alias-passcode=' + grunt.option('keystore-alias-passcode') : ''
        ].join(' ')
      },
      xwalkInstallx86: {
        command: 'adb install -r build/*_x86.apk'
      },
      xwalkInstallarm: {
        command: 'adb install -r build/*_arm.apk'
      },
      restartAdb: {
        command: [
          'sudo $(which adb) kill-server',
          'sudo $(which adb) start-server',
          'adb devices'
        ].join('&&')
      },
      cordovaPrepare: {
        command: [
          'rm -rf www',
          'cp -a dist www'
        ].join('&&')
      },
      cordovaSplashIcons: {
        command: [
          'cordova-icon',
          'cordova-splash'
        ].join('&&')
      }
    },
    bump: {
      options: {
        files: ['package.json', 'bower.json', 'manifest.json', 'config.xml'],
        updateConfigs: [],
        commit: true,
        commitMessage: 'Release %VERSION%',
        commitFiles: ['package.json', 'bower.json', 'manifest.json', 'config.xml'],
        createTag: false,
        tagName: '%VERSION%',
        tagMessage: 'Version %VERSION%',
        push: false,
        pushTo: 'upstream',
        gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d'
      }
    },
    jshint: {
      all: ['game/**/*.js', 'Gruntfile.js'],
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      }
    },
    jscs: {
      src: [
        'game/**/*.js',
        '!game/main.js',
        '!game/plugins/*'
      ],
      options: {
        config: '.jscsrc',
        reporter: require('jscs-stylish').path
      }
    },
    githooks: {
      all: {
        'pre-commit': 'jshint jscs',
      }
    },
    'notify_hooks': {
      options: {
        enabled: true,
        'max_jshint_notifications': 5, // maximum number of notifications from jshint output
        success: true, // whether successful grunt executions should be notified automatically
        duration: 3 // the duration of notification in seconds, for `notify-send only
      }
    },
  });

  // Register Grunt Tasks
  grunt.registerTask('default', 'serve');
  grunt.registerTask('buildBootstrapper', function() {
    var stateFiles = grunt.file.expand('game/states/*.js'),
        gameStates = [],
        statePattern = new RegExp(/(\w+).js$/),
        bootstrapper = grunt.file.read('templates/_main.js.tpl');

    stateFiles.forEach(function(file) {
      var state = file.match(statePattern)[1];
      if (!!state) {
        gameStates.push({shortName: state, stateName: _.capitalize(state) + 'State'});
      }
    });
    config.gameStates = gameStates;
    bootstrapper = grunt.template.process(bootstrapper, {data: config});
    grunt.file.write('game/main.js', bootstrapper);
  });
  grunt.registerTask('build', function(dest) {
    grunt.task.run([
      'buildBootstrapper',
      'browserify:' + (dest || 'dist'),
      'uglify:' + (dest || 'dist'),
      'copy:' + (dest || 'dist'),
      'notify_hooks'
    ]);
  });
  grunt.registerTask('serve', function(environment) {
    grunt.task.run([
      'githooks',
      'clean:serve',
      'copy:' + (environment || 'dev'),
      'build:serve',
      'connect:livereload',
      'open',
      'watch'
    ]);
  });
  grunt.registerTask('xwalkBuild', function(environment) {
    grunt.task.run([
      'clean:dist',
      'copy:' + (environment || 'prod'),
      'build:dist',
      'shell:xwalkBuild',
      'notify_hooks'
    ]);
  });
  grunt.registerTask('restartAdb', ['shell:restartAdb']);
  grunt.registerTask('xwalkInstall', function(arch) {
    // arch is x86 (Intel based tablets) or arm (non-Intel)
    grunt.task.run(['shell:xwalkInstall' + (arch || 'arm'), 'notify_hooks']);
  });
  grunt.registerTask('cordovaPlatformsPlugins', function() {
    var pkg = grunt.file.readJSON('package.json');
    if (!pkg.platforms) {
      return grunt.log.error('Platforms not found.');
    }
    _.forEach(pkg.platforms, function (platform) {
      grunt.log.writeln('Installing platform ' + platform);
      shell.exec('cordova platform add ' + platform);
    });
    _.forEach(pkg.plugins, function (plugin) {
      grunt.log.writeln('Installing plugin ' + plugin);
      shell.exec('cordova plugin add ' + plugin);
    });
  });
  grunt.registerTask('cordovaPrepare', function(environment) {
    var tasks = [
      'clean:dist',
      'copy:' + (environment || 'prod'),
      'build:dist',
      'shell:cordovaPrepare',
      'cordovaPlatformsPlugins'
    ];
    if (grunt.option('splashicons')) {
      tasks.push('shell:cordovaSplashIcons');
    }
    grunt.task.run(tasks);
  });
};
<|endoftext|>


<commit_before>module.exports = function (grunt) {
  grunt.initConfig({
    uglify: {
      main: {
        files: {
          'ng-stomp.min.js': ['ng-stomp.js']
        }
      }
    },
    jshint: {
      all: ['*.js', '!*.min.js']
    }
  });

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.registerTask('default', ['jshint', 'uglify']);
};<commit_msg>Add task for standalone file (includes dependencies)<commit_after>module.exports = function (grunt) {
  grunt.initConfig({
    uglify: {
      main: {
        options: {
          preserveComments: 'some'
        },
        files: {
          'ng-stomp.min.js': ['ng-stomp.js'],
          'ng-stomp.standalone.min.js': [
            'bower_components/sockjs/sockjs.min.js',
            'bower_components/stomp-websocket/lib/stomp.min.js',
            'bower_components/stompie/stompie-min.js',
            'ng-stomp.js'
          ]
        }
      }
    },
    jshint: {
      all: ['*.js', '!*.min.js']
    }
  });

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.registerTask('default', ['jshint', 'uglify']);
};<|endoftext|>


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

'use strict';

// Include Gulp & tools we'll use
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var runSequence = require('run-sequence');
var browserSync = require('browser-sync');
var pagespeed = require('psi');
var reload = browserSync.reload;
var browserify = require('browserify');
var reactify = require('reactify');
var transform = require('vinyl-transform');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');

var AUTOPREFIXER_BROWSERS = [
  'ie >= 10',
  'ie_mob >= 10',
  'ff >= 30',
  'chrome >= 34',
  'safari >= 7',
  'opera >= 23',
  'ios >= 7',
  'android >= 4.4',
  'bb >= 10'
];

// Lint JavaScript
gulp.task('jshint', function () {
  return gulp.src('app/scripts/**/*.js')
    .pipe(reload({stream: true, once: true}))
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
});

// Optimize images
gulp.task('images', function () {
  return gulp.src('app/images/**/*')
    .pipe($.imagemin({
      progressive: true,
      interlaced: true
    }))
    .pipe(gulp.dest('dist/images'))
    .pipe($.size({title: 'images'}));
});

// Copy all files at the root level (app)
gulp.task('copy', function () {
  return gulp.src([
    'app/*',
    '!app/*.html',
    'node_modules/apache-server-configs/dist/.htaccess'
  ], {
    dot: true
  }).pipe(gulp.dest('dist'))
    .pipe($.size({title: 'copy'}));
});

// Copy web fonts to dist
gulp.task('fonts', function () {
  return gulp.src(['app/fonts/**'])
    .pipe(gulp.dest('dist/fonts'))
    .pipe($.size({title: 'fonts'}));
});

// Compile and automatically prefix stylesheets
gulp.task('styles', function () {
  // For best performance, don't add Sass partials to `gulp.src`
  return gulp.src([
    'app/styles/*.scss',
    'app/styles/**/*.css',
    'app/styles/components/components.scss'
  ])
    .pipe($.sourcemaps.init())
    .pipe($.changed('.tmp/styles', {extension: '.css'}))
    .pipe($.sass({
      precision: 10,
      onError: console.error.bind(console, 'Sass error:')
    }))
    .pipe($.autoprefixer({browsers: AUTOPREFIXER_BROWSERS}))
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest('.tmp/styles'))
    // Concatenate and minify styles
    .pipe($.if('*.css', $.csso()))
    .pipe(gulp.dest('dist/styles'))
    .pipe($.size({title: 'styles'}));
});

// Scan your HTML for assets & optimize them
gulp.task('html', function () {
  var assets = $.useref.assets({searchPath: '{.tmp,app}'});

  return gulp.src('app/**/*.html')
    .pipe(assets)
    // Concatenate and minify JavaScript
    .pipe($.if('*.js', $.uglify({preserveComments: 'some'})))
    // Remove any unused CSS
    // Note: if not using the Style Guide, you can delete it from
    //       the next line to only include styles your project uses.
    .pipe($.if('*.css', $.uncss({
      html: [
        'app/index.html',
        'app/personvern.html'
      ],
      // CSS Selectors for UnCSS to ignore
      ignore: [
        /.navdrawer-container.open/,
        /.app-bar.open/
      ]
    })))
    // Concatenate and minify styles
    // In case you are still using useref build blocks
    .pipe($.if('*.css', $.csso()))
    .pipe(assets.restore())
    .pipe($.useref())
    // Update production Style Guide paths
    .pipe($.replace('components/components.css', 'components/main.min.css'))
    // Minify any HTML
    .pipe($.if('*.html', $.minifyHtml()))
    // Output files
    .pipe(gulp.dest('dist'))
    .pipe($.size({title: 'html'}));
});

//Browserify
gulp.task('browserify', function() {

  var bundler = browserify({
    entries: ['./app/scripts/app.js'],
    debug: true
  });

  var bundle = function() {
    return bundler
      .transform(reactify)
      .bundle()
      .pipe(source('bundle.js'))
      .pipe(buffer())
      .pipe(sourcemaps.init({loadMaps: true}))
      // Add transformation tasks to the pipeline here.
      .pipe(uglify())
      .pipe(sourcemaps.write('./'))
      .pipe(gulp.dest('.tmp/scripts/'))
      .pipe(gulp.dest('./dist/scripts/'));
  };

  return bundle();
});

// Clean output directory
gulp.task('clean', del.bind(null, ['.tmp', 'dist/*', '!dist/.git'], {dot: true}));

// Watch files for changes & reload
gulp.task('serve', ['styles', 'browserify'], function () {
  browserSync({
    notify: false,
    // Customize the BrowserSync console logging prefix
    logPrefix: 'WSK',
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: ['.tmp', 'app']
  });

  gulp.watch(['app/**/*.html'], reload);
  gulp.watch(['app/styles/**/*.{scss,css}'], ['styles', reload]);
  gulp.watch(['app/scripts/**/*.js'], ['browserify', reload]);
  gulp.watch(['elements/**/*.js'], ['browserify', reload]);
  gulp.watch(['app/images/**/*'], reload);
});

// Build and serve the output from the dist build
gulp.task('serve:dist', ['default'], function () {
  browserSync({
    notify: false,
    logPrefix: 'WSK',
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: 'dist'
  });
});

// Build production files, the default task
gulp.task('default', ['clean'], function (cb) {
  runSequence('styles', ['browserify', 'html', 'images', 'fonts', 'copy'], cb);
});

// Run PageSpeed Insights
gulp.task('pagespeed', function (cb) {
  // Update the below URL to the public URL of your site
  pagespeed.output('example.com', {
    strategy: 'mobile'
    // By default we use the PageSpeed Insights free (no API key) tier.
    // Use a Google Developer API key if you have one: http://goo.gl/RkN0vE
    // key: 'YOUR_API_KEY'
  }, cb);
});

// Load custom tasks from the `tasks` directory
// try { require('require-dir')('tasks'); } catch (err) { console.error(err); }
<commit_msg>Adds utils to gulp.watch<commit_after>/**
 *
 *  Web Starter Kit
 *  Copyright 2014 Google Inc. All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License
 *
 */

'use strict';

// Include Gulp & tools we'll use
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var runSequence = require('run-sequence');
var browserSync = require('browser-sync');
var pagespeed = require('psi');
var reload = browserSync.reload;
var browserify = require('browserify');
var reactify = require('reactify');
var transform = require('vinyl-transform');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');

var AUTOPREFIXER_BROWSERS = [
  'ie >= 10',
  'ie_mob >= 10',
  'ff >= 30',
  'chrome >= 34',
  'safari >= 7',
  'opera >= 23',
  'ios >= 7',
  'android >= 4.4',
  'bb >= 10'
];

// Lint JavaScript
gulp.task('jshint', function () {
  return gulp.src('app/scripts/**/*.js')
    .pipe(reload({stream: true, once: true}))
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
});

// Optimize images
gulp.task('images', function () {
  return gulp.src('app/images/**/*')
    .pipe($.imagemin({
      progressive: true,
      interlaced: true
    }))
    .pipe(gulp.dest('dist/images'))
    .pipe($.size({title: 'images'}));
});

// Copy all files at the root level (app)
gulp.task('copy', function () {
  return gulp.src([
    'app/*',
    '!app/*.html',
    'node_modules/apache-server-configs/dist/.htaccess'
  ], {
    dot: true
  }).pipe(gulp.dest('dist'))
    .pipe($.size({title: 'copy'}));
});

// Copy web fonts to dist
gulp.task('fonts', function () {
  return gulp.src(['app/fonts/**'])
    .pipe(gulp.dest('dist/fonts'))
    .pipe($.size({title: 'fonts'}));
});

// Compile and automatically prefix stylesheets
gulp.task('styles', function () {
  // For best performance, don't add Sass partials to `gulp.src`
  return gulp.src([
    'app/styles/*.scss',
    'app/styles/**/*.css',
    'app/styles/components/components.scss'
  ])
    .pipe($.sourcemaps.init())
    .pipe($.changed('.tmp/styles', {extension: '.css'}))
    .pipe($.sass({
      precision: 10,
      onError: console.error.bind(console, 'Sass error:')
    }))
    .pipe($.autoprefixer({browsers: AUTOPREFIXER_BROWSERS}))
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest('.tmp/styles'))
    // Concatenate and minify styles
    .pipe($.if('*.css', $.csso()))
    .pipe(gulp.dest('dist/styles'))
    .pipe($.size({title: 'styles'}));
});

// Scan your HTML for assets & optimize them
gulp.task('html', function () {
  var assets = $.useref.assets({searchPath: '{.tmp,app}'});

  return gulp.src('app/**/*.html')
    .pipe(assets)
    // Concatenate and minify JavaScript
    .pipe($.if('*.js', $.uglify({preserveComments: 'some'})))
    // Remove any unused CSS
    // Note: if not using the Style Guide, you can delete it from
    //       the next line to only include styles your project uses.
    .pipe($.if('*.css', $.uncss({
      html: [
        'app/index.html',
        'app/personvern.html'
      ],
      // CSS Selectors for UnCSS to ignore
      ignore: [
        /.navdrawer-container.open/,
        /.app-bar.open/
      ]
    })))
    // Concatenate and minify styles
    // In case you are still using useref build blocks
    .pipe($.if('*.css', $.csso()))
    .pipe(assets.restore())
    .pipe($.useref())
    // Update production Style Guide paths
    .pipe($.replace('components/components.css', 'components/main.min.css'))
    // Minify any HTML
    .pipe($.if('*.html', $.minifyHtml()))
    // Output files
    .pipe(gulp.dest('dist'))
    .pipe($.size({title: 'html'}));
});

//Browserify
gulp.task('browserify', function() {

  var bundler = browserify({
    entries: ['./app/scripts/app.js'],
    debug: true
  });

  var bundle = function() {
    return bundler
      .transform(reactify)
      .bundle()
      .pipe(source('bundle.js'))
      .pipe(buffer())
      .pipe(sourcemaps.init({loadMaps: true}))
      // Add transformation tasks to the pipeline here.
      .pipe(uglify())
      .pipe(sourcemaps.write('./'))
      .pipe(gulp.dest('.tmp/scripts/'))
      .pipe(gulp.dest('./dist/scripts/'));
  };

  return bundle();
});

// Clean output directory
gulp.task('clean', del.bind(null, ['.tmp', 'dist/*', '!dist/.git'], {dot: true}));

// Watch files for changes & reload
gulp.task('serve', ['styles', 'browserify'], function () {
  browserSync({
    notify: false,
    // Customize the BrowserSync console logging prefix
    logPrefix: 'WSK',
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: ['.tmp', 'app']
  });

  gulp.watch(['app/**/*.html'], reload);
  gulp.watch(['app/styles/**/*.{scss,css}'], ['styles', reload]);
  gulp.watch(['app/scripts/**/*.js'], ['browserify', reload]);
  gulp.watch(['elements/**/*.js'], ['browserify', reload]);
  gulp.watch(['utils/**/*.js'], ['browserify', reload]);
  gulp.watch(['app/images/**/*'], reload);
});

// Build and serve the output from the dist build
gulp.task('serve:dist', ['default'], function () {
  browserSync({
    notify: false,
    logPrefix: 'WSK',
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: 'dist'
  });
});

// Build production files, the default task
gulp.task('default', ['clean'], function (cb) {
  runSequence('styles', ['browserify', 'html', 'images', 'fonts', 'copy'], cb);
});

// Run PageSpeed Insights
gulp.task('pagespeed', function (cb) {
  // Update the below URL to the public URL of your site
  pagespeed.output('example.com', {
    strategy: 'mobile'
    // By default we use the PageSpeed Insights free (no API key) tier.
    // Use a Google Developer API key if you have one: http://goo.gl/RkN0vE
    // key: 'YOUR_API_KEY'
  }, cb);
});

// Load custom tasks from the `tasks` directory
// try { require('require-dir')('tasks'); } catch (err) { console.error(err); }
<|endoftext|>


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

import {LitElement, html} from "lit";
import UtilsNew from "../../../core/utilsNew.js";
import {classMap} from "lit/directives/class-map.js";

/**
 * Token filter. Select2 version with opencga dynamic datasource
 *
 */

export default class SelectTokenFilter extends LitElement {

    constructor() {
        super();
        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            config: {
                type: Object
            },
            value: {
                type: String
            }
        };
    }

    _init() {
        this._prefix = "select-" + UtilsNew.randomString(6) + "_";
        this.separator = ",";
    }

    connectedCallback() {
        super.connectedCallback();
        this._config = {...this.getDefaultConfig(), ...this.config};
        this.state = [];
    }

    firstUpdated() {
        this.select = $("#" + this._prefix);
        this.select.select2({
            tags: this._config.freeTag === true,
            multiple: true,
            width: "style",
            placeholder: this._config.placeholder,
            minimumInputLength: this._config.minimumInputLength,
            ajax: {
                transport: async (params, success, failure) => this._config.source(params, success, failure),
                processResults: (restResponse, params) => {
                    const _params = params;
                    _params.page = _params.page || 1;
                    return {
                        results: this.preprocessResults(restResponse.getResults()),
                        pagination: {
                            more: (_params.page * this._config.limit) < restResponse.getResponse().numMatches
                        }
                    };
                }
            },
            templateResult: item => {
                if (item.loading) {
                    return item.text;
                }
                // NOTE this function silently fails in case of errors if not wrapped in try/catch block
                try {
                    const {name, ...rest} = this._config.fields(item) ?? item.id;
                    return $(`<span>${name}</span> ${(rest ? Object.entries(rest).map(([label, value]) => `
${label} ${value || "-"}
`).join("") : "") }`);
                } catch (e) {
                    console.error(e);
                }
            },
            templateSelection: item => {
                return item.id ?? item.text;
            },
            ...this._config.select2Config
        })
            .on("select2:select", e => {
                this.filterChange(e);
                /* dynamic width. DONE in css */
                /* if (this._config.dynamicWidth) {
                    let width = 200;
                    $(".select2-selection__choice", this).each(function () {
                        const token = $(this);
                        const tokenWidth = token.outerWidth();
                        width += tokenWidth;
                    });
                    console.log("$(this).find(\"span.select2-selection\")", $(this).find("span.select2-selection"))
                    $(this).find("span.select2-selection").css("max-width", width);
                }*/
            })
            .on("select2:unselect", e => {
                this.filterChange(e);
            });

    }

    updated(_changedProperties) {
        if (_changedProperties.has("config")) {
            this._config = {...this.getDefaultConfig(), ...this.config};
        }
        if (_changedProperties.has("value")) {
            /* if (this.value) {
                this.state = this.value.split(",");
            }*/
            this.select.val(null).trigger("change");
            const selection = this.value ? this.value.split(",") : null;
            this.select.val(selection);
            this.select.trigger("change");

            // this.addOptions(this.value?.split(this.separator));
            // const selection = this.value ? this.value.split(this.separator) : null;
            // this.select.val(selection); // this wont work as options arent actually there since there is an ajax source
            // this.select.trigger('change');
            // this.requestUpdate();

        }

    }

    preprocessResults(results) {
        if (results.length) {
            if ("string" === typeof results[0]) {
                return results.map(s => ({id: s}));
            }
        }
        return results;
    }

    /* addOptions(ids) {
        if (ids) {
            for (const id of ids) {
                if (this.select.find("option[value='" + id + "']").length) {
                    this.select.val(id).trigger("change");
                } else {
                    // Create a DOM Option and pre-select by default
                    const newOption = new Option(id, id, true, true);
                    // Append it to the select
                    this.select.append(newOption).trigger("change");
                }
            }
            this.select.trigger("change");
        } else {
            this.select.val(null).trigger("change");

        }

    }*/

    filterChange(e) {
        const selection = this.select.select2("data").map(el => el.id).join(this.separator);
        console.log("filterChange", selection);
        const event = new CustomEvent("filterChange", {
            detail: {
                value: selection
            }
        });
        this.dispatchEvent(event);
    }

    getDefaultConfig() {
        return {
            limit: 10,
            minimumInputLength: 0,
            maxItems: 0,
            placeholder: "Start typing",
            freeTag: false,
            source: () => {
                throw new Error("Data source not defined");
            },
            fields: item => ({
                "name": item.id,
            }),
        };
    }

    render() {
        return html`

            <select class="form-control"  id="${this._prefix}" @change="${this.filterChange}"></select>

        `;
    }

}

customElements.define("select-token-filter", SelectTokenFilter);
<commit_msg>select-token-filter freetag behaviour fixed #165<commit_after>/**
 * Copyright 2015-2019 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "lit";
import UtilsNew from "../../../core/utilsNew.js";
import {classMap} from "lit/directives/class-map.js";

/**
 * Token filter. Select2 version with opencga dynamic datasource
 *
 */

export default class SelectTokenFilter extends LitElement {

    constructor() {
        super();
        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            config: {
                type: Object
            },
            value: {
                type: String
            }
        };
    }

    _init() {
        this._prefix = "select-" + UtilsNew.randomString(6) + "_";
        this.separator = ",";
    }

    connectedCallback() {
        super.connectedCallback();
        this._config = {...this.getDefaultConfig(), ...this.config};
        this.state = [];
    }

    firstUpdated() {
        this.select = $("#" + this._prefix);
        this.select.select2({
            tags: this._config.freeTag === true,
            multiple: true,
            width: "style",
            placeholder: this._config.placeholder,
            minimumInputLength: this._config.minimumInputLength,
            ajax: {
                transport: async (params, success, failure) => this._config.source(params, success, failure),
                processResults: (restResponse, params) => {
                    const _params = params;
                    _params.page = _params.page || 1;
                    return {
                        results: this.preprocessResults(restResponse.getResults()),
                        pagination: {
                            more: (_params.page * this._config.limit) < restResponse.getResponse().numMatches
                        }
                    };
                }
            },
            templateResult: item => {
                if (item.loading) {
                    return item.text;
                }
                // NOTE this function silently fails in case of errors if not wrapped in try/catch block
                try {
                    const {name, ...rest} = this._config.fields(item) ?? item.id;
                    return $(`<span>${name}</span> ${(rest ? Object.entries(rest).map(([label, value]) => `
${label} ${value || "-"}
`).join("") : "") }`);
                } catch (e) {
                    console.error(e);
                }
            },
            templateSelection: item => {
                return item.id ?? item.text;
            },
            ...this._config.select2Config
        })
            .on("select2:select", e => {
                this.filterChange(e);
                /* dynamic width. DONE in css */
                /* if (this._config.dynamicWidth) {
                    let width = 200;
                    $(".select2-selection__choice", this).each(function () {
                        const token = $(this);
                        const tokenWidth = token.outerWidth();
                        width += tokenWidth;
                    });
                    console.log("$(this).find(\"span.select2-selection\")", $(this).find("span.select2-selection"))
                    $(this).find("span.select2-selection").css("max-width", width);
                }*/
            })
            .on("select2:unselect", e => {
                this.filterChange(e);
            });

    }

    updated(_changedProperties) {
        if (_changedProperties.has("config")) {
            this._config = {...this.getDefaultConfig(), ...this.config};
        }
        if (_changedProperties.has("value")) {
            /* if (this.value) {
                this.state = this.value.split(",");
            }*/

            /* this.select.val(null).trigger("change");
            const selection = this.value ? this.value.split(",") : null;
            this.select.val(selection);
            this.select.trigger("change");
            */

            this.select.empty();
            this.addOptions(this.value?.split(this.separator));

            // const selection = this.value ? this.value.split(this.separator) : null;
            // this.select.val(selection); // this wont work as options arent actually there since there is an ajax source
            // this.select.trigger('change');
            // this.requestUpdate();

        }

    }

    preprocessResults(results) {
        if (results.length) {
            if ("string" === typeof results[0]) {
                return results.map(s => ({id: s}));
            }
        }
        return results;
    }

    addOptions(ids) {
        if (ids) {
            for (const id of ids) {
                if (this.select.find("option[value='" + id + "']").length) {
                    this.select.val(id).trigger("change");
                } else {
                    // Create a DOM Option and pre-select by default
                    const newOption = new Option(id, id, true, true);
                    // Append it to the select
                    this.select.append(newOption).trigger("change");
                }
            }
            this.select.trigger("change");
        } else {
            this.select.val(null).trigger("change");

        }
    }

    filterChange(e) {
        const selection = this.select.select2("data").map(el => el.id).join(this.separator);
        console.log("filterChange", selection);
        const event = new CustomEvent("filterChange", {
            detail: {
                value: selection
            }
        });
        this.dispatchEvent(event);
    }

    getDefaultConfig() {
        return {
            limit: 10,
            minimumInputLength: 0,
            maxItems: 0,
            placeholder: "Start typing",
            freeTag: false,
            source: () => {
                throw new Error("Data source not defined");
            },
            fields: item => ({
                "name": item.id,
            }),
        };
    }

    render() {
        return html`

            <select class="form-control"  id="${this._prefix}" @change="${this.filterChange}"></select>

        `;
    }

}

customElements.define("select-token-filter", SelectTokenFilter);
<|endoftext|>


<commit_before>const rx = require('rx');
const pokerEvaluator = require('poker-evaluator');

const Deck = require('./deck');
const ImageHelpers = require('./image-helpers');
const PlayerInteraction = require('./player-interaction');
const Combinations = require('../util/combinations');

class TexasHoldem {
  // Public: Creates a new game instance.
  //
  // slack - An instance of the Slack client
  // messages - An {Observable} representing messages posted to the channel
  // channel - The channel where the game will be played
  // players - The players participating in the game
  constructor(slack, messages, channel, players) {
    this.slack = slack;
    this.messages = messages;
    this.channel = channel;
    this.players = players;

    // Cache the direct message channels for each player as we'll be using
    // them often, and fetching them takes linear time per number of users.
    this.playerDms = {};
    for (let player of this.players) {
      this.playerDms[player.id] = this.slack.getDMByName(player.name);
    }

    this.deck = new Deck();
    this.quitGame = new rx.Subject();
    this.disp = new rx.CompositeDisposable();
  }

  // Public: Starts a new game.
  //
  // Returns nothing
  start() {
    this.disp.add(rx.Observable.return(true)
      .flatMap(() => this.playHand())
      .repeat()
      .takeUntil(this.quitGame)
      .subscribe());
  }

  // Public: Ends the current game immediately and disposes all resources
  // associated with the game.
  //
  // Returns nothing
  quit() {
    this.quitGame.onNext();
    this.disp.dispose();
  }

  // Private: Plays a single hand of hold'em. The sequence goes like this:
  // 1. Clear the board and player hands
  // 2. Shuffle the deck and give players their cards
  // 3. TODO: Do a pre-flop betting round
  // 4. Deal the flop and do a betting round
  // 5. Deal the turn and do a betting round
  // 6. Deal the river and do a final betting round
  // 7. TODO: Decide a winner and send chips their way
  //
  // Returns an {Observable} containing the result of the hand
  playHand() {
    this.board = [];
    this.playerHands = {};

    this.deck.shuffle();
    this.dealPlayerCards();

    let evaluation = () =>
      this.evaluateHands().do((result) => {
        this.channel.send(`${result.winner.name} wins with ${result.handName}, ${result.hand.toString()}`);
      });

    return this.flop().flatMap(() =>
      this.turn().flatMap(() =>
        this.river().flatMap(evaluation)));
  }

  // Private: Deals hole cards to each player in the game. To communicate this
  // to the players, we send them a DM with the text description of the cards.
  // We can't post in channel for obvious reasons.
  //
  // Returns nothing
  dealPlayerCards() {
    for (let player of this.players) {
      let card = this.deck.drawCard();
      this.playerHands[player.id] = [card];
    }

    for (let player of this.players) {
      let card = this.deck.drawCard();
      this.playerHands[player.id].push(card);

      let dm = this.playerDms[player.id];
      dm.send(`Your hand is: ${this.playerHands[player.id]}`);
    }
  }

  // Private: Handles the flop and its subsequent round of betting.
  //
  // Returns an {Observable} sequence of player actions taken during the flop
  flop() {
    let flop = [this.deck.drawCard(), this.deck.drawCard(), this.deck.drawCard()];
    this.board = flop;

    return this.postBoard('flop')
      .flatMap(() => this.doBettingRound());
  }

  // Private: Handles the turn and its subsequent round of betting.
  //
  // Returns an {Observable} sequence of player actions taken during the turn
  turn() {
    this.deck.drawCard(); // Burn one
    let turn = this.deck.drawCard();
    this.board.push(turn);

    return this.postBoard('turn')
      .flatMap(() => this.doBettingRound());
  }

  // Private: Handles the river and its subsequent round of betting.
  //
  // Returns an {Observable} sequence of player actions taken during the river
  river() {
    this.deck.drawCard(); // Burn one
    let river = this.deck.drawCard();
    this.board.push(river);

    return this.postBoard('river')
      .flatMap(() => this.doBettingRound());
  }

  // Private: For each player, create a 7-card hand by combining their hole
  // cards with the board, then pass that to our hand evaluator to get the type
  // of hand and its ranking among types. If it's better than the best hand
  // we've seen so far, assign a winner.
  //
  // Returns an {Observable} with a single value: an object containing the
  // winning player and information about their hand.
  evaluateHands() {
    let bestHand = { handType: 0, handRank: 0 };
    let winner = null;
    let cardArray = null;

    for (let player of this.players) {
      let sevenCardHand = [...this.playerHands[player.id], ...this.board];
      let evalInput = sevenCardHand.map(card => card.toString());
      let currentHand = pokerEvaluator.evalHand(evalInput);

      // TODO: Handle ties
      if (currentHand.handType > bestHand.handType ||
        (currentHand.handType === bestHand.handType && currentHand.handRank > bestHand.handRank)) {
        bestHand = currentHand;
        winner = player;
        cardArray = sevenCardHand;
      }
    }

    return rx.Observable.return({
      winner: winner,
      hand: this.bestFiveCardHand(cardArray),
      handName: bestHand.handName
    });
  }

  // Private: Determines the best possible 5-card hand from a 7-card hand. To
  // do this, we first need to get all the unique 5-card combinations, then
  // have our hand evaluator rank them.
  //
  // Returns an array of five {Card} objects
  bestFiveCardHand(sevenCardHand) {
    let fiveCardHands = Combinations.k_combinations(sevenCardHand, 5);
    let bestHand = { handType: 0, handRank: 0 };
    let cardArray = null;

    for (let fiveCardHand of fiveCardHands) {
      let evalInput = fiveCardHand.map(card => card.toString());
      let currentHand = pokerEvaluator.evalHand(evalInput);

      if (currentHand.handType > bestHand.handType ||
        (currentHand.handType === bestHand.handType && currentHand.handRank > bestHand.handRank)) {
        bestHand = currentHand;
        cardArray = fiveCardHand;
      }
    }

    return cardArray;
  }

  // Private: Creates an image of the cards on board and posts it to the
  // channel using `message.attachments`.
  //
  // round - The name of the round
  //
  // Returns an {Observable} indicating completion
  postBoard(round) {
    return ImageHelpers.createBoardImage(this.board).flatMap((url) => {
      let message = {
        as_user: true,
        token: this.slack.token,
      };

      message.attachments = [{
        title: `Dealing the ${round}:`,
        fallback: this.board.toString(),
        text: this.board.toString(),
        color: "good",
        image_url: url
      }];

      this.channel.postMessage(message);

      // NB: Since we don't have a callback for the message arriving, we're
      // just going to wait a bit before continuing.
      return rx.Observable.timer(500);
    }).take(1);
  }

  // Private: Handles the logic for a round of betting.
  //
  // Returns an {Observable} sequence of actions (e.g, 'check', 'fold') taken
  // by players during the round
  doBettingRound() {
    return rx.Observable.fromArray(this.players)
      .concatMap((player) => PlayerInteraction.getActionForPlayer(this.messages, this.channel, player));
  }
}

module.exports = TexasHoldem;
<commit_msg>Step up the Rx game and make this method actually work for multiple players. We need to use defer to ensure that the sequence doesn't continue until the previous player action is taken, and reduce to turn the resulting sequence into a single array.<commit_after>const rx = require('rx');
const pokerEvaluator = require('poker-evaluator');

const Deck = require('./deck');
const ImageHelpers = require('./image-helpers');
const PlayerInteraction = require('./player-interaction');
const Combinations = require('../util/combinations');

class TexasHoldem {
  // Public: Creates a new game instance.
  //
  // slack - An instance of the Slack client
  // messages - An {Observable} representing messages posted to the channel
  // channel - The channel where the game will be played
  // players - The players participating in the game
  constructor(slack, messages, channel, players) {
    this.slack = slack;
    this.messages = messages;
    this.channel = channel;
    this.players = players;

    // Cache the direct message channels for each player as we'll be using
    // them often, and fetching them takes linear time per number of users.
    this.playerDms = {};
    for (let player of this.players) {
      this.playerDms[player.id] = this.slack.getDMByName(player.name);
    }

    this.deck = new Deck();
    this.quitGame = new rx.Subject();
    this.disp = new rx.CompositeDisposable();
  }

  // Public: Starts a new game.
  //
  // Returns nothing
  start() {
    this.disp.add(rx.Observable.return(true)
      .flatMap(() => this.playHand())
      .repeat()
      .takeUntil(this.quitGame)
      .subscribe());
  }

  // Public: Ends the current game immediately and disposes all resources
  // associated with the game.
  //
  // Returns nothing
  quit() {
    this.quitGame.onNext();
    this.disp.dispose();
  }

  // Private: Plays a single hand of hold'em. The sequence goes like this:
  // 1. Clear the board and player hands
  // 2. Shuffle the deck and give players their cards
  // 3. TODO: Do a pre-flop betting round
  // 4. Deal the flop and do a betting round
  // 5. Deal the turn and do a betting round
  // 6. Deal the river and do a final betting round
  // 7. TODO: Decide a winner and send chips their way
  //
  // Returns an {Observable} containing the result of the hand
  playHand() {
    this.board = [];
    this.playerHands = {};

    this.deck.shuffle();
    this.dealPlayerCards();

    let evaluation = () =>
      this.evaluateHands().do((result) => {
        this.channel.send(`${result.winner.name} wins with ${result.handName}, ${result.hand.toString()}`);
      });

    return this.flop().flatMap(() =>
      this.turn().flatMap(() =>
        this.river().flatMap(evaluation)));
  }

  // Private: Deals hole cards to each player in the game. To communicate this
  // to the players, we send them a DM with the text description of the cards.
  // We can't post in channel for obvious reasons.
  //
  // Returns nothing
  dealPlayerCards() {
    for (let player of this.players) {
      let card = this.deck.drawCard();
      this.playerHands[player.id] = [card];
    }

    for (let player of this.players) {
      let card = this.deck.drawCard();
      this.playerHands[player.id].push(card);

      let dm = this.playerDms[player.id];
      dm.send(`Your hand is: ${this.playerHands[player.id]}`);
    }
  }

  // Private: Handles the flop and its subsequent round of betting.
  //
  // Returns an {Observable} sequence of player actions taken during the flop
  flop() {
    let flop = [this.deck.drawCard(), this.deck.drawCard(), this.deck.drawCard()];
    this.board = flop;

    return this.postBoard('flop')
      .flatMap(() => this.doBettingRound());
  }

  // Private: Handles the turn and its subsequent round of betting.
  //
  // Returns an {Observable} sequence of player actions taken during the turn
  turn() {
    this.deck.drawCard(); // Burn one
    let turn = this.deck.drawCard();
    this.board.push(turn);

    return this.postBoard('turn')
      .flatMap(() => this.doBettingRound());
  }

  // Private: Handles the river and its subsequent round of betting.
  //
  // Returns an {Observable} sequence of player actions taken during the river
  river() {
    this.deck.drawCard(); // Burn one
    let river = this.deck.drawCard();
    this.board.push(river);

    return this.postBoard('river')
      .flatMap(() => this.doBettingRound());
  }

  // Private: For each player, create a 7-card hand by combining their hole
  // cards with the board, then pass that to our hand evaluator to get the type
  // of hand and its ranking among types. If it's better than the best hand
  // we've seen so far, assign a winner.
  //
  // Returns an {Observable} with a single value: an object containing the
  // winning player and information about their hand.
  evaluateHands() {
    let bestHand = { handType: 0, handRank: 0 };
    let winner = null;
    let cardArray = null;

    for (let player of this.players) {
      let sevenCardHand = [...this.playerHands[player.id], ...this.board];
      let evalInput = sevenCardHand.map(card => card.toString());
      let currentHand = pokerEvaluator.evalHand(evalInput);

      // TODO: Handle ties
      if (currentHand.handType > bestHand.handType ||
        (currentHand.handType === bestHand.handType && currentHand.handRank > bestHand.handRank)) {
        bestHand = currentHand;
        winner = player;
        cardArray = sevenCardHand;
      }
    }

    return rx.Observable.return({
      winner: winner,
      hand: this.bestFiveCardHand(cardArray),
      handName: bestHand.handName
    });
  }

  // Private: Determines the best possible 5-card hand from a 7-card hand. To
  // do this, we first need to get all the unique 5-card combinations, then
  // have our hand evaluator rank them.
  //
  // Returns an array of five {Card} objects
  bestFiveCardHand(sevenCardHand) {
    let fiveCardHands = Combinations.k_combinations(sevenCardHand, 5);
    let bestHand = { handType: 0, handRank: 0 };
    let cardArray = null;

    for (let fiveCardHand of fiveCardHands) {
      let evalInput = fiveCardHand.map(card => card.toString());
      let currentHand = pokerEvaluator.evalHand(evalInput);

      if (currentHand.handType > bestHand.handType ||
        (currentHand.handType === bestHand.handType && currentHand.handRank > bestHand.handRank)) {
        bestHand = currentHand;
        cardArray = fiveCardHand;
      }
    }

    return cardArray;
  }

  // Private: Creates an image of the cards on board and posts it to the
  // channel using `message.attachments`.
  //
  // round - The name of the round
  //
  // Returns an {Observable} indicating completion
  postBoard(round) {
    return ImageHelpers.createBoardImage(this.board).flatMap((url) => {
      let message = {
        as_user: true,
        token: this.slack.token,
      };

      message.attachments = [{
        title: `Dealing the ${round}:`,
        fallback: this.board.toString(),
        text: this.board.toString(),
        color: "good",
        image_url: url
      }];

      this.channel.postMessage(message);

      // NB: Since we don't have a callback for the message arriving, we're
      // just going to wait a bit before continuing.
      return rx.Observable.timer(500);
    }).take(1);
  }

  // Private: Handles the logic for a round of betting.
  //
  // Returns an {Observable} sequence of actions (e.g, 'check', 'fold') taken
  // by players during the round
  doBettingRound() {
    return rx.Observable.fromArray(this.playersInHand)
      .concatMap((player) => rx.Observable.defer(() =>
        PlayerInteraction.getActionForPlayer(this.messages, this.channel, player)))
      .reduce((acc, x) => {
        acc.push(x);
        return acc;
      }, [])
      .do((result) => console.log(`Got result: ${JSON.stringify(result)}`));
  }
}

module.exports = TexasHoldem;
<|endoftext|>


<commit_before>import EventEmitter from "wolfy87-eventemitter";
import Queue from "./queue";
import Socket from "./socket";
import {contains, uniqueId} from "./utils";

const DDP_VERSION = "1";
const PUBLIC_EVENTS = [
    // Subscription messages
    "ready", "nosub", "added", "changed", "removed",
    // Method messages
    "result", "updated",
    // Error messages
    "error"
];
const DEFAULT_RECONNECT_INTERVAL = 10000;

export default class DDP extends EventEmitter {

    emit () {
        setTimeout(super.emit.bind(this, ...arguments), 0);
    }

    constructor (options) {

        super();

        this.status = "disconnected";

        // Default `autoConnect` and `autoReconnect` to true
        this.autoConnect = (options.autoConnect !== false);
        this.autoReconnect = (options.autoReconnect !== false);
        this.reconnectInterval = options.reconnectInterval || DEFAULT_RECONNECT_INTERVAL;

        this.messageQueue = new Queue(message => {
            if (this.status === "connected") {
                this.socket.send(message);
                return true;
            } else {
                return false;
            }
        });

        this.socket = new Socket(options.SocketConstructor, options.endpoint);

        this.socket.on("open", () => {
            // When the socket opens, send the `connect` message
            // to establish the DDP connection
            this.socket.send({
                msg: "connect",
                version: DDP_VERSION,
                support: [DDP_VERSION]
            });
        });

        this.socket.on("close", () => {
            this.status = "disconnected";
            this.messageQueue.empty();
            this.emit("disconnected");
            if (this.autoReconnect) {
                // Schedule a reconnection
                setTimeout(
                    this.socket.open.bind(this.socket),
                    this.reconnectInterval
                );
            }
        });

        this.socket.on("message:in", message => {
            if (message.msg === "connected") {
                this.status = "connected";
                this.messageQueue.process();
                this.emit("connected");
            } else if (message.msg === "ping") {
                // Reply with a `pong` message to prevent the server from
                // closing the connection
                this.socket.send({msg: "pong", id: message.id});
            } else if (contains(PUBLIC_EVENTS, message.msg)) {
                this.emit(message.msg, message);
            }
        });

        if (this.autoConnect) {
            this.connect();
        }

    }

    connect () {
        this.socket.open();
    }

    disconnect () {
        /*
        *   If `disconnect` is called, the caller likely doesn't want the
        *   the instance to try to auto-reconnect. Therefore we set the
        *   `autoReconnect` flag to false.
        */
        this.autoReconnect = false;
        this.socket.close();
    }

    method (name, params) {
        const id = uniqueId();
        this.messageQueue.push({
            msg: "method",
            id: id,
            method: name,
            params: params
        });
        return id;
    }

    sub (name, params) {
        const id = uniqueId();
        this.messageQueue.push({
            msg: "sub",
            id: id,
            name: name,
            params: params
        });
        return id;
    }

    unsub (id) {
        this.messageQueue.push({
            msg: "unsub",
            id: id
        });
        return id;
    }

}
<commit_msg>allow subscription id to be specified<commit_after>import EventEmitter from "wolfy87-eventemitter";
import Queue from "./queue";
import Socket from "./socket";
import {contains, uniqueId} from "./utils";

const DDP_VERSION = "1";
const PUBLIC_EVENTS = [
    // Subscription messages
    "ready", "nosub", "added", "changed", "removed",
    // Method messages
    "result", "updated",
    // Error messages
    "error"
];
const DEFAULT_RECONNECT_INTERVAL = 10000;

export default class DDP extends EventEmitter {

    emit () {
        setTimeout(super.emit.bind(this, ...arguments), 0);
    }

    constructor (options) {

        super();

        this.status = "disconnected";

        // Default `autoConnect` and `autoReconnect` to true
        this.autoConnect = (options.autoConnect !== false);
        this.autoReconnect = (options.autoReconnect !== false);
        this.reconnectInterval = options.reconnectInterval || DEFAULT_RECONNECT_INTERVAL;

        this.messageQueue = new Queue(message => {
            if (this.status === "connected") {
                this.socket.send(message);
                return true;
            } else {
                return false;
            }
        });

        this.socket = new Socket(options.SocketConstructor, options.endpoint);

        this.socket.on("open", () => {
            // When the socket opens, send the `connect` message
            // to establish the DDP connection
            this.socket.send({
                msg: "connect",
                version: DDP_VERSION,
                support: [DDP_VERSION]
            });
        });

        this.socket.on("close", () => {
            this.status = "disconnected";
            this.messageQueue.empty();
            this.emit("disconnected");
            if (this.autoReconnect) {
                // Schedule a reconnection
                setTimeout(
                    this.socket.open.bind(this.socket),
                    this.reconnectInterval
                );
            }
        });

        this.socket.on("message:in", message => {
            if (message.msg === "connected") {
                this.status = "connected";
                this.messageQueue.process();
                this.emit("connected");
            } else if (message.msg === "ping") {
                // Reply with a `pong` message to prevent the server from
                // closing the connection
                this.socket.send({msg: "pong", id: message.id});
            } else if (contains(PUBLIC_EVENTS, message.msg)) {
                this.emit(message.msg, message);
            }
        });

        if (this.autoConnect) {
            this.connect();
        }

    }

    connect () {
        this.socket.open();
    }

    disconnect () {
        /*
        *   If `disconnect` is called, the caller likely doesn't want the
        *   the instance to try to auto-reconnect. Therefore we set the
        *   `autoReconnect` flag to false.
        */
        this.autoReconnect = false;
        this.socket.close();
    }

    method (name, params) {
        const id = uniqueId();
        this.messageQueue.push({
            msg: "method",
            id: id,
            method: name,
            params: params
        });
        return id;
    }

    sub (name, params, id = null) {
        id || (id = uniqueId());
        this.messageQueue.push({
            msg: "sub",
            id: id,
            name: name,
            params: params
        });
        return id;
    }

    unsub (id) {
        this.messageQueue.push({
            msg: "unsub",
            id: id
        });
        return id;
    }

}
<|endoftext|>


<commit_before>/**
 * Peento Application
 *
 * @author Zongmin Lei <leizongmin@gmail.com>
 */

var fs = require('fs');
var path = require('path');
var async = require('async');
var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('cookie-session');
var morgan = require('morgan');
var serveStatic = require('serve-static');
var timeout = require('connect-timeout');
var rd = require('rd');
var expressLiquid = require('express-liquid');
var createNamespace = require('lei-ns').Namespace;
var MySQLPool = require('lei-mysql');
var MySQLModel = require('lei-mysql-model');
var Pipe = require('lei-pipe');
var FileLookup = require('file-lookup');
var errorhandler = require('./middleware/errorhandler');
var assetsMiddleware = require('./middleware/assets');
var csrfMiddleware = require('./middleware/csrf');
var multipartyMiddleware = require('./middleware/multiparty');
var utils = require('./lib/utils');
var Plugin = require('./lib/plugin');
var createDebug = require('./lib/debug');
var defaultConfig = require('./lib/default_config');
var debug = require('./lib/debug')('app');

function warning (str) {
  console.error('Warning: ' + str);
}

module.exports = function (config) {
  return new PeentoApplication(config);
};

function PeentoApplication (config) {
  debug('new');

  // fill default config
  config = utils.merge(defaultConfig, config || {});

  // init global namespace
  var ns = this.ns = createNamespace();
  ns('app', this);
  ns('config', config);
  ns('utils', utils);
  ns('debug', createDebug);
  ns('middleware.csrf', csrfMiddleware(ns, debug));
  ns('middleware.multiparty', multipartyMiddleware(ns, debug));
  this._is_debug = !!config.debug;
  this._fileLookup = {
    view:  new FileLookup(),
    asset: new FileLookup()
  };

  // init express
  var app = this.express = express();
  app.use(morgan());
  app.use(bodyParser());
  app.use(express.query());
  app.use(cookieParser(config.cookie.secret));
  app.use(session({
    keys: [config.session.secret]
  }));
  app.use('/assets', assetsMiddleware(ns));
  app.use(timeout(config.request.timeout));

  this._initTpl();
}

PeentoApplication.prototype.listen = function (port) {
  debug('listen %s', port);
  this.express.listen(port);
};

PeentoApplication.prototype.start = function () {
  debug('start');
  this._initDb();
  this._initPlugins();
  this._initFilters();
  this.express.use(errorhandler());
  this.listen(this.ns('config.port'));
};

/******************************************************************************/

PeentoApplication.prototype._usePlugin = function (name, fn) {
  var ns = this.ns;
  var plugin = new Plugin(name, ns);
  ns('plugin.' + name, plugin);
  fn(ns, plugin, plugin.debug);

  if (!Array.isArray(this._plugins)) this._plugins = [];
  this._plugins.push(plugin);

  this._fileLookup.asset.add(path.resolve(plugin.dir, 'asset'));
  this._fileLookup.view.add(path.resolve(plugin.dir, 'view'));
}

PeentoApplication.prototype.use = function (name) {
  var errs = [];
  var m;

  if (typeof name === 'function') {
    m = name;
    name = utils.randomString(8);
  }

  // try to load from working path: ./name
  if (!m) {
    try {
      m = require(path.resolve(name));
    } catch (err) {
      errs.push(err);
    }
  }

  // try to load from package "peento-xxx"
  if (!m) {
    try {
      var n = 'peento-' + name;
      m = require(n);
    } catch (err) {
      errs.push(err);
    }
  }

  if (typeof m !== 'function') {
    throw new Error('Plugin ' + name + ' not found');
  }

  this._usePlugin(name, m);
};

PeentoApplication.prototype._initPlugins = function () {
  debug('_initPlugins');
  if (Array.isArray(this._plugins)) {
    this._plugins.forEach(function (plugin) {
      plugin.init();
    });
  } else {
    warning('no plugin was loaded.');
  }
};

/******************************************************************************/

PeentoApplication.prototype._initTpl = function () {
  debug('_initTpl');
  var me = this;
  var ns = this.ns;
  var app = this.express;

  var baseContext = this.context = expressLiquid.newContext();
  var renderLiquid = this.renderLiquid = expressLiquid({
    context: baseContext,
    resolveFilename: function (name, settings) {
      var ext = path.extname(name);
      if (!ext) name += '.liquid';
      return name;
    },
    includeFile: function (name, callback) {
      var views = ns('view');
      if (name[0] === '/') name = name.slice(1);
      var f = views[name];
      // if is debug mode, try to lookup from view paths
      if (!f && me._is_debug) {
        f = me._fileLookup.view.resolveSync(name);
      }
      // view not found
      if (!f) f = views['view_not_found.liquid'];
      debug('resolve view: [%s] %s', name, f);

      // read file
      fs.readFile(f, {encoding: 'utf8'}, function (err, tpl) {
        if (err) return callback(err);
        callback(null, '{% assign _view_name="' + name.slice(0, -7) + '" %}' + tpl)
      });
    },
    traceError: me._is_debug
  });

  app.use(function (req, res, next) {
    res.context = expressLiquid.newContext();
    res._render = res.render;

    res.render = function (tpl) {
      debug('render: %s', tpl);

      res.context.setLocals('_server', {
        query:  req.query,
        body:   req.body,
        params: req.params,
        session: req.session
      });
      res.context.setLocals('_config', ns('config'));

      renderLiquid(tpl, {
        context:    res.context,
        cache:      !me._is_debug,
        settings:   {}
      }, function (err, html) {
        if (err) return next(err);
        res.header('content-type', 'text/html');
        res.end(html);
      });
    };

    res.setLocals = function (n, v) {
      return res.context.setLocals(n, v);
    };

    next();
  });
};

PeentoApplication.prototype._initFilters = function () {
  debug('_initFilters');
  var ns = this.ns;
  var baseContext = this.context;
  var filters = ns('filter');
  for (var i in filters) {
    if (i.substr(-5) === 'Async') {
      baseContext.setAsyncFilter(i.substr(0, i.length - 5), filters[i]);
    } else {
      baseContext.setFilter(i, filters[i]);
    }
  }
};

PeentoApplication.prototype._initDb = function () {
  debug('_initDb');
  var ns = this.ns;
  var db = new MySQLPool(ns('config.mysql'));
  this.db = db;
  ns('db', db);

  var debugSql = createDebug('db:query');
  db.use('sql', function (sql, next) {
    debugSql(sql);
    next(null, sql);
  });
};

/******************************************************************************/

PeentoApplication.prototype._getCallPipe = function (name) {
  this._callPipes = this._callPipes || {};
  this._callPipes[name] = this._callPipes[name] || new Pipe();
  return this._callPipes[name];
};

PeentoApplication.prototype.call = function (name, params, callback) {
  var me = this;
  var ns = me.ns;

  var call = ns('call.' + name);
  if (typeof call !== 'function') {
    return callback(new TypeError('Cannot call ' + name));
  }

  async.series([

    // before.xxxx
    function (next) {
      debug('call: before %s', name);
      var before = me._getCallPipe('before.' + name);
      before.start(params, function (err, data) {
        params = data;
        next(err);
      });
    },

    // xxxx
    function (next) {
      debug('call: %s', name);
      call(params, function (err, data) {
        params = data;
        next(err);
      });
    },

    // after.xxx
    function (next) {
      debug('call: after %s', name);
      var after = me._getCallPipe('after.' + name);
      after.start(params, function (err, data) {
        params = data;
        next(err);
      });
    }

  ], function (err) {
    callback(err, params);
  });
};
<commit_msg>app继承EventEmitter<commit_after>/**
 * Peento Application
 *
 * @author Zongmin Lei <leizongmin@gmail.com>
 */

var fs = require('fs');
var path = require('path');
var events = require('events');
var util = require('util');
var async = require('async');
var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('cookie-session');
var morgan = require('morgan');
var serveStatic = require('serve-static');
var timeout = require('connect-timeout');
var rd = require('rd');
var expressLiquid = require('express-liquid');
var createNamespace = require('lei-ns').Namespace;
var MySQLPool = require('lei-mysql');
var MySQLModel = require('lei-mysql-model');
var Pipe = require('lei-pipe');
var FileLookup = require('file-lookup');
var errorhandler = require('./middleware/errorhandler');
var assetsMiddleware = require('./middleware/assets');
var csrfMiddleware = require('./middleware/csrf');
var multipartyMiddleware = require('./middleware/multiparty');
var utils = require('./lib/utils');
var Plugin = require('./lib/plugin');
var createDebug = require('./lib/debug');
var defaultConfig = require('./lib/default_config');
var debug = require('./lib/debug')('app');

function warning (str) {
  console.error('Warning: ' + str);
}

module.exports = function (config) {
  return new PeentoApplication(config);
};

function PeentoApplication (config) {
  debug('new');

  // fill default config
  config = utils.merge(defaultConfig, config || {});

  // init global namespace
  var ns = this.ns = createNamespace();
  ns('app', this);
  ns('config', config);
  ns('utils', utils);
  ns('debug', createDebug);
  ns('middleware.csrf', csrfMiddleware(ns, debug));
  ns('middleware.multiparty', multipartyMiddleware(ns, debug));
  this._is_debug = !!config.debug;
  this._fileLookup = {
    view:  new FileLookup(),
    asset: new FileLookup()
  };

  // init express
  var app = this.express = express();
  app.use(morgan());
  app.use(bodyParser());
  app.use(express.query());
  app.use(cookieParser(config.cookie.secret));
  app.use(session({
    keys: [config.session.secret]
  }));
  app.use('/assets', assetsMiddleware(ns));
  app.use(timeout(config.request.timeout));

  this._initTpl();
}
util.inherits(PeentoApplication, events.EventEmitter);

PeentoApplication.prototype.listen = function (port) {
  debug('listen %s', port);
  this.express.listen(port);
};

PeentoApplication.prototype.start = function () {
  debug('start');
  this._initDb();
  this._initPlugins();
  this._initFilters();
  this.express.use(errorhandler());
  this.listen(this.ns('config.port'));
};

/******************************************************************************/

PeentoApplication.prototype._usePlugin = function (name, fn) {
  var ns = this.ns;
  var plugin = new Plugin(name, ns);
  ns('plugin.' + name, plugin);
  fn(ns, plugin, plugin.debug);

  if (!Array.isArray(this._plugins)) this._plugins = [];
  this._plugins.push(plugin);

  this._fileLookup.asset.add(path.resolve(plugin.dir, 'asset'));
  this._fileLookup.view.add(path.resolve(plugin.dir, 'view'));
}

PeentoApplication.prototype.use = function (name) {
  var errs = [];
  var m;

  if (typeof name === 'function') {
    m = name;
    name = utils.randomString(8);
  }

  // try to load from working path: ./name
  if (!m) {
    try {
      m = require(path.resolve(name));
    } catch (err) {
      errs.push(err);
    }
  }

  // try to load from package "peento-xxx"
  if (!m) {
    try {
      var n = 'peento-' + name;
      m = require(n);
    } catch (err) {
      errs.push(err);
    }
  }

  if (typeof m !== 'function') {
    throw new Error('Plugin ' + name + ' not found');
  }

  this._usePlugin(name, m);
};

PeentoApplication.prototype._initPlugins = function () {
  debug('_initPlugins');
  if (Array.isArray(this._plugins)) {
    this._plugins.forEach(function (plugin) {
      plugin.init();
    });
  } else {
    warning('no plugin was loaded.');
  }
};

/******************************************************************************/

PeentoApplication.prototype._initTpl = function () {
  debug('_initTpl');
  var me = this;
  var ns = this.ns;
  var app = this.express;

  var baseContext = this.context = expressLiquid.newContext();
  var renderLiquid = this.renderLiquid = expressLiquid({
    context: baseContext,
    resolveFilename: function (name, settings) {
      var ext = path.extname(name);
      if (!ext) name += '.liquid';
      return name;
    },
    includeFile: function (name, callback) {
      var views = ns('view');
      if (name[0] === '/') name = name.slice(1);
      var f = views[name];
      // if is debug mode, try to lookup from view paths
      if (!f && me._is_debug) {
        f = me._fileLookup.view.resolveSync(name);
      }
      // view not found
      if (!f) f = views['view_not_found.liquid'];
      debug('resolve view: [%s] %s', name, f);

      // read file
      fs.readFile(f, {encoding: 'utf8'}, function (err, tpl) {
        if (err) return callback(err);
        callback(null, '{% assign _view_name="' + name.slice(0, -7) + '" %}' + tpl)
      });
    },
    traceError: me._is_debug
  });

  app.use(function (req, res, next) {
    res.context = expressLiquid.newContext();
    res._render = res.render;

    res.render = function (tpl) {
      debug('render: %s', tpl);

      res.context.setLocals('_server', {
        query:  req.query,
        body:   req.body,
        params: req.params,
        session: req.session
      });
      res.context.setLocals('_config', ns('config'));

      renderLiquid(tpl, {
        context:    res.context,
        cache:      !me._is_debug,
        settings:   {}
      }, function (err, html) {
        if (err) return next(err);
        res.header('content-type', 'text/html');
        res.end(html);
      });
    };

    res.setLocals = function (n, v) {
      return res.context.setLocals(n, v);
    };

    next();
  });
};

PeentoApplication.prototype._initFilters = function () {
  debug('_initFilters');
  var ns = this.ns;
  var baseContext = this.context;
  var filters = ns('filter');
  for (var i in filters) {
    if (i.substr(-5) === 'Async') {
      baseContext.setAsyncFilter(i.substr(0, i.length - 5), filters[i]);
    } else {
      baseContext.setFilter(i, filters[i]);
    }
  }
};

PeentoApplication.prototype._initDb = function () {
  debug('_initDb');
  var ns = this.ns;
  var db = new MySQLPool(ns('config.mysql'));
  this.db = db;
  ns('db', db);

  var debugSql = createDebug('db:query');
  db.use('sql', function (sql, next) {
    debugSql(sql);
    next(null, sql);
  });
};

/******************************************************************************/

PeentoApplication.prototype._getCallPipe = function (name) {
  this._callPipes = this._callPipes || {};
  this._callPipes[name] = this._callPipes[name] || new Pipe();
  return this._callPipes[name];
};

PeentoApplication.prototype.call = function (name, params, callback) {
  var me = this;
  var ns = me.ns;

  var call = ns('call.' + name);
  if (typeof call !== 'function') {
    return callback(new TypeError('Cannot call ' + name));
  }

  async.series([

    // before.xxxx
    function (next) {
      debug('call: before %s', name);
      var before = me._getCallPipe('before.' + name);
      before.start(params, function (err, data) {
        params = data;
        next(err);
      });
    },

    // xxxx
    function (next) {
      debug('call: %s', name);
      call(params, function (err, data) {
        params = data;
        next(err);
      });
    },

    // after.xxx
    function (next) {
      debug('call: after %s', name);
      var after = me._getCallPipe('after.' + name);
      after.start(params, function (err, data) {
        params = data;
        next(err);
      });
    }

  ], function (err) {
    callback(err, params);
  });
};
<|endoftext|>


<commit_before>import React from 'react';
import { Navigator, Platform, BackAndroid } from 'react-native';
import { Provider } from 'react-redux';
import configureStore from './store';
import router from './router';

export default class App extends React.Component {

    componentDidMount() {
        BackAndroid.addEventListener('hardwareBackPress', () => {
            if (this.navigator && this.navigator.getCurrentRoutes().length > 1) {
                this.navigator.pop();
                return true;
            }
            return false;
        });
    }

    renderScene(route, navigator) {
        return router(`${Platform.OS}-${route}`, navigator);
    }

    render() {
        const store = configureStore();
        return (
            <Provider store={store}>
                <Navigator
                    store={store}
                    ref={ref => { this.navigator = ref; }}
                    initialRoute={{}}
                    renderScene={this.renderScene}
                    configureScene={() => (Platform.OS === 'ios') ?
                        Navigator.SceneConfigs.PushFromRight :
                        Navigator.SceneConfigs.FloatFromBottomAndroid
                    }
                />
            </Provider>
        );
    }

}<commit_msg>Adding statusbar color to Android<commit_after>import React from 'react';
import { Navigator, Platform, BackAndroid, StatusBar, View } from 'react-native';
import { Provider } from 'react-redux';
import configureStore from './store';
import router from './router';
import Theme from './theme';

export default class App extends React.Component {

    componentDidMount() {
        BackAndroid.addEventListener('hardwareBackPress', () => {
            if (this.navigator && this.navigator.getCurrentRoutes().length > 1) {
                this.navigator.pop();
                return true;
            }
            return false;
        });
    }

    renderScene(route, navigator) {
        return router(`${Platform.OS}-${route}`, navigator);
    }

    render() {
        const store = configureStore();
        return (
            <Provider store={store}>
                <View style={{ flex: 1 }}>
                    <StatusBar
                        translucent={false}
                        backgroundColor={Theme.statusBarColor}
                        barStyle={Theme.statusBarStyle}
                    />
                    <Navigator
                        store={store}
                        ref={ref => { this.navigator = ref; }}
                        initialRoute={{}}
                        renderScene={this.renderScene}
                        configureScene={() => (Platform.OS === 'ios') ?
                            Navigator.SceneConfigs.PushFromRight :
                            Navigator.SceneConfigs.FloatFromBottomAndroid
                        }
                    />
                </View>
            </Provider>
        );
    }

}<|endoftext|>


<commit_before>/**
 * @copyright 2014 NetEase SDC
 * @author Su Su <gzsusu@corp.netease.com>
 */

module.exports = function(grunt) {
  'use strict';

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    jsonlint: {
      src: ['*.json', 'lib/**/*.json', 'test/**/*.json']
    },
    jscs: {
      src: ['*.js', 'lib/**/*.js', 'test/*.js', 'test/**/*.js'],
      options: {
        config: '.jscs.json'
      }
    },
    jshint: {
      options: {
        jshintrc: true
      },
      src: {
        files: {
          src: ['*.js', 'lib/**/*.js', 'test/**/*.js']
        }
      }
    },
    mochaTest: {
      options: {
        reporter: 'spec',
        clearRequireCache: true
      },
      service: {
        src: ['test/*.js']
      }
    }
  });

  grunt.loadNpmTasks('grunt-jsonlint');
  grunt.loadNpmTasks('grunt-jscs');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-mocha-test');

  // Default task(s).
  grunt.registerTask('default', [
    'jsonlint',
    'jscs',
    'jshint:src',
    'mochaTest:service'
  ]);

  grunt.registerTask('test', [
    'mochaTest:service'
  ]);

};
<commit_msg>Correct info.<commit_after>/**
 * @copyright 2014 Su Su
 * @author Su Su <s@warmsea.net>
 */

module.exports = function(grunt) {
  'use strict';

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    jsonlint: {
      src: ['*.json', 'lib/**/*.json', 'test/**/*.json']
    },
    jscs: {
      src: ['*.js', 'lib/**/*.js', 'test/*.js', 'test/**/*.js'],
      options: {
        config: '.jscs.json'
      }
    },
    jshint: {
      options: {
        jshintrc: true
      },
      src: {
        files: {
          src: ['*.js', 'lib/**/*.js', 'test/**/*.js']
        }
      }
    },
    mochaTest: {
      options: {
        reporter: 'spec',
        clearRequireCache: true
      },
      service: {
        src: ['test/*.js']
      }
    }
  });

  grunt.loadNpmTasks('grunt-jsonlint');
  grunt.loadNpmTasks('grunt-jscs');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-mocha-test');

  // Default task(s).
  grunt.registerTask('default', [
    'jsonlint',
    'jscs',
    'jshint:src',
    'mochaTest:service'
  ]);

  grunt.registerTask('test', [
    'mochaTest:service'
  ]);

};
<|endoftext|>


<commit_before>const _ = require('lodash/fp');
const args = require('yargs').argv;
const fs = require('fs');
const gulp = require('gulp');
const gulpDebugger = require('gulp-debug');
const gutil = require('gulp-util');
const path = require('path');
const proc = require('child_process');
const usage = require('gulp-help-doc');

var paths = {
  bin: {
    prefix: 'src/Raven.Assure/bin',
    environment: 'Release',
    target: 'net46',
    files: '**/*'
  },
  package: 'package'
};

gulp.task('help', () => usage(gulp));

/**
 * Build/compile Raven.Assure.
 * Same as `dotnet build ./src/Raven.Assure/`.
 *
 * @task {build}
 */
gulp.task('build', function buildRavenAssure(done) {
   var buildProcess = proc
      .spawn('dotnet', ['build'], {
         cwd: path.join('src', 'Raven.Assure')
      });

   buildProcess.stdout.on('data', logDatar);
   buildProcess.stderr.on('data', logError);
   buildProcess.on('close', done);
});

/**
 * This is an annoying task because dotnet project.json doesn't support
 * [cross-project content copying](https://github.com/dotnet/cli/issues/753).
 */
gulp.task('copyConfigs', function copyConfigs() {
   var configPath = path.join('src', 'Raven.Assure', 'bin', 'Debug', 'net46', 'win7-x64', 'config');
   var configs =  '{default,test.qa}.json';

   return gulp.src(path.join(configPath, configs))
      .pipe(gulpDebugger({ title: 'from:' }))
      .pipe(gulp.dest(path.join('test', 'Raven.Assure.Test', 'bin', 'Debug', 'net46', 'win7-x64', 'config')))
      .pipe(gulpDebugger({ title: 'to:' }))
      .on('error', logError);
});

/**
 * Run Raven.Assure.Test xUnit tests.
 * Same as `dotnet test ./test/Raven.Assure.Test/`.
 *
 * @task {test}
 */
gulp.task('test', ['copyConfigs'], function testRavenAssure(done) {
   var testProcess = proc
      .spawn('dotnet', ['test'], {
         cwd: path.join('test', 'Raven.Assure.Test')
      });

   testProcess.stdout.on('data', logDatar);
   testProcess.stderr.on('data', logError);
   testProcess.on('close', done);
});

/**
 * [WIP] Not working! Bump the version.
 * @task {bump}
 */
gulp.task('bump', function bumpVersion(done) {
   debugger;
   try {
      var bumpProcess = proc.spawn('bump', ['--prompt'], {
         cwd: path.join('node_modules', 'version-bump-prompt', 'bin')
      });
   }
   catch (error) {
      console.log('error', error);
   }

   bumpProcess.stdout.on('data', logDatar);
   bumpProcess.stderr.on('data', logError);
   bumpProcess.on('error', logError);
   bumpProcess.on('close', done);
});

/**
 * Package Raven.Assure CLI into ./package/{target}/smuggle-{version}-{environment}.
 * @task {package}
 * @arg {environment} The build environment: {Debug|Release(default)}
 *
 * TODO: add branch to package output folder name, like with mobile.
 */
gulp.task('package', ['build'], function packageRavenAssure(done) {
  const smugglePackage = getPackageJson();
  var env = args.environment || paths.bin.environment;
  var fullPackagePath = path.join(paths.package, paths.bin.target, `smuggle-${smugglePackage.version}-${env}`);
  var fullBinPath = path.join(paths.bin.prefix, env, paths.bin.target, paths.bin.files);

  gutil.log('Packaging from:', gutil.colors.cyan(fullBinPath));
  gutil.log('Packaging into:', gutil.colors.cyan(fullPackagePath));

  gulp.src(fullBinPath)
      .pipe(gulp.dest(fullPackagePath));
});

// Define reusable loggers.
var toString = (msg) => msg.toString();
// dotnet CLI adds line break, so when combined with log it adds an additional empty line.
// This replaces that line break with an empty string.
var removeLineBreaks = (msg) => msg.replace(/(\r\n|\r|\n)/g, '');
var logDatar = _.flow(toString, removeLineBreaks, gutil.log);
var logError = _.flow(gutil.colors.red, logDatar);

var getPackageJson = () => JSON.parse(fs.readFileSync('./package.json', 'utf8'));
<commit_msg>Fix package name from smuggle to assure and --env alias<commit_after>const _ = require('lodash/fp');
const args = require('yargs').argv;
const fs = require('fs');
const gulp = require('gulp');
const gulpDebugger = require('gulp-debug');
const gutil = require('gulp-util');
const path = require('path');
const proc = require('child_process');
const usage = require('gulp-help-doc');

var paths = {
  bin: {
    prefix: 'src/Raven.Assure/bin',
    environment: 'Release',
    target: 'net46',
    files: '**/*'
  },
  package: 'package'
};

gulp.task('help', () => usage(gulp));

/**
 * Build/compile Raven.Assure.
 * Same as `dotnet build ./src/Raven.Assure/`.
 *
 * @task {build}
 */
gulp.task('build', function buildRavenAssure(done) {
   var buildProcess = proc
      .spawn('dotnet', ['build'], {
         cwd: path.join('src', 'Raven.Assure')
      });

   buildProcess.stdout.on('data', logDatar);
   buildProcess.stderr.on('data', logError);
   buildProcess.on('close', done);
});

/**
 * This is an annoying task because dotnet project.json doesn't support
 * [cross-project content copying](https://github.com/dotnet/cli/issues/753).
 */
gulp.task('copyConfigs', function copyConfigs() {
   var configPath = path.join('src', 'Raven.Assure', 'bin', 'Debug', 'net46', 'win7-x64', 'config');
   var configs =  '{default,test.qa}.json';

   return gulp.src(path.join(configPath, configs))
      .pipe(gulpDebugger({ title: 'from:' }))
      .pipe(gulp.dest(path.join('test', 'Raven.Assure.Test', 'bin', 'Debug', 'net46', 'win7-x64', 'config')))
      .pipe(gulpDebugger({ title: 'to:' }))
      .on('error', logError);
});

/**
 * Run Raven.Assure.Test xUnit tests.
 * Same as `dotnet test ./test/Raven.Assure.Test/`.
 *
 * @task {test}
 */
gulp.task('test', ['copyConfigs'], function testRavenAssure(done) {
   var testProcess = proc
      .spawn('dotnet', ['test'], {
         cwd: path.join('test', 'Raven.Assure.Test')
      });

   testProcess.stdout.on('data', logDatar);
   testProcess.stderr.on('data', logError);
   testProcess.on('close', done);
});

/**
 * [WIP] Not working! Bump the version.
 * @task {bump}
 */
gulp.task('bump', function bumpVersion(done) {
   debugger;
   try {
      var bumpProcess = proc.spawn('bump', ['--prompt'], {
         cwd: path.join('node_modules', 'version-bump-prompt', 'bin')
      });
   }
   catch (error) {
      console.log('error', error);
   }

   bumpProcess.stdout.on('data', logDatar);
   bumpProcess.stderr.on('data', logError);
   bumpProcess.on('error', logError);
   bumpProcess.on('close', done);
});

/**
 * Package Raven.Assure CLI into ./package/{target}/assure-{version}-{environment}.
 * @task {package}
 * @arg {environment} The build environment: {Debug|Release(default)}
 * @arg {env} Alias for environment
 *
 * TODO: add branch to package output folder name, like with mobile.
 */
gulp.task('package', ['build'], function packageRavenAssure(done) {
  const assurePackage = getPackageJson();
  var env = args.environment || args.env || paths.bin.environment;
  var fullPackagePath = path.join(paths.package, paths.bin.target, `assure-${assurePackage.version}-${env}`);
  var fullBinPath = path.join(paths.bin.prefix, env, paths.bin.target, paths.bin.files);

  gutil.log('Packaging from:', gutil.colors.cyan(fullBinPath));
  gutil.log('Packaging into:', gutil.colors.cyan(fullPackagePath));

  gulp.src(fullBinPath)
      .pipe(gulp.dest(fullPackagePath));
});

// Define reusable loggers.
var toString = (msg) => msg.toString();
// dotnet CLI adds line break, so when combined with log it adds an additional empty line.
// This replaces that line break with an empty string.
var removeLineBreaks = (msg) => msg.replace(/(\r\n|\r|\n)/g, '');
var logDatar = _.flow(toString, removeLineBreaks, gutil.log);
var logError = _.flow(gutil.colors.red, logDatar);

var getPackageJson = () => JSON.parse(fs.readFileSync('./package.json', 'utf8'));
<|endoftext|>