<commit_before>function (user, context, callback) {
  var WHITELIST = ['7PQFR1tyqr6TIqdHcgbRcYcbmbgYflVE', // ldap-pwless.testrp.security.allizom.org
                   'xRFzU2bj7Lrbo3875aXwyxIArdkq1AOT', // Federated AWS CLI auth0-dev
                   'N7lULzWtfVUDGymwDs0yDEq6ZcwmFazj', // Federated AWS CLI auth0-prod
  ];
  if (WHITELIST.indexOf(context.clientID) >= 0) {
    const request = require('request');
    var aws_groups;
    console.log("Enriching id_token with amr for AWS Federated CLI");
    // Amazon will read in the id token's `amr` list and allow you to match on policies with a string condition.
    // See
    // https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html#Conditions_String
    //
    // Note that this abuses the `amr` value (see https://tools.ietf.org/html/rfc8176) as these are not listed as
    // registered values, and that groups are not authentication methods.
    //
    // NOTES:
    // - Amazon will accept an id_token of MAXIMUM 2048 bytes
    // - Amazon will process an `amr` value in that token that results in a certain unknown maximum size. Through
    // experimenting with sizes, this is about 26 groups of "reasonable size" (15-20 characters). This means we
    // shouldn't send too many groups in the `amr` or things will fail.

    // Fetching valid groups as we need to reduce `amr`
    // NOTE: This rule REQUIRES configuration.aws_mapping_url to be set. The file looks like this:
    // {
    //  "team_opsec": [
    //    "arn:aws:iam::656532927350:role/gene-test-federated-role-mozlando"
    //  ],
    //  "vpn_eis_automation" : [
    //      "arn:aws:iam::656532927350:role/federated-aws-cli-test-may2019"
    //    ]
    // }
    var options = { method: 'GET', url: configuration.aws_mapping_url };
    request(options, function (error, response, body) {
      if (error) throw new Error(error);
      if (response.statusCode !== 200) {
        console.log('Could not fetch AWS amr mappings URL: '+response.statusCode);
      } else {
        aws_groups = Object.keys(JSON.parse(body));
        user.groups = user.groups || [];
        context.idToken.amr = user.groups.filter(function(n) { return aws_groups.indexOf(n)  > -1 ;});

        // If Duo will be called, Auth0 will add an `amr` claim in list slot 0 and overwrite our entry, so we need to
        // care for this. Note that sometimes it'll get replaced, sometimes not. This is always replaced by Duo is
        // triggered by Auth0 and replaced by "mfa" but could be any valid amr value.
        context.idToken.amr.splice(0, 0, "");

        console.log("Returning idToken with idToken.amr size == "+context.idToken.amr.length+" (should be ~< 26 and idToken < 2048) for user_id "+user.user_id);
        return callback(null, user, context);
      }
    });
  } else {
    return callback(null, user, context);
  }
}
<commit_msg>clearer comment<commit_after>function (user, context, callback) {
  var WHITELIST = ['7PQFR1tyqr6TIqdHcgbRcYcbmbgYflVE', // ldap-pwless.testrp.security.allizom.org
                   'xRFzU2bj7Lrbo3875aXwyxIArdkq1AOT', // Federated AWS CLI auth0-dev
                   'N7lULzWtfVUDGymwDs0yDEq6ZcwmFazj', // Federated AWS CLI auth0-prod
  ];
  if (WHITELIST.indexOf(context.clientID) >= 0) {
    const request = require('request');
    var aws_groups;
    console.log("Enriching id_token with amr for AWS Federated CLI");
    // Amazon will read in the id token's `amr` list and allow you to match on policies with a string condition.
    // See
    // https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html#Conditions_String
    //
    // Note that this abuses the `amr` value (see https://tools.ietf.org/html/rfc8176) as these are not listed as
    // registered values, and that groups are not authentication methods.
    //
    // NOTES:
    // - Amazon will accept an id_token of MAXIMUM 2048 bytes
    // - Amazon will process an `amr` value in that token that results in a certain unknown maximum size. Through
    // experimenting with sizes, this is about 26 groups of "reasonable size" (15-20 characters). This means we
    // shouldn't send too many groups in the `amr` or things will fail.

    // Fetching valid groups as we need to reduce `amr`
    // NOTE: This rule REQUIRES configuration.aws_mapping_url to be set. The file looks like this:
    // {
    //  "team_opsec": [
    //    "arn:aws:iam::656532927350:role/gene-test-federated-role-mozlando"
    //  ],
    //  "vpn_eis_automation" : [
    //      "arn:aws:iam::656532927350:role/federated-aws-cli-test-may2019"
    //    ]
    // }
    var options = { method: 'GET', url: configuration.aws_mapping_url };
    request(options, function (error, response, body) {
      if (error) throw new Error(error);
      if (response.statusCode !== 200) {
        console.log('Could not fetch AWS amr mappings URL: '+response.statusCode);
      } else {
        aws_groups = Object.keys(JSON.parse(body));
        user.groups = user.groups || [];
        context.idToken.amr = user.groups.filter(function(n) { return aws_groups.indexOf(n)  > -1 ;});

        // If Auth0 is going to send the user to Duo, Auth0 will modify the `amr` claim. Auth0 will specifically
        // overwrite the first element in the `amr` list (slot 0) with the string `mfa`. Anything put in slot 0
        // of the list by this rule may be overwritten by this `mfa` value. In cases where the user already has a
        // valid session with Duo, Auth0 will not overwrite slot 0 of the `amr` claim. As a result, this rule adds
        // a single element at the beginning of the `amr` claim list, an empty string. This slot 0 empty string
        // will be overwritten by the string `mfa` when users log into Duo and will be left in place when users have
        // a valid Duo session already. In the future it's possible that Auth0 will either add a different valid
        // `amr` value (other than `mfa`) or possibly additional `amr` values which could overwrite additional
        // elements in the `amr` claim list. This rule does not account for these possible future issues.
        context.idToken.amr.splice(0, 0, "");

        console.log("Returning idToken with idToken.amr size == "+context.idToken.amr.length+" (should be ~< 26 and idToken < 2048) for user_id "+user.user_id);
        return callback(null, user, context);
      }
    });
  } else {
    return callback(null, user, context);
  }
}
<|endoftext|>


<commit_before>const inquirer = require('inquirer');
const childProcess = require('child_process');

const formNumber = process.argv[2];

const formNumberPrompt = {
    message: 'Which form do you want to reset?',
    type: 'list',
    name: 'formNumber',
    choices: [
        '1 - First Form',
        '2 - Second Form',
        '3 - Third Form',
        '4 - Test Dummy Form',
        '5 - Async Form',
        '6 - Async Test Dummy Form'
    ]
}

let prompts = [formNumberPrompt];

inquirer
    .prompt(prompts)
    .then(function (data) {
        const finalFormSelection = data.formNumber ? data.formNumber : formNumber;
        const finalFormNumber = parseInt(finalFormSelection);

        childProcess.fork('./runner-utils/client-runners/reset-form.js', [finalFormNumber]);
    });
<commit_msg>Removed incomplete form from menu list<commit_after>const inquirer = require('inquirer');
const childProcess = require('child_process');

const formNumber = process.argv[2];

const formNumberPrompt = {
    message: 'Which form do you want to reset?',
    type: 'list',
    name: 'formNumber',
    choices: [
        '1 - First Form',
        '2 - Second Form',
        '3 - Third Form',
        '4 - Test Dummy Form',
        // '5 - Async Form',
        '6 - Async Test Dummy Form'
    ]
}

let prompts = [formNumberPrompt];

inquirer
    .prompt(prompts)
    .then(function (data) {
        const finalFormSelection = data.formNumber ? data.formNumber : formNumber;
        const finalFormNumber = parseInt(finalFormSelection);

        childProcess.fork('./runner-utils/client-runners/reset-form.js', [finalFormNumber]);
    });
<|endoftext|>


<commit_before>$('.page-header').remove();

// MapLoader will probably end up with all the other modules.
/*
var MapLoader = (function(){
    var maploaded = false, cbs = [];
    function init(_opts) {
        log("started map load");
    }
    function loaded() {
        log("Finished map load");
        maploaded = true;
        _.each(cbs, function(cb){
            cb();
        });
    }
    function addOnload(cb) {
        if(maploaded) {
            cb();
        } else {
            cbs.push(cb);
        }
    }
    return {
        init: init,
        loaded: loaded,
        addOnload: addOnload
    }
})();
*/

var zz = 0;
var itemzOnMap = {};

var displayWindowOptions = {
    offsetElems: '.topbar .fill .container',
    sizeCookie: true,
    callbacks: {
        resize: [
            function(animate, sizeName){
                if(sizeName==="full") {
                    NMIS.DisplayWindow.showTitle('tables');
                } else {
                    NMIS.DisplayWindow.showTitle('bar');
                }
            }
        ]
    }
};

NMIS.DisplayWindow.init(".content", displayWindowOptions);

var overviewObj = {
    name: 'Overview', slug: 'overview'
};

NMIS.loadSectors(sectorData, {
    default: {
        name: 'Overview', slug: 'overview'
    }
});

var wElems = NMIS.DisplayWindow.getElems();

var dashboard = $.sammy('body');
(function(){
    NMIS.init();
    NMIS.LocalNav.init(wElems.wrap, {
        sections: [
            [
                ["mode:summary", "LGA Summary", "#"],
                ["mode:facilities", "Facility Detail", "#"]
            ],
            [
                ["sector:overview", "Overview", "#"],
                ["sector:health", "Health", "#"],
                ["sector:education", "Education", "#"],
                ["sector:water", "Water", "#"]
            ]
        ]
    });

	NMIS.urlFor = function(_o){
        var o = _.extend({
            //defaults
            root: '/nmis~',
            mode: 'summary'
        }, _o);
        if(!o.lga || !o.state) return "/nmis~?error";
        return (function _pushAsDefined(obj, keyList) {
    	    var key, i, l, arr = [], item;
    	    for(i=0, l=keyList.length; i < l; i++) {
    	        key = keyList[i];
    	        item = obj[key];
                if(!!item) {
                    if(item===false) { return ["/error"]; }
                    arr.push(item.slug === undefined ? item : item.slug);
    	        } else {
    	            return arr;
    	        }
    	    }
    	    return arr;
    	})(o, ["root", "state", "lga", "mode",
                        "sector", "subsector", "indicator"]).join('/');
    }
    $('.url-for').each(function(){
        var d = $(this).data('urlFor');
        $(this).attr('href', NMIS.urlFor(_.extend({
            lga: lga.slug,
            state: state.slug
        }, d)));
    });
//    log(.eq(0).data('urlFor'))
    var env = {root: '/nmis~', state: state, lga: lga};
    NMIS.Breadcrumb.init("p.bc", {
        levels: [
            [state.name, env.root],
            [lga.name, "/nmis~/"+state.slug+"/"+lga.slug+"/"]
        ]
    });
})();
<commit_msg>moved NMIS.init() out of the inner scope.<commit_after>$('.page-header').remove();

var zz = 0;
var itemzOnMap = {};

var displayWindowOptions = {
    offsetElems: '.topbar .fill .container',
    sizeCookie: true,
    callbacks: {
        resize: [
            function(animate, sizeName){
                if(sizeName==="full") {
                    NMIS.DisplayWindow.showTitle('tables');
                } else {
                    NMIS.DisplayWindow.showTitle('bar');
                }
            }
        ]
    }
};

NMIS.DisplayWindow.init(".content", displayWindowOptions);

var overviewObj = {
    name: 'Overview', slug: 'overview'
};

NMIS.loadSectors(sectorData, {
    default: {
        name: 'Overview', slug: 'overview'
    }
});

NMIS.init();

var wElems = NMIS.DisplayWindow.getElems();

var dashboard = $.sammy('body');
(function(){
    NMIS.LocalNav.init(wElems.wrap, {
        sections: [
            [
                ["mode:summary", "LGA Summary", "#"],
                ["mode:facilities", "Facility Detail", "#"]
            ],
            [
                ["sector:overview", "Overview", "#"],
                ["sector:health", "Health", "#"],
                ["sector:education", "Education", "#"],
                ["sector:water", "Water", "#"]
            ]
        ]
    });

	NMIS.urlFor = function(_o){
        var o = _.extend({
            //defaults
            root: '/nmis~',
            mode: 'summary'
        }, _o);
        if(!o.lga || !o.state) return "/nmis~?error";
        return (function _pushAsDefined(obj, keyList) {
    	    var key, i, l, arr = [], item;
    	    for(i=0, l=keyList.length; i < l; i++) {
    	        key = keyList[i];
    	        item = obj[key];
                if(!!item) {
                    if(item===false) { return ["/error"]; }
                    arr.push(item.slug === undefined ? item : item.slug);
    	        } else {
    	            return arr;
    	        }
    	    }
    	    return arr;
    	})(o, ["root", "state", "lga", "mode",
                        "sector", "subsector", "indicator"]).join('/');
    }
    $('.url-for').each(function(){
        var d = $(this).data('urlFor');
        $(this).attr('href', NMIS.urlFor(_.extend({
            lga: lga.slug,
            state: state.slug
        }, d)));
    });
    var env = {root: '/nmis~', state: state, lga: lga};
    NMIS.Breadcrumb.init("p.bc", {
        levels: [
            [state.name, env.root],
            [lga.name, "/nmis~/"+state.slug+"/"+lga.slug+"/"]
        ]
    });
})();
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var path = require('path');
var fs = require('fs');

var sh = require('shelljs');
var exec = require('../utils/exec');
var _ = require('lodash');

var log = require('../utils/log');
var env = require('../utils/env');
var plugins = require('../utils/plugins');

gulp.task('clean', function () {
  if (fs.existsSync(env.folders.build)) {
    sh.rm('-fr', path.join(env.folders.build, '*'));
  }
  if (fs.existsSync(env.folders.temp)) {
    sh.rm('-fr', path.join(env.folders.temp, '*'));
  }
});

var getAppFiles = function (filter) {
  return [env.folders.app + filter, '!' + env.folders.app + '/forks' + filter];
};

gulp.task('bowerInstall', function () {
  // 用于CI系统时，请加上--ci参数
  return exec('bower', ['install', '--config.interactive=' + !env.args.ci, '--allow-root']).catch(function () {
    log.error("bower install失败，可能网络有问题或存在版本冲突，请手动运行bower install命令来解决它。");
    process.exit(1);
  });

});

gulp.task('sass', function () {
  return gulp.src(env.folders.app + '/styles/**/*.scss')
    .pipe(plugins.sourcemaps.init())
    .pipe(plugins.sass({
      includePaths: [
        env.folders.app + '/styles'
      ],
      imagePath: env.folders.app + '/images',
      onError: function (err) {
        if (err.code === 1) {
          log.error(err.file + ' @ ' + err.line + ':' + err.column + '. error: ' + err.message);
        } else {
          log.message(err.file + ' @ ' + err.line + ':' + err.column + '. level: ' + err.code + ', message:' + err.message)
        }
      }
    }))
    .pipe(plugins.sourcemaps.write())
    .pipe(gulp.dest(env.folders.temp + '/app'));
});

var filesOf = function (extensionName) {
  return [
    env.folders.app + '/**/*.' + extensionName,
    env.folders.test + '/**/*.' + extensionName,
    env.folders.mock + '/**/*.' + extensionName,
    '!' + env.folders.mock + '/node_modules/**/*.' + extensionName
  ];
};

gulp.task('coffee', function () {
  return gulp.src(filesOf('coffee'), {base: env.folders.project})
    .pipe(plugins.plumber())
    .pipe(plugins.sourcemaps.init())
    .pipe(plugins.coffee({bare: true}))
    .on('error', log.error)
    .pipe(plugins.sourcemaps.write())
    .pipe(gulp.dest(env.folders.temp));
});

gulp.task('es6', function () {
  return gulp.src(filesOf('es6'), {base: env.folders.project})
    .pipe(plugins.plumber())
    .pipe(plugins.sourcemaps.init())
    .pipe(plugins.es6())
    .on('error', log.error)
    .pipe(plugins.sourcemaps.write())
    .pipe(plugins.rename({
      extname: ".js"
    }))
    .pipe(gulp.dest(env.folders.temp));
});

gulp.task('typescript', function () {
  return gulp.src(filesOf('ts').concat(['!' + env.folders.project + '/**/*.d.ts']), {base: env.folders.project})
    .pipe(plugins.plumber())
    .pipe(plugins.sourcemaps.init())
    .pipe(plugins.typescript({
      declarationFiles: true
    })).js
    .pipe(plugins.sourcemaps.write())
    .pipe(gulp.dest(env.folders.temp));
});

gulp.task('lint', function () {
  // 第三方库的js不进行lint
  return gulp.src(filesOf('js'))
    .pipe(plugins.plumber())
    .pipe(plugins.jshint())
    .pipe(plugins.jshint.reporter('jshint-stylish'));
});

gulp.task('webFont', function () {
  var fontName = 'app-icons';
  return gulp.src(env.folders.app + '/icons/**/*.svg')
    .pipe(plugins.plumber())
    // gulp-iconfont/gulp-iconfont-css不能正确处理appendCodepoints的情况，所以自己写了一个webFontScss插件
    .pipe(plugins.webFontScss({
      fontName: fontName, // required
      fontPath: 'fonts/',
      normalize: true,
      scss: {
        base: env.folders.temp + '/app/fonts', // 必须和dest中的路径相同，否则_icons.scss写入的位置会有问题
        templateFile: env.folders.frontJet + '/app/assets/app/_icons.scss.tpl',
        filename: env.folders.app + '/styles/_icons.scss'
      },
      appendCodepoints: true // 保留原有代码位，以免新版本刚发布时css对应的图标混乱
    }))
    .pipe(gulp.dest(env.folders.temp + '/app/fonts'));
});

gulp.task('wireBowerJs', ['bowerInstall'], function () {
  // 把对bower js的引用注入到html文件中
  return gulp.src(env.folders.app + '/*.html')
    .pipe(plugins.plumber())
    .pipe(plugins.wiredep({
      directory: env.folders.library,
      dependencies: true,
      devDependencies: false,
      fileTypes: {
        html: {
          replace: {
            // 强制使用utf-8格式
            js: '<script src="{{filePath}}" charset="utf-8"></script>'
          }
        }
      }
    }))
    .pipe(gulp.dest('app'));
});

gulp.task('wireBowerScss', ['bowerInstall'], function () {
  return gulp.src(getAppFiles('/**/*.scss'))
    .pipe(plugins.plumber())
    .pipe(plugins.wiredep({
      directory: env.folders.library,
      dependencies: true,
      devDependencies: false
    }))
    .pipe(gulp.dest('app'));
});

gulp.task('wireBower', ['wireBowerJs', 'wireBowerScss']);

var sortByFileName = function (file1, file2) {
  return -file1.relative.localeCompare(file2.relative);
};
gulp.task('wireAppJs', function () {
  // 按照约定优于配置的原则将js文件注入所有根目录下的文件
  var injectJs = function (files) {
    return plugins.inject(files,
      {
        starttag: '<!-- inject:app:js -->',
        relative: true,
        transform: function (filepath, file) {
          // 自己的js统一使用utf-8格式
          return '<script src="' + toPosixPath(file.relative) + '" charset="utf-8"></script>';
        }
      });
  };

  var appFiles = gulp.src(getAppFiles('/**/*.js').concat(['!' + env.folders.app + '/**/*.test.js', '!' + env.folders.temp + '/app/**/*.test.js']), {base: env.folders.app});
  var sortedFiles = appFiles
    .pipe(plugins.sort(sortByFileName))
    .pipe(plugins.angularFileSort());

  return gulp.src(env.folders.app + '/*.html')
    .pipe(plugins.plumber())
    // 整理出文件依赖关系，然后注入
    .pipe(injectJs(sortedFiles))
    .pipe(gulp.dest(env.folders.app));
});

gulp.task('wireAppScss', function () {
  // 按照约定优于配置的原则将scss文件注入所有styles目录下的文件
  var injectScss = function (files) {
    return plugins.inject(files,
      {
        starttag: '// inject:page:scss',
        endtag: '// endinject',
        relative: true,
        transform: function (filepath, file) {
          return '@import "' + toPosixPath(file.relative) + '";';
        }
      });
  };

  var stylesPath = env.folders.app + '/styles';
  var filter = '/**/*.scss';
  // 除了styles中的scss以外，都注入进来
  var appFiles = gulp.src(getAppFiles(filter).concat(['!' + stylesPath + filter]), {base: stylesPath});
  //
  var sortedFiles = appFiles
    .pipe(plugins.sort(sortByFileName));

  return gulp.src(stylesPath + filter)
    .pipe(plugins.plumber())
    // 整理出文件依赖关系，然后注入
    .pipe(injectScss(sortedFiles))
    .pipe(gulp.dest(stylesPath));
});

gulp.task('wireApp', ['wireAppJs', 'wireAppScss']);

gulp.task('copyLibraries', function () {
  var files = plugins.mainBowerFiles();

  var libraryPath = env.folders.project + '/bower_components';
  // js，css交给usemin去处理，中间文件不用拷贝过去
  _.each(['js', 'css', 'scss', 'less', 'coffee', 'ts', 'dart'], function (ext) {
    files.push('!' + libraryPath + '/**/*.' + ext);
  });

  return gulp.src(files, {base: libraryPath})
    .pipe(gulp.dest(env.folders.build + '/bower_components'));
});
gulp.task('copyForks', function () {
  // 如果指定了系统，则将其文件归并到主工程中，否则原样保留
  var forkName = env.args.ios ? 'ios' : env.args.android ? 'android' : 'default';
  return sh.cp('-r', env.folders.app + '/forks/' + forkName + '/*', env.folders.build);
});

var htmlMinifyOptions = {
  conditionals: true, // ie条件注释留着
  empty: true,
  spare: true,
  quotes: true
};

gulp.task('copyViews', function () {
  // 子页面处理下，根目录下的不用管
  return gulp.src([env.folders.app + '/**/*.html', '!' + env.folders.app + '/*.html'], {base: env.folders.app})
    .pipe(plugins.plumber())
    .pipe(plugins.minifyHtml(htmlMinifyOptions))
    .pipe(plugins.ngHtml2js({
      moduleName: 'app',
      declareModule: false
    }))
    .pipe(plugins.concat('templates.js'))
    .pipe(gulp.dest(env.folders.temp + '/shadow'));
});

gulp.task('copyImages', function () {
  return gulp.src(env.folders.app + '/images/**/*.*')
    .pipe(plugins.plumber())
    .pipe(plugins.imagemin())
    .pipe(gulp.dest(env.folders.build + '/images'));
});

gulp.task('copyFonts', function () {
  return gulp.src(env.folders.temp + '/app/fonts')
    .pipe(gulp.dest(env.folders.build));
});

gulp.task('copyIcons', function () {
  return gulp.src(env.folders.app + '/*.ico')
    .pipe(gulp.dest(env.folders.build));
});

gulp.task('buildHome', function () {
  var assets = plugins.useref.assets();
  var isJs = function (file) {
    return /^.*\.js$/.test(file.relative);
  };
  var isAppJs = function (file) {
    return isJs(file) && !/^\w*\/vendor.*\.js$/.test(file.relative);
  };
  return gulp.src('app/*.html')
    .pipe(plugins.plumber())
    .pipe(assets)
    .pipe(plugins.rev())
    .pipe(plugins.if(isAppJs, plugins.ngAnnotate()))
    .pipe(plugins.if(isJs, plugins.uglify()))
    .pipe(plugins.if('*.css', plugins.csso()))
    .pipe(assets.restore())
    .pipe(plugins.useref())
    .pipe(plugins.revReplace())
    .pipe(gulp.dest(env.folders.build));
});

gulp.task('buildManifest', function () {
  return gulp.src(env.folders.build + '/**/*.*')
    .pipe(plugins.plumber())
    .pipe(plugins.manifest({
      hash: true,
      preferOnline: true,
      network: ['http://*', 'https://*', '*'],
      filename: 'app.manifest',
      exclude: 'app.manifest'
    }));
});

gulp.task('compile', function (done) {
  // 全部串行，以免出现两个并发任务同时操作同一个文件的问题，这些步骤中速度不是最重要的
  plugins.runSequence('clean', 'bowerInstall', 'webFont', 'wireApp', 'wireBower', 'sass', 'coffee', 'es6', 'typescript', done);
});

gulp.task('build', function (done) {
  plugins.runSequence('compile', 'copyForks', 'copyLibraries', 'copyFonts', 'copyImages', 'copyViews',
    'copyIcons', 'buildHome', 'buildManifest', 'preview.reload', done);
});

var path = require('path');
function toPosixPath(fileName) {
  if (!fileName) {
    return fileName;
  }
  return fileName.replace(/\\/g, '/');
}
<commit_msg>解决windows下的路径分隔符问题<commit_after>'use strict';

var gulp = require('gulp');
var path = require('path');
var fs = require('fs');

var sh = require('shelljs');
var exec = require('../utils/exec');
var _ = require('lodash');

var log = require('../utils/log');
var env = require('../utils/env');
var plugins = require('../utils/plugins');

gulp.task('clean', function () {
  if (fs.existsSync(env.folders.build)) {
    sh.rm('-fr', path.join(env.folders.build, '*'));
  }
  if (fs.existsSync(env.folders.temp)) {
    sh.rm('-fr', path.join(env.folders.temp, '*'));
  }
});

var getAppFiles = function (filter) {
  return [env.folders.app + filter, '!' + env.folders.app + '/forks' + filter];
};

gulp.task('bowerInstall', function () {
  // 用于CI系统时，请加上--ci参数
  return exec('bower', ['install', '--config.interactive=' + !env.args.ci, '--allow-root']).catch(function () {
    log.error("bower install失败，可能网络有问题或存在版本冲突，请手动运行bower install命令来解决它。");
    process.exit(1);
  });

});

gulp.task('sass', function () {
  return gulp.src(env.folders.app + '/styles/**/*.scss')
    .pipe(plugins.sourcemaps.init())
    .pipe(plugins.sass({
      includePaths: [
        env.folders.app + '/styles'
      ],
      imagePath: env.folders.app + '/images',
      onError: function (err) {
        if (err.code === 1) {
          log.error(err.file + ' @ ' + err.line + ':' + err.column + '. error: ' + err.message);
        } else {
          log.message(err.file + ' @ ' + err.line + ':' + err.column + '. level: ' + err.code + ', message:' + err.message)
        }
      }
    }))
    .pipe(plugins.sourcemaps.write())
    .pipe(gulp.dest(env.folders.temp + '/app'));
});

var filesOf = function (extensionName) {
  return [
    env.folders.app + '/**/*.' + extensionName,
    env.folders.test + '/**/*.' + extensionName,
    env.folders.mock + '/**/*.' + extensionName,
    '!' + env.folders.mock + '/node_modules/**/*.' + extensionName
  ];
};

gulp.task('coffee', function () {
  return gulp.src(filesOf('coffee'), {base: env.folders.project})
    .pipe(plugins.plumber())
    .pipe(plugins.sourcemaps.init())
    .pipe(plugins.coffee({bare: true}))
    .on('error', log.error)
    .pipe(plugins.sourcemaps.write())
    .pipe(gulp.dest(env.folders.temp));
});

gulp.task('es6', function () {
  return gulp.src(filesOf('es6'), {base: env.folders.project})
    .pipe(plugins.plumber())
    .pipe(plugins.sourcemaps.init())
    .pipe(plugins.es6())
    .on('error', log.error)
    .pipe(plugins.sourcemaps.write())
    .pipe(plugins.rename({
      extname: ".js"
    }))
    .pipe(gulp.dest(env.folders.temp));
});

gulp.task('typescript', function () {
  return gulp.src(filesOf('ts').concat(['!' + env.folders.project + '/**/*.d.ts']), {base: env.folders.project})
    .pipe(plugins.plumber())
    .pipe(plugins.sourcemaps.init())
    .pipe(plugins.typescript({
      declarationFiles: true
    })).js
    .pipe(plugins.sourcemaps.write())
    .pipe(gulp.dest(env.folders.temp));
});

gulp.task('lint', function () {
  // 第三方库的js不进行lint
  return gulp.src(filesOf('js'))
    .pipe(plugins.plumber())
    .pipe(plugins.jshint())
    .pipe(plugins.jshint.reporter('jshint-stylish'));
});

gulp.task('webFont', function () {
  var fontName = 'app-icons';
  return gulp.src(env.folders.app + '/icons/**/*.svg')
    .pipe(plugins.plumber())
    // gulp-iconfont/gulp-iconfont-css不能正确处理appendCodepoints的情况，所以自己写了一个webFontScss插件
    .pipe(plugins.webFontScss({
      fontName: fontName, // required
      fontPath: 'fonts/',
      normalize: true,
      scss: {
        base: env.folders.temp + '/app/fonts', // 必须和dest中的路径相同，否则_icons.scss写入的位置会有问题
        templateFile: env.folders.frontJet + '/app/assets/app/_icons.scss.tpl',
        filename: env.folders.app + '/styles/_icons.scss'
      },
      appendCodepoints: true // 保留原有代码位，以免新版本刚发布时css对应的图标混乱
    }))
    .pipe(gulp.dest(env.folders.temp + '/app/fonts'));
});

gulp.task('wireBowerJs', ['bowerInstall'], function () {
  // 把对bower js的引用注入到html文件中
  return gulp.src(env.folders.app + '/*.html')
    .pipe(plugins.plumber())
    .pipe(plugins.wiredep({
      directory: env.folders.library,
      dependencies: true,
      devDependencies: false,
      fileTypes: {
        html: {
          replace: {
            // 强制使用utf-8格式
            js: '<script src="{{filePath}}" charset="utf-8"></script>'
          }
        }
      }
    }))
    .pipe(gulp.dest('app'));
});

gulp.task('wireBowerScss', ['bowerInstall'], function () {
  return gulp.src(getAppFiles('/**/*.scss'))
    .pipe(plugins.plumber())
    .pipe(plugins.wiredep({
      directory: env.folders.library,
      dependencies: true,
      devDependencies: false
    }))
    .pipe(gulp.dest('app'));
});

gulp.task('wireBower', ['wireBowerJs', 'wireBowerScss']);

var sortByFileName = function (file1, file2) {
  return -file1.relative.localeCompare(file2.relative);
};
gulp.task('wireAppJs', function () {
  // 按照约定优于配置的原则将js文件注入所有根目录下的文件
  var injectJs = function (files) {
    return plugins.inject(files,
      {
        starttag: '<!-- inject:app:js -->',
        relative: true,
        transform: function (filepath, file) {
          // 自己的js统一使用utf-8格式
          return '<script src="' + toPosixPath(file.relative) + '" charset="utf-8"></script>';
        }
      });
  };

  var appFiles = gulp.src(getAppFiles('/**/*.js').concat(['!' + env.folders.app + '/**/*.test.js', '!' + env.folders.temp + '/app/**/*.test.js']), {base: env.folders.app});
  var sortedFiles = appFiles
    .pipe(plugins.sort(sortByFileName))
    .pipe(plugins.angularFileSort());

  return gulp.src(env.folders.app + '/*.html')
    .pipe(plugins.plumber())
    // 整理出文件依赖关系，然后注入
    .pipe(injectJs(sortedFiles))
    .pipe(gulp.dest(env.folders.app));
});

gulp.task('wireAppScss', function () {
  // 按照约定优于配置的原则将scss文件注入所有styles目录下的文件
  var injectScss = function (files) {
    return plugins.inject(files,
      {
        starttag: '// inject:page:scss',
        endtag: '// endinject',
        relative: true,
        transform: function (filepath, file) {
          return '@import "' + toPosixPath(file.relative) + '";';
        }
      });
  };

  var stylesPath = env.folders.app + '/styles';
  var filter = '/**/*.scss';
  // 除了styles中的scss以外，都注入进来
  var appFiles = gulp.src(getAppFiles(filter).concat(['!' + stylesPath + filter]), {base: stylesPath});
  //
  var sortedFiles = appFiles
    .pipe(plugins.sort(sortByFileName));

  return gulp.src(stylesPath + filter)
    .pipe(plugins.plumber())
    // 整理出文件依赖关系，然后注入
    .pipe(injectScss(sortedFiles))
    .pipe(gulp.dest(stylesPath));
});

gulp.task('wireApp', ['wireAppJs', 'wireAppScss']);

gulp.task('copyLibraries', function () {
  var files = plugins.mainBowerFiles();

  var libraryPath = env.folders.project + '/bower_components';
  // js，css交给usemin去处理，中间文件不用拷贝过去
  _.each(['js', 'css', 'scss', 'less', 'coffee', 'ts', 'dart'], function (ext) {
    files.push('!' + libraryPath + '/**/*.' + ext);
  });

  return gulp.src(files, {base: libraryPath})
    .pipe(gulp.dest(env.folders.build + '/bower_components'));
});
gulp.task('copyForks', function () {
  // 如果指定了系统，则将其文件归并到主工程中，否则原样保留
  var forkName = env.args.ios ? 'ios' : env.args.android ? 'android' : 'default';
  return sh.cp('-r', env.folders.app + '/forks/' + forkName + '/*', env.folders.build);
});

var htmlMinifyOptions = {
  conditionals: true, // ie条件注释留着
  empty: true,
  spare: true,
  quotes: true
};

gulp.task('copyViews', function () {
  // 子页面处理下，根目录下的不用管
  return gulp.src([env.folders.app + '/**/*.html', '!' + env.folders.app + '/*.html'], {base: env.folders.app})
    .pipe(plugins.plumber())
    .pipe(plugins.minifyHtml(htmlMinifyOptions))
    .pipe(plugins.ngHtml2js({
      moduleName: 'app',
      declareModule: false
    }))
    .pipe(plugins.concat('templates.js'))
    .pipe(gulp.dest(env.folders.temp + '/shadow'));
});

gulp.task('copyImages', function () {
  return gulp.src(env.folders.app + '/images/**/*.*')
    .pipe(plugins.plumber())
    .pipe(plugins.imagemin())
    .pipe(gulp.dest(env.folders.build + '/images'));
});

gulp.task('copyFonts', function () {
  return gulp.src(env.folders.temp + '/app/fonts')
    .pipe(gulp.dest(env.folders.build));
});

gulp.task('copyIcons', function () {
  return gulp.src(env.folders.app + '/*.ico')
    .pipe(gulp.dest(env.folders.build));
});

gulp.task('buildHome', function () {
  var assets = plugins.useref.assets();
  var isJs = function (file) {
    return /^.*\.js$/.test(file.relative);
  };
  var isAppJs = function (file) {
    return isJs(file) && !/^\w*\/vendor.*\.js$/.test(toPosixPath(file.relative));
  };
  return gulp.src('app/*.html')
    .pipe(plugins.plumber())
    .pipe(assets)
    .pipe(plugins.rev())
    .pipe(plugins.if(isAppJs, plugins.ngAnnotate()))
    .pipe(plugins.if(isJs, plugins.uglify()))
    .pipe(plugins.if('*.css', plugins.csso()))
    .pipe(assets.restore())
    .pipe(plugins.useref())
    .pipe(plugins.revReplace())
    .pipe(gulp.dest(env.folders.build));
});

gulp.task('buildManifest', function () {
  return gulp.src(env.folders.build + '/**/*.*')
    .pipe(plugins.plumber())
    .pipe(plugins.manifest({
      hash: true,
      preferOnline: true,
      network: ['http://*', 'https://*', '*'],
      filename: 'app.manifest',
      exclude: 'app.manifest'
    }));
});

gulp.task('compile', function (done) {
  // 全部串行，以免出现两个并发任务同时操作同一个文件的问题，这些步骤中速度不是最重要的
  plugins.runSequence('clean', 'bowerInstall', 'webFont', 'wireApp', 'wireBower', 'sass', 'coffee', 'es6', 'typescript', done);
});

gulp.task('build', function (done) {
  plugins.runSequence('compile', 'copyForks', 'copyLibraries', 'copyFonts', 'copyImages', 'copyViews',
    'copyIcons', 'buildHome', 'buildManifest', 'preview.reload', done);
});

var path = require('path');
function toPosixPath(fileName) {
  if (!fileName) {
    return fileName;
  }
  return fileName.replace(/\\/g, '/');
}
<|endoftext|>


<commit_before>import React, { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import { useLongPress, LongPressDetectEvents } from 'use-long-press'
import styled from '@emotion/styled'
import { useHistory } from 'react-router-dom'

import Thumbnail from './Thumbnail'
import FabMenu from '../components/FabMenu'
import { ReactComponent as AlbumIcon } from '../static/images/album_outlined.svg'
import { ReactComponent as DeleteIcon } from '../static/images/delete_outlined.svg'
import { ReactComponent as TagIcon } from '../static/images/tag_outlined.svg'

const Container = styled('ul')`
  margin: 0;
  padding: 0;
  padding: 40px;

  & > h2 {
    display: block;
  }

  .section {
    .thumbnails {
      width: 100%;
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
      grid-column-gap: 20px;
      grid-row-gap: 20px;
      box-sizing: content-box;
    }
    h2 {
      font-size: 18px;
    }
  }

  @media all and (max-width: 1024px) {
    padding: 20px;
    .section {
      margin-bottom: 20px;
      .thumbnails {
        grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
      }
    }
  }
  @media all and (max-width: 700px) {
    padding: 10px;
    .section {
      margin-bottom: 10px;
      .thumbnails {
        grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
        grid-column-gap: 10px;
        grid-row-gap: 10px;
      }
    }
  }
`
const SectionHeading = styled('h2')`
  display: block;
`

const ESCAPE_KEY = 27
const CTRL_KEY = 17

const Thumbnails = ({
  photoSections,
  refetchPhotoList,
  refetchAlbumList,
  mapPhotosRefetch,
  mode,
  rateable,
}) => {
  const history = useHistory()
  const [selected, setSelected] = useState([])
  const [ctrlKeyPressed, setCtrlKeyPressed] = useState(false)

  let options = [
    {
      label: 'Tag',
      icon: <TagIcon />,
    },
    {
      label: 'Add to album',
      icon: <AlbumIcon />,
    },
    {
      label: 'Remove from album',
      icon: <AlbumIcon />,
    },
    {
      label: 'Delete',
      icon: <DeleteIcon />,
    },
  ]

  mode !== 'ALBUM_ID' && options.splice(2, 1)
  const getNode = (startEl) => {
    for (let el = startEl; el && el.parentNode; el = el.parentNode) {
      if (el.tagName === 'LI') return el
    }
    return null
  }

  const addRemoveItem = (id) => {
    let ids = [...selected]
    const index = ids.indexOf(id)
    index > -1 ? ids.splice(index, 1) : ids.push(id)
    setSelected(ids)
  }

  const bind = useLongPress(
    (e) => {
      const id = getNode(e.target).getAttribute('data-id')
      addRemoveItem(id)
    },
    {
      onCancel: (e) => {
        const id = getNode(e.target).getAttribute('data-id')
        selected.length > 0 ? addRemoveItem(id) : history.push(`/photo/${id}`)
      },
      threshold: 500,
      captureEvent: true,
      cancelOnMovement: false,
      detect: LongPressDetectEvents.BOTH,
    }
  )

  useEffect(() => {
    if (mode === 'ALBUMS') setSelected([])
  }, [mode])

  useEffect(() => {
    const handleKeyDown = (event) => {
      switch (event.keyCode) {
        case ESCAPE_KEY:
          setSelected([])
          break
        case CTRL_KEY:
          setCtrlKeyPressed(true)
          break
        default:
          break
      }
    }

    const handleKeyUp = (event) => {
      switch (event.keyCode) {
        case CTRL_KEY:
          setCtrlKeyPressed(false)
          break
        default:
          break
      }
    }

    document.addEventListener('keydown', handleKeyDown)
    document.addEventListener('keyup', handleKeyUp)

    return () => {
      document.removeEventListener('keydown', handleKeyDown)
      document.removeEventListener('keyup', handleKeyUp)
    }
  }, [])

  const onMouseDown = ctrlKeyPressed
    ? (e) => {
        const id = getNode(e.target).getAttribute('data-id')
        addRemoveItem(id)
      }
    : bind.onMouseDown

  return (
    <>
      <Container>
        {photoSections
          ? photoSections.map((section) => (

                {section.title ? (
                  <SectionHeading>{section.title}</SectionHeading>
                ) : null}

                  {section.segments.map((segment) =>
                    segment.photos.map((photo) => {
                      return mode === 'ALBUMS' ? (
                        <Thumbnail
                          key={photo.albumId}
                          id={photo.id}
                          imageUrl={photo.thumbnail}
                          starRating={photo.starRating}
                          selected={selected.indexOf(photo.id) > -1}
                          selectable={selected.length > 0}
                          mode={mode}
                          rateable={rateable}
                          albumId={photo.albumId}
                          albumPhotosCount={photo.albumPhotosCount}
                          albumName={photo.albumName}
                        />
                      ) : (
                        <Thumbnail
                          key={photo.id}
                          id={photo.id}
                          imageUrl={photo.thumbnail}
                          starRating={photo.starRating}
                          selected={selected.indexOf(photo.id) > -1}
                          selectable={selected.length > 0 || ctrlKeyPressed}
                          mode={mode}
                          rateable={rateable}
                          {...bind}
                          onMouseDown={onMouseDown}
                        />
                      )
                    })
                  )}

            ))
          : null}
      </Container>
      {selected.length > 0 && (
        <FabMenu
          options={options}
          photoIds={selected}
          refetchPhotoList={refetchPhotoList}
          refetchAlbumList={refetchAlbumList}
          mapPhotosRefetch={mapPhotosRefetch}
        />
      )}
    </>
  )
}

Thumbnails.propTypes = {
  photoSections: PropTypes.array,
  refetchPhotoList: PropTypes.func,
  refetchAlbumList: PropTypes.func,
  mapPhotosRefetch: PropTypes.func,
  mode: PropTypes.string,
  rateable: PropTypes.bool,
}

Thumbnails.defaultProps = {
  photoSections: [],
  mode: 'TIMELINE',
  rateable: false,
}

export default Thumbnails
<commit_msg>Back arrow to album list<commit_after>import React, { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import { useLongPress, LongPressDetectEvents } from 'use-long-press'
import styled from '@emotion/styled'
import { useHistory } from 'react-router-dom'

import Thumbnail from './Thumbnail'
import FabMenu from '../components/FabMenu'
import { ReactComponent as AlbumIcon } from '../static/images/album_outlined.svg'
import { ReactComponent as ArrowBackIcon } from '../static/images/arrow_back.svg'
import { ReactComponent as DeleteIcon } from '../static/images/delete_outlined.svg'
import { ReactComponent as TagIcon } from '../static/images/tag_outlined.svg'

const Container = styled('ul')`
  margin: 0;
  padding: 0;
  padding: 40px;

  & > h2 {
    display: block;
  }

  .backIcon {
    cursor: pointer;
    margin-right: 10px;
    vertical-align: middle;
    display: inline-block;
    svg {
      filter: invert(0.9);
    }
  }

  .section {
    .thumbnails {
      width: 100%;
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
      grid-column-gap: 20px;
      grid-row-gap: 20px;
      box-sizing: content-box;
    }
    h2 {
      font-size: 18px;
      display: inline-block;
      margin: 0 0 20px 0;
    }
  }

  @media all and (max-width: 1024px) {
    padding: 20px;
    .section {
      margin-bottom: 20px;
      .thumbnails {
        grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
      }
    }
  }
  @media all and (max-width: 700px) {
    padding: 10px;
    .section {
      margin-bottom: 10px;
      .thumbnails {
        grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
        grid-column-gap: 10px;
        grid-row-gap: 10px;
      }
    }
  }
`
const SectionHeading = styled('h2')`
  display: block;
`

const ESCAPE_KEY = 27
const CTRL_KEY = 17

const Thumbnails = ({
  photoSections,
  refetchPhotoList,
  refetchAlbumList,
  mapPhotosRefetch,
  mode,
  rateable,
}) => {
  const history = useHistory()
  const [selected, setSelected] = useState([])
  const [ctrlKeyPressed, setCtrlKeyPressed] = useState(false)

  let options = [
    {
      label: 'Tag',
      icon: <TagIcon />,
    },
    {
      label: 'Add to album',
      icon: <AlbumIcon />,
    },
    {
      label: 'Remove from album',
      icon: <AlbumIcon />,
    },
    {
      label: 'Delete',
      icon: <DeleteIcon />,
    },
  ]

  mode !== 'ALBUM_ID' && options.splice(2, 1)
  const getNode = (startEl) => {
    for (let el = startEl; el && el.parentNode; el = el.parentNode) {
      if (el.tagName === 'LI') return el
    }
    return null
  }

  const addRemoveItem = (id) => {
    let ids = [...selected]
    const index = ids.indexOf(id)
    index > -1 ? ids.splice(index, 1) : ids.push(id)
    setSelected(ids)
  }

  const bind = useLongPress(
    (e) => {
      const id = getNode(e.target).getAttribute('data-id')
      addRemoveItem(id)
    },
    {
      onCancel: (e) => {
        const id = getNode(e.target).getAttribute('data-id')
        selected.length > 0 ? addRemoveItem(id) : history.push(`/photo/${id}`)
      },
      threshold: 500,
      captureEvent: true,
      cancelOnMovement: false,
      detect: LongPressDetectEvents.BOTH,
    }
  )

  useEffect(() => {
    if (mode === 'ALBUMS') setSelected([])
  }, [mode])

  useEffect(() => {
    const handleKeyDown = (event) => {
      switch (event.keyCode) {
        case ESCAPE_KEY:
          setSelected([])
          break
        case CTRL_KEY:
          setCtrlKeyPressed(true)
          break
        default:
          break
      }
    }

    const handleKeyUp = (event) => {
      switch (event.keyCode) {
        case CTRL_KEY:
          setCtrlKeyPressed(false)
          break
        default:
          break
      }
    }

    document.addEventListener('keydown', handleKeyDown)
    document.addEventListener('keyup', handleKeyUp)

    return () => {
      document.removeEventListener('keydown', handleKeyDown)
      document.removeEventListener('keyup', handleKeyUp)
    }
  }, [])

  const onMouseDown = ctrlKeyPressed
    ? (e) => {
        const id = getNode(e.target).getAttribute('data-id')
        addRemoveItem(id)
      }
    : bind.onMouseDown

  return (
    <>
      <Container>
        {photoSections
          ? photoSections.map((section) => (

                  {mode === 'ALBUM_ID' && (

                      <ArrowBackIcon
                        onClick={() => {
                          if (document.referrer !== '' || history.length > 2) {
                            history.goBack()
                          } else {
                            history.push('/?mode=albums')
                          }
                        }}
                      />

                  )}
                  {section.title ? (
                    <SectionHeading>{section.title}</SectionHeading>
                  ) : null}

                  {section.segments.map((segment) =>
                    segment.photos.map((photo) => {
                      return mode === 'ALBUMS' ? (
                        <Thumbnail
                          key={photo.albumId}
                          id={photo.id}
                          imageUrl={photo.thumbnail}
                          starRating={photo.starRating}
                          selected={selected.indexOf(photo.id) > -1}
                          selectable={selected.length > 0}
                          mode={mode}
                          rateable={rateable}
                          albumId={photo.albumId}
                          albumPhotosCount={photo.albumPhotosCount}
                          albumName={photo.albumName}
                        />
                      ) : (
                        <Thumbnail
                          key={photo.id}
                          id={photo.id}
                          imageUrl={photo.thumbnail}
                          starRating={photo.starRating}
                          selected={selected.indexOf(photo.id) > -1}
                          selectable={selected.length > 0 || ctrlKeyPressed}
                          mode={mode}
                          rateable={rateable}
                          {...bind}
                          onMouseDown={onMouseDown}
                        />
                      )
                    })
                  )}

            ))
          : null}
      </Container>
      {selected.length > 0 && (
        <FabMenu
          options={options}
          photoIds={selected}
          refetchPhotoList={refetchPhotoList}
          refetchAlbumList={refetchAlbumList}
          mapPhotosRefetch={mapPhotosRefetch}
        />
      )}
    </>
  )
}

Thumbnails.propTypes = {
  photoSections: PropTypes.array,
  refetchPhotoList: PropTypes.func,
  refetchAlbumList: PropTypes.func,
  mapPhotosRefetch: PropTypes.func,
  mode: PropTypes.string,
  rateable: PropTypes.bool,
}

Thumbnails.defaultProps = {
  photoSections: [],
  mode: 'TIMELINE',
  rateable: false,
}

export default Thumbnails
<|endoftext|>


<commit_before>var Mdns = require('../');

var mdns = new Mdns();

mdns.on('ready', function () {
    mdns.discover();
});

mdns.on('update', function () {
    console.log('ips with _workstation._tcp service', mdns.ips('_workstation._tcp'));
    console.log('services on host 10.100.0.61', mdns.services('10.100.0.61'));
    mdns.shutdown();
});<commit_msg>Updated example<commit_after>var mdns = require('../');

// var browser = new mdns.Mdns(mdns.tcp("googlecast"));
// console.log(mdns.ServiceType.wildcard);
var browser = new mdns.Mdns(mdns.ServiceType.wildcard);

browser.on('ready', function () {
  browser.discover();
});

browser.on('update', function (data) {
    console.log('device address', data.addresses[0]);
    console.log('device name', data.name);
    console.log('service name', data.type);
    mdns.shutdown();
});<|endoftext|>


<commit_before>import {
  teal500,
  teal600,
  teal700,
  deepPurple500,
  deepPurple600,
  deepPurple700,
  grey50,
  grey100,
  grey200,
  grey300,
  grey400,
  grey500,
  grey600,
  grey700,
  grey800,
  grey900,
  darkBlack,
  fullBlack,
  white
} from 'material-ui/styles/colors'

// GK: theme structure following https://github.com/jxnblk/styled-system/blob/master/README.md
// and https://github.com/cloudflare/cf-ui/blob/master/packages/cf-style-const/src/variables.js

export default {
  breakpoints: {
    mobile: '13.6em',
    mobileWide: '30.4em',
    tablet: '47.2em',
    //tabletLegacy: '49.2em',
    //tabletWide: '55em',
    desktop: '64em',
    desktopLarge: '97.6em'
  },
  space: [
    '0rem', // [0] SR: wanting to override default allofthespace with noneofthespace
    '0.25rem', // [1]
    '0.5rem', // [2]
    '1rem', // [3]
    '2rem', // [4]
    '4rem', // [5]
    '8rem', // [6]
    '16rem' // [7]
  ],
  fontSizes: [
    '0.8rem', // [0] 10pt
    '0.95rem', // [1] 11pt
    '1rem', // [2] 12pt
    '1.2rem', // [3] 14pt
    '1.4rem', // [4] 16pt
    '1.5rem', // [5] 18pt
    '1.7rem', // [6] 21pt
    '2rem', // [7] 24pt
    '3rem', // [8] 36pt
    '4rem', // [9] 48pt
    '5rem', // [10] 60pt
    '6rem', // [11] 72pt
    '8rem' // [12] 96pt
    // og scale:
    // '0.875rem',
    // '1rem',
    // '1.25rem',
    // '1.5rem',
    // '2.25rem',
    // '3rem',
    // '5rem',
    // '6rem',
    // '8rem',
    // '10rem'
  ],
  fonts: {
    primary: 'Roboto, sans-serif',
    logo: '"Lobster Two", cursive'
  },
  colors: {
    primary1: teal500,
    primary2: teal600,
    primary3: teal700,
    accent1: deepPurple500,
    accent2: deepPurple600,
    accent3: deepPurple700,
    greys: [
      grey50, // [0]
      grey100, // [1]
      grey200, // [2]
      grey300, // [3]
      grey400, // [4]
      grey500, // [5]
      grey600, // [6]
      grey700, // [7]
      grey800, // [8]
      grey900 // [9]
    ],
    text: darkBlack,
    alternateText: white,
    canvas: white,
    border: grey300,
    shadow: fullBlack
  },
  fontWeights: {
    thin: 100,
    light: 300,
    regular: 400,
    medium: 500,
    bold: 700,
    black: 900
  },
  em: '1em',
  rem: '1rem',
  borderRadius: '2px',
  zIndexMax: 1000
}
<commit_msg>style(theme): add px conversions to breakpoints<commit_after>import {
  teal500,
  teal600,
  teal700,
  deepPurple500,
  deepPurple600,
  deepPurple700,
  grey50,
  grey100,
  grey200,
  grey300,
  grey400,
  grey500,
  grey600,
  grey700,
  grey800,
  grey900,
  darkBlack,
  fullBlack,
  white
} from 'material-ui/styles/colors'

// GK: theme structure following https://github.com/jxnblk/styled-system/blob/master/README.md
// and https://github.com/cloudflare/cf-ui/blob/master/packages/cf-style-const/src/variables.js

export default {
  breakpoints: {
    // em-px conversions given base 16px
    mobile: '13.6em', // 217px
    mobileWide: '30.4em', // 486px
    tablet: '47.2em', // 755px
    //tabletLegacy: '49.2em',
    //tabletWide: '55em',
    desktop: '64em', // 1024px
    desktopLarge: '97.6em' // 1171px
  },
  space: [
    '0rem', // [0] SR: wanting to override default allofthespace with noneofthespace
    '0.25rem', // [1]
    '0.5rem', // [2]
    '1rem', // [3]
    '2rem', // [4]
    '4rem', // [5]
    '8rem', // [6]
    '16rem' // [7]
  ],
  fontSizes: [
    '0.8rem', // [0] 10pt
    '0.95rem', // [1] 11pt
    '1rem', // [2] 12pt
    '1.2rem', // [3] 14pt
    '1.4rem', // [4] 16pt
    '1.5rem', // [5] 18pt
    '1.7rem', // [6] 21pt
    '2rem', // [7] 24pt
    '3rem', // [8] 36pt
    '4rem', // [9] 48pt
    '5rem', // [10] 60pt
    '6rem', // [11] 72pt
    '8rem' // [12] 96pt
    // og scale:
    // '0.875rem',
    // '1rem',
    // '1.25rem',
    // '1.5rem',
    // '2.25rem',
    // '3rem',
    // '5rem',
    // '6rem',
    // '8rem',
    // '10rem'
  ],
  fonts: {
    primary: 'Roboto, sans-serif',
    logo: '"Lobster Two", cursive'
  },
  colors: {
    primary1: teal500,
    primary2: teal600,
    primary3: teal700,
    accent1: deepPurple500,
    accent2: deepPurple600,
    accent3: deepPurple700,
    greys: [
      grey50, // [0]
      grey100, // [1]
      grey200, // [2]
      grey300, // [3]
      grey400, // [4]
      grey500, // [5]
      grey600, // [6]
      grey700, // [7]
      grey800, // [8]
      grey900 // [9]
    ],
    text: darkBlack,
    alternateText: white,
    canvas: white,
    border: grey300,
    shadow: fullBlack
  },
  fontWeights: {
    thin: 100,
    light: 300,
    regular: 400,
    medium: 500,
    bold: 700,
    black: 900
  },
  em: '1em',
  rem: '1rem',
  borderRadius: '2px',
  zIndexMax: 1000
}
<|endoftext|>


<commit_before>goog.require('ol.Collection');
goog.require('ol.Coordinate');
goog.require('ol.Map');
goog.require('ol.RendererHints');
goog.require('ol.View2D');
goog.require('ol.layer.TileLayer');
goog.require('ol.source.OpenStreetMap');

var map = new ol.Map({
  layers: new ol.Collection([
    new ol.layer.TileLayer({
      source: new ol.source.OpenStreetMap()
    })
  ]),
  renderers: ol.RendererHints.createFromQueryData(),
  target: 'map',
  view: new ol.View2D({
    center: new ol.Coordinate(0, 0),
    zoom: 2
  })
});
<commit_msg>Don't use ol.Collection in simple example<commit_after>goog.require('ol.Coordinate');
goog.require('ol.Map');
goog.require('ol.RendererHints');
goog.require('ol.View2D');
goog.require('ol.layer.TileLayer');
goog.require('ol.source.OpenStreetMap');

var map = new ol.Map({
  layers: [
    new ol.layer.TileLayer({
      source: new ol.source.OpenStreetMap()
    })
  ],
  renderers: ol.RendererHints.createFromQueryData(),
  target: 'map',
  view: new ol.View2D({
    center: new ol.Coordinate(0, 0),
    zoom: 2
  })
});
<|endoftext|>


<commit_before>/**
 * Created by praveen on 25.08.15.
 */
angular.module('UserApp', ['ngMaterial', 'ngRoute', 'ngCookies', 'ngMd5', 'chart.js', 'md.data.table',
    'angulartics', 'angulartics.google.analytics'])
    .config(function($mdThemingProvider) {
    $mdThemingProvider.theme('default')
        .primaryPalette('blue')
        .accentPalette('deep-orange');
});

angular.module('UserApp').constant('config', {
    apiUrl: 'http://api.coursestats.de',
    minCharsInSearch: 2
});

// Route configuration
angular.module('UserApp').config(function($routeProvider) {$routeProvider
    .when('/course/:id',{
        templateUrl : 'includes/grade.html',
        controller  : 'GradeCtrl'
    })
    .when('/teacher/:id',{
        templateUrl : 'includes/grade.html',
        controller  : 'GradeCtrl'
    })
    .when('/review/:id',{
        templateUrl : 'includes/review.html',
        controller  : 'ReviewCtrl'
    })
    .when('/login',{
        templateUrl : 'includes/login.html',
        controller  : 'LoginCtrl'
    })
    .when('/register',{
        templateUrl : 'includes/register.html',
        controller  : 'RegisterCtrl'
    })
    .when('/',{
        templateUrl : 'includes/default.html'
    })
    .otherwise({
        redirectTo: '/'
    });
});

angular.module('UserApp').controller('AppCtrl', function($scope) {
});

<commit_msg>https for api<commit_after>/**
 * Created by praveen on 25.08.15.
 */
angular.module('UserApp', ['ngMaterial', 'ngRoute', 'ngCookies', 'ngMd5', 'chart.js', 'md.data.table',
    'angulartics', 'angulartics.google.analytics'])
    .config(function($mdThemingProvider) {
    $mdThemingProvider.theme('default')
        .primaryPalette('blue')
        .accentPalette('deep-orange');
});

angular.module('UserApp').constant('config', {
    apiUrl: 'https://api.coursestats.de',
    minCharsInSearch: 2
});

// Route configuration
angular.module('UserApp').config(function($routeProvider) {$routeProvider
    .when('/course/:id',{
        templateUrl : 'includes/grade.html',
        controller  : 'GradeCtrl'
    })
    .when('/teacher/:id',{
        templateUrl : 'includes/grade.html',
        controller  : 'GradeCtrl'
    })
    .when('/review/:id',{
        templateUrl : 'includes/review.html',
        controller  : 'ReviewCtrl'
    })
    .when('/login',{
        templateUrl : 'includes/login.html',
        controller  : 'LoginCtrl'
    })
    .when('/register',{
        templateUrl : 'includes/register.html',
        controller  : 'RegisterCtrl'
    })
    .when('/',{
        templateUrl : 'includes/default.html'
    })
    .otherwise({
        redirectTo: '/'
    });
});

angular.module('UserApp').controller('AppCtrl', function($scope) {
});

<|endoftext|>


<commit_before>import { getScrollbarWidth } from './scroll.js'
import { client } from '../plugins/Platform.js'

let vpLeft, vpTop

export function validatePosition (pos) {
  let parts = pos.split(' ')
  if (parts.length !== 2) {
    return false
  }
  if (!['top', 'center', 'bottom'].includes(parts[0])) {
    console.error('Anchor/Self position must start with one of top/center/bottom')
    return false
  }
  if (!['left', 'middle', 'right'].includes(parts[1])) {
    console.error('Anchor/Self position must end with one of left/middle/right')
    return false
  }
  return true
}

export function validateOffset (val) {
  if (!val) { return true }
  if (val.length !== 2) { return false }
  if (typeof val[0] !== 'number' || typeof val[1] !== 'number') {
    return false
  }
  return true
}

export function parsePosition (pos) {
  let parts = pos.split(' ')
  return { vertical: parts[0], horizontal: parts[1] }
}

export function validateCover (val) {
  if (val === true || val === false) { return true }
  return validatePosition(val)
}

export function getAnchorProps (el, offset) {
  let { top, left, right, bottom, width, height } = el.getBoundingClientRect()

  if (offset !== void 0) {
    top -= offset[1]
    left -= offset[0]
    bottom += offset[1]
    right += offset[0]

    width += offset[0]
    height += offset[1]
  }

  return {
    top,
    left,
    right,
    bottom,
    width,
    height,
    middle: left + (right - left) / 2,
    center: top + (bottom - top) / 2
  }
}

export function getTargetProps (el) {
  const { width, height } = el.getBoundingClientRect()
  return {
    top: 0,
    center: height / 2,
    bottom: height,
    left: 0,
    middle: width / 2,
    right: width
  }
}

// cfg: { el, anchorEl, anchorOrigin, selfOrigin, offset, absoluteOffset, cover, fit, maxHeight, maxWidth }
export function setPosition (cfg) {
  if (client.is.ios === true && window.visualViewport !== void 0) {
    // uses the q-position-engine CSS class

    const el = document.body.style
    const { offsetLeft: left, offsetTop: top } = window.visualViewport

    if (left !== vpLeft) {
      el.setProperty('--q-pe-left', left + 'px')
      vpLeft = left
    }
    if (top !== vpTop) {
      el.setProperty('--q-pe-top', top + 'px')
      vpTop = top
    }
  }

  let anchorProps

  // scroll position might change
  // if max-height/-width changes, so we
  // need to restore it after we calculate
  // the new positioning
  const { scrollLeft, scrollTop } = cfg.el

  if (cfg.absoluteOffset === void 0) {
    anchorProps = getAnchorProps(cfg.anchorEl, cfg.cover === true ? [0, 0] : cfg.offset)
  }
  else {
    const
      { top: anchorTop, left: anchorLeft } = cfg.anchorEl.getBoundingClientRect(),
      top = anchorTop + cfg.absoluteOffset.top,
      left = anchorLeft + cfg.absoluteOffset.left

    anchorProps = { top, left, width: 1, height: 1, right: left + 1, center: top, middle: left, bottom: top + 1 }
  }

  let elStyle = {
    maxHeight: cfg.maxHeight,
    maxWidth: cfg.maxWidth,
    visibility: 'visible'
  }

  if (cfg.fit === true || cfg.cover === true) {
    elStyle.minWidth = anchorProps.width + 'px'
    if (cfg.cover === true) {
      elStyle.minHeight = anchorProps.height + 'px'
    }
  }

  Object.assign(cfg.el.style, elStyle)

  const
    targetProps = getTargetProps(cfg.el),
    props = {
      top: anchorProps[cfg.anchorOrigin.vertical] - targetProps[cfg.selfOrigin.vertical],
      left: anchorProps[cfg.anchorOrigin.horizontal] - targetProps[cfg.selfOrigin.horizontal]
    }

  applyBoundaries(props, anchorProps, targetProps, cfg.anchorOrigin, cfg.selfOrigin)

  elStyle = {
    top: props.top + 'px',
    left: props.left + 'px'
  }

  if (props.maxHeight !== void 0) {
    elStyle.maxHeight = props.maxHeight + 'px'

    if (anchorProps.height > props.maxHeight) {
      elStyle.minHeight = elStyle.maxHeight
    }
  }
  if (props.maxWidth !== void 0) {
    elStyle.maxWidth = props.maxWidth + 'px'

    if (anchorProps.width > props.maxWidth) {
      elStyle.minWidth = elStyle.maxWidth
    }
  }

  Object.assign(cfg.el.style, elStyle)

  // restore scroll position
  if (cfg.el.scrollTop !== scrollTop) {
    cfg.el.scrollTop = scrollTop
  }
  if (cfg.el.scrollLeft !== scrollLeft) {
    cfg.el.scrollLeft = scrollLeft
  }
}

function applyBoundaries (props, anchorProps, targetProps, anchorOrigin, selfOrigin) {
  const
    currentHeight = targetProps.bottom,
    currentWidth = targetProps.right,
    margin = getScrollbarWidth(),
    innerHeight = window.innerHeight - margin,
    innerWidth = document.body.clientWidth

  if (props.top < 0 || props.top + currentHeight > innerHeight) {
    if (selfOrigin.vertical === 'center') {
      props.top = anchorProps[anchorOrigin.vertical] > innerHeight / 2
        ? Math.max(0, innerHeight - currentHeight)
        : 0
      props.maxHeight = Math.min(currentHeight, innerHeight)
    }
    else if (anchorProps[anchorOrigin.vertical] > innerHeight / 2) {
      const anchorY = Math.min(
        innerHeight,
        anchorOrigin.vertical === 'center'
          ? anchorProps.center
          : (anchorOrigin.vertical === selfOrigin.vertical ? anchorProps.bottom : anchorProps.top)
      )
      props.maxHeight = Math.min(currentHeight, anchorY)
      props.top = Math.max(0, anchorY - currentHeight)
    }
    else {
      props.top = Math.max(0, anchorOrigin.vertical === 'center'
        ? anchorProps.center
        : (anchorOrigin.vertical === selfOrigin.vertical ? anchorProps.top : anchorProps.bottom)
      )
      props.maxHeight = Math.min(currentHeight, innerHeight - props.top)
    }
  }

  if (props.left < 0 || props.left + currentWidth > innerWidth) {
    props.maxWidth = Math.min(currentWidth, innerWidth)
    if (selfOrigin.horizontal === 'middle') {
      props.left = anchorProps[anchorOrigin.horizontal] > innerWidth / 2
        ? Math.max(0, innerWidth - currentWidth)
        : 0
    }
    else if (anchorProps[anchorOrigin.horizontal] > innerWidth / 2) {
      const anchorX = Math.min(
        innerWidth,
        anchorOrigin.horizontal === 'middle'
          ? anchorProps.middle
          : (anchorOrigin.horizontal === selfOrigin.horizontal ? anchorProps.right : anchorProps.left)
      )
      props.maxWidth = Math.min(currentWidth, anchorX)
      props.left = Math.max(0, anchorX - props.maxWidth)
    }
    else {
      props.left = Math.max(0, anchorOrigin.horizontal === 'middle'
        ? anchorProps.middle
        : (anchorOrigin.horizontal === selfOrigin.horizontal ? anchorProps.left : anchorProps.right)
      )
      props.maxWidth = Math.min(currentWidth, innerWidth - props.left)
    }
  }
}
<commit_msg>fix(ui): position engine when using transitions<commit_after>import { getScrollbarWidth } from './scroll.js'
import { client } from '../plugins/Platform.js'

let vpLeft, vpTop

export function validatePosition (pos) {
  let parts = pos.split(' ')
  if (parts.length !== 2) {
    return false
  }
  if (!['top', 'center', 'bottom'].includes(parts[0])) {
    console.error('Anchor/Self position must start with one of top/center/bottom')
    return false
  }
  if (!['left', 'middle', 'right'].includes(parts[1])) {
    console.error('Anchor/Self position must end with one of left/middle/right')
    return false
  }
  return true
}

export function validateOffset (val) {
  if (!val) { return true }
  if (val.length !== 2) { return false }
  if (typeof val[0] !== 'number' || typeof val[1] !== 'number') {
    return false
  }
  return true
}

export function parsePosition (pos) {
  let parts = pos.split(' ')
  return { vertical: parts[0], horizontal: parts[1] }
}

export function validateCover (val) {
  if (val === true || val === false) { return true }
  return validatePosition(val)
}

export function getAnchorProps (el, offset) {
  let { top, left, right, bottom, width, height } = el.getBoundingClientRect()

  if (offset !== void 0) {
    top -= offset[1]
    left -= offset[0]
    bottom += offset[1]
    right += offset[0]

    width += offset[0]
    height += offset[1]
  }

  return {
    top,
    left,
    right,
    bottom,
    width,
    height,
    middle: left + (right - left) / 2,
    center: top + (bottom - top) / 2
  }
}

export function getTargetProps (el) {
  return {
    top: 0,
    center: el.offsetHeight / 2,
    bottom: el.offsetHeight,
    left: 0,
    middle: el.offsetWidth / 2,
    right: el.offsetWidth
  }
}

// cfg: { el, anchorEl, anchorOrigin, selfOrigin, offset, absoluteOffset, cover, fit, maxHeight, maxWidth }
export function setPosition (cfg) {
  if (client.is.ios === true && window.visualViewport !== void 0) {
    // uses the q-position-engine CSS class

    const el = document.body.style
    const { offsetLeft: left, offsetTop: top } = window.visualViewport

    if (left !== vpLeft) {
      el.setProperty('--q-pe-left', left + 'px')
      vpLeft = left
    }
    if (top !== vpTop) {
      el.setProperty('--q-pe-top', top + 'px')
      vpTop = top
    }
  }

  let anchorProps

  // scroll position might change
  // if max-height/-width changes, so we
  // need to restore it after we calculate
  // the new positioning
  const { scrollLeft, scrollTop } = cfg.el

  if (cfg.absoluteOffset === void 0) {
    anchorProps = getAnchorProps(cfg.anchorEl, cfg.cover === true ? [0, 0] : cfg.offset)
  }
  else {
    const
      { top: anchorTop, left: anchorLeft } = cfg.anchorEl.getBoundingClientRect(),
      top = anchorTop + cfg.absoluteOffset.top,
      left = anchorLeft + cfg.absoluteOffset.left

    anchorProps = { top, left, width: 1, height: 1, right: left + 1, center: top, middle: left, bottom: top + 1 }
  }

  let elStyle = {
    maxHeight: cfg.maxHeight,
    maxWidth: cfg.maxWidth,
    visibility: 'visible'
  }

  if (cfg.fit === true || cfg.cover === true) {
    elStyle.minWidth = anchorProps.width + 'px'
    if (cfg.cover === true) {
      elStyle.minHeight = anchorProps.height + 'px'
    }
  }

  Object.assign(cfg.el.style, elStyle)

  const
    targetProps = getTargetProps(cfg.el),
    props = {
      top: anchorProps[cfg.anchorOrigin.vertical] - targetProps[cfg.selfOrigin.vertical],
      left: anchorProps[cfg.anchorOrigin.horizontal] - targetProps[cfg.selfOrigin.horizontal]
    }

  applyBoundaries(props, anchorProps, targetProps, cfg.anchorOrigin, cfg.selfOrigin)

  elStyle = {
    top: props.top + 'px',
    left: props.left + 'px'
  }

  if (props.maxHeight !== void 0) {
    elStyle.maxHeight = props.maxHeight + 'px'

    if (anchorProps.height > props.maxHeight) {
      elStyle.minHeight = elStyle.maxHeight
    }
  }
  if (props.maxWidth !== void 0) {
    elStyle.maxWidth = props.maxWidth + 'px'

    if (anchorProps.width > props.maxWidth) {
      elStyle.minWidth = elStyle.maxWidth
    }
  }

  Object.assign(cfg.el.style, elStyle)

  // restore scroll position
  if (cfg.el.scrollTop !== scrollTop) {
    cfg.el.scrollTop = scrollTop
  }
  if (cfg.el.scrollLeft !== scrollLeft) {
    cfg.el.scrollLeft = scrollLeft
  }
}

function applyBoundaries (props, anchorProps, targetProps, anchorOrigin, selfOrigin) {
  const
    currentHeight = targetProps.bottom,
    currentWidth = targetProps.right,
    margin = getScrollbarWidth(),
    innerHeight = window.innerHeight - margin,
    innerWidth = document.body.clientWidth

  if (props.top < 0 || props.top + currentHeight > innerHeight) {
    if (selfOrigin.vertical === 'center') {
      props.top = anchorProps[anchorOrigin.vertical] > innerHeight / 2
        ? Math.max(0, innerHeight - currentHeight)
        : 0
      props.maxHeight = Math.min(currentHeight, innerHeight)
    }
    else if (anchorProps[anchorOrigin.vertical] > innerHeight / 2) {
      const anchorY = Math.min(
        innerHeight,
        anchorOrigin.vertical === 'center'
          ? anchorProps.center
          : (anchorOrigin.vertical === selfOrigin.vertical ? anchorProps.bottom : anchorProps.top)
      )
      props.maxHeight = Math.min(currentHeight, anchorY)
      props.top = Math.max(0, anchorY - currentHeight)
    }
    else {
      props.top = Math.max(0, anchorOrigin.vertical === 'center'
        ? anchorProps.center
        : (anchorOrigin.vertical === selfOrigin.vertical ? anchorProps.top : anchorProps.bottom)
      )
      props.maxHeight = Math.min(currentHeight, innerHeight - props.top)
    }
  }

  if (props.left < 0 || props.left + currentWidth > innerWidth) {
    props.maxWidth = Math.min(currentWidth, innerWidth)
    if (selfOrigin.horizontal === 'middle') {
      props.left = anchorProps[anchorOrigin.horizontal] > innerWidth / 2
        ? Math.max(0, innerWidth - currentWidth)
        : 0
    }
    else if (anchorProps[anchorOrigin.horizontal] > innerWidth / 2) {
      const anchorX = Math.min(
        innerWidth,
        anchorOrigin.horizontal === 'middle'
          ? anchorProps.middle
          : (anchorOrigin.horizontal === selfOrigin.horizontal ? anchorProps.right : anchorProps.left)
      )
      props.maxWidth = Math.min(currentWidth, anchorX)
      props.left = Math.max(0, anchorX - props.maxWidth)
    }
    else {
      props.left = Math.max(0, anchorOrigin.horizontal === 'middle'
        ? anchorProps.middle
        : (anchorOrigin.horizontal === selfOrigin.horizontal ? anchorProps.left : anchorProps.right)
      )
      props.maxWidth = Math.min(currentWidth, innerWidth - props.left)
    }
  }
}
<|endoftext|>


<commit_before>'use strict';
// Polyfill
require('babel-polyfill');
/**
 * Module depedencies
*/
const chalk = require('chalk');

/**
 * Logger class
 * @param options {Object} options
*/
class Logger {
  constructor(options) {
    this.options = Object.assign({
      silent: false,
      debug: false
    }, options || {});
    // Stdout
    this.stdout = console.log;
  }

  /**
   * Get date
   * @private
   */
  static getdate() {
    const date = new Date();
    return chalk.grey(`${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`);
  }

  /**
   * Info method
   * @colour green
   * @param txt {String} txt
   */
   /* istanbul ignore info */
   info(txt) {
     if (!this.options.silent) {
       const colour = "green";
       const str = this.prefix || chalk[colour].bold('INFO');
       this.stdout(`[ ${Logger.getdate()} ${str} ] ${txt}`);
     }
   }

   /**
    * Error method
    * @colour red
    * @param txt {String} txt
    */
    /* istanbul ignore info */
    err(txt) {
      if (!this.options.silent) {
        const colour = "bgRed";
        const str = chalk[colour].bold('ERR!');
        console.error(`[ ${Logger.getdate()} ${str} ] ${txt}`);
      }
    }

    /**
     * Throw method
     * @colour red
     * @param err {Error} error to throw
     */
     /* istanbul ignore err */
     throw(err) {
       if (process.env.NODE_ENV !== 'test') {
         this.throw_noexit(err);
         process.exit(1);
       } else {
         throw err;
       }
     }

     /**
      * Throw without exit method
      * @colour red
      * @param err {Error} error to throw
      */
      /* istanbul ignore err */
      throw_noexit(err) {
        if (!this.options.silent) {
          const colour = "bgRed";
          const str = chalk[colour].bold('ERR!');
          console.error(`[ ${Logger.getdate()} ${str} ]`);
          console.error(`[ ${Logger.getdate()} ${str} ] ${err.stack.split('\n')[0]}`);
          console.error(`[ ${Logger.getdate()} ${str} ]`);
          if (this.options.debug || process.env.NODE_ENV !== 'production') {
            console.error(`[ ${Logger.getdate()} ${str} ] Full error:`);
            console.error(`[ ${Logger.getdate()} ${str} ]`);
            let e = 0;
            for (e of err.stack.split('\n')) {
              console.error(`[ ${Logger.getdate()} ${str} ] ${e}`);
            }
          }
          console.error(`[ ${Logger.getdate()} ${str} ]`);
        }
      }

   /**
    * Debug method
    * @colour cyan
    * @param txt {String} txt
    */
    /* istanbul ignore debug */
    debug(txt) {
      if (!this.options.silent && this.options.debug) {
        const colour = "cyan";
        const str = this.prefix || chalk[colour].bold('DEBUG');
        this.stdout(`[ ${Logger.getdate()} ${str} ] ${txt}`);
      }
    }

    // Make a method
    make(method, options) {
      return this[method].bind(
        Object.assign(this, { options: options })
      );
    }
}

// Export
module.exports = Logger;
<commit_msg>:shirt: Code Climate improvments<commit_after>/**
 * Module depedencies
*/
const chalk = require('chalk');

/**
 * Logger class
 * @param options {Object} options
*/
class Logger {
  constructor(options) {
    this.options = Object.assign({
      silent: false,
      debug: false
    }, options || {});
    // Stdout
    this.stdout = console.log;
  }

  /**
   * Get date
   * @private
   */
  static getdate() {
    const date = new Date();
    return chalk.grey(`${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`);
  }

  /**
   * Info method
   * @colour green
   * @param txt {String} txt
   */
   /* istanbul ignore info */
   info(txt) {
     if (!this._isSilent()) {
       this.log("green", "INFO", txt);
     }
   }

   /**
    * Debug method
    * @colour cyan
    * @param txt {String} txt
    */
    /* istanbul ignore debug */
    debug(txt) {
      if (!this._isSilent() && this.options.debug) {
        this.log("cyan", "DEBUG", txt);
      }
    }

   /**
    * Error method
    * @colour red
    * @param txt {String} txt
    */
    /* istanbul ignore info */
    err(txt) {
      if (!this.options.silent) {
        const colour = "bgRed";
        const str = chalk[colour].bold('ERR!');
        console.error(`[ ${Logger.getdate()} ${str} ] ${txt}`);
      }
    }

    /**
     * Throw method
     * @colour red
     * @param err {Error} error to throw
     */
     /* istanbul ignore err */
     throw(err) {
       if (process.env.NODE_ENV !== 'test') {
         this.throw_noexit(err);
         process.exit(1);
       } else {
         throw err;
       }
     }

     /**
      * Throw without exit method
      * @colour red
      * @param err {Error} error to throw
      */
      /* istanbul ignore err */
      throw_noexit(err) {
        if (!this.options.silent) {
          const colour = "bgRed";
          const str = chalk[colour].bold('ERR!');
          console.error(`[ ${Logger.getdate()} ${str} ]`);
          console.error(`[ ${Logger.getdate()} ${str} ] ${err.stack.split('\n')[0]}`);
          console.error(`[ ${Logger.getdate()} ${str} ]`);
          if (this.options.debug || process.env.NODE_ENV !== 'production') {
            console.error(`[ ${Logger.getdate()} ${str} ] Full error:`);
            console.error(`[ ${Logger.getdate()} ${str} ]`);
            let e = 0;
            for (e of err.stack.split('\n')) {
              console.error(`[ ${Logger.getdate()} ${str} ] ${e}`);
            }
          }
          console.error(`[ ${Logger.getdate()} ${str} ]`);
        }
      }

      /**
       * 'Make' a solo method, with different options
       *
       * @param method {String} method to make
       * @param options {Object} options
       * @return {Function} this[method]
       */
      make(method, options) {
        return this[method].bind(
          Object.assign(this, { options: options })
        );
      }

      /**
       * Log text in the format of [ hrs:mins:secs {type} ] {text}
       * with type being the colour specified by colour
       *
       * @param colour {String} colour of type
       * @param type {String} type of log level (debug, info, warn)
       * @param text {String} text to log
       */

      log(colour, type, text) {
        const str = this.prefix || chalk[colour].bold(type);
        this.stdout(`[ ${Logger.getdate()} ${str} ] ${text}`);
      }

      /**
       * Check if silent option is enabled
       *
       * @return {Boolean} this.options.silent
       */
      _isSilent() {
        return this.options.silent;
      }
}

// Export
module.exports = Logger;
<|endoftext|>


<commit_before>import Color from 'color';

export function lightenToContrastThreshold(foreground, background, contrastThreshold) {
    const foregroundColor = Color(foreground);
    const backgroundColor = Color(background);

    let newColor = foregroundColor;

    while (newColor.contrast(backgroundColor) < contrastThreshold) {
        if (newColor.l() >= 100) {
            break;
        }

        newColor = newColor.lightness(newColor.l() + 5);
    }

    return newColor;
}

export function darkenToContrastThreshold(foreground, background, contrastThreshold) {
    const foregroundColor = Color(foreground);
    const backgroundColor = Color(background);

    let newColor = foregroundColor;

    while (newColor.contrast(backgroundColor) < contrastThreshold) {
        if (newColor.l() <= 0) {
            break;
        }

        newColor = newColor.lightness(newColor.l() - 5);
    }

    return newColor;
}

export function textColorForBackgroundColor(background) {
    const backgroundColor = Color(background);

    const white = Color({r: 255, g: 255, b: 255});
    const black = Color({r: 0, g: 0, b: 0});

    // shared with Portal https://github.com/TryGhost/Portal/blob/317876f20d22431df15e655ea6cc197fe636615e/src/utils/contrast-color.js#L26-L29
    const yiq = (
        backgroundColor.red() * 299 +
        backgroundColor.green() * 587 +
        backgroundColor.b() * 114
    ) / 1000;

    return (yiq >= 186) ? black : white;
}
<commit_msg>Fixed infinite loop when lightening/darkening colors<commit_after>import Color from 'color';

export function lightenToContrastThreshold(foreground, background, contrastThreshold) {
    const foregroundColor = Color(foreground);
    const backgroundColor = Color(background);

    const {h,s} = foregroundColor.hsl().object();

    let newColor = foregroundColor;

    while (newColor.contrast(backgroundColor) < contrastThreshold) {
        if (newColor.lightness() >= 100) {
            break;
        }

        newColor = Color({h, s, l: newColor.lightness() + 5});
    }

    return newColor;
}

export function darkenToContrastThreshold(foreground, background, contrastThreshold) {
    const foregroundColor = Color(foreground);
    const backgroundColor = Color(background);

    const {h,s} = foregroundColor.hsl().object();

    let newColor = foregroundColor;

    while (newColor.contrast(backgroundColor) < contrastThreshold) {
        if (newColor.lightness() <= 0) {
            break;
        }

        newColor = Color({h, s, l: newColor.lightness() - 5});
    }

    return newColor;
}

export function textColorForBackgroundColor(background) {
    const backgroundColor = Color(background);

    const white = Color({r: 255, g: 255, b: 255});
    const black = Color({r: 0, g: 0, b: 0});

    // shared with Portal https://github.com/TryGhost/Portal/blob/317876f20d22431df15e655ea6cc197fe636615e/src/utils/contrast-color.js#L26-L29
    const yiq = (
        backgroundColor.red() * 299 +
        backgroundColor.green() * 587 +
        backgroundColor.b() * 114
    ) / 1000;

    return (yiq >= 186) ? black : white;
}
<|endoftext|>