<commit_before>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %>
'use strict';
var fs = require('fs');
<% if (buildTool == 'maven') { %>
var parseString = require('xml2js').parseString;
// Returns the second occurence of the version number
var parseVersionFromPomXml = function() {
    var version;
    var pomXml = fs.readFileSync('pom.xml', "utf8");
    parseString(pomXml, function (err, result){
        version = result.project.version[0];
    });
    return version;
};<% } else { %>
// Returns the first occurence of the version number
var parseVersionFromBuildGradle = function() {
    var versionRegex = /^version\s*=\s*[',"]([^',"]*)[',"]/gm; // Match and group the version number
    var buildGradle = fs.readFileSync('build.gradle', "utf8");
    return versionRegex.exec(buildGradle)[1];
};<% } %>

// usemin custom step
var useminAutoprefixer = {
    name: 'autoprefixer',
    createConfig: require('grunt-usemin/lib/config/cssmin').createConfig // Reuse cssmins createConfig
};

module.exports = function (grunt) {
    require('load-grunt-tasks')(grunt);
    require('time-grunt')(grunt);

    grunt.initConfig({
        yeoman: {
            // configurable paths
            app: require('./bower.json').appPath || 'app',
            dist: 'src/main/webapp/dist'
        },
        watch: {
            bower: {
                files: ['bower.json'],
                tasks: ['wiredep']
            },
            ngconstant: {
                files: ['Gruntfile.js', <% if(buildTool == 'maven') { %>'pom.xml'<% } else { %>'build.gradle'<% } %>],
                tasks: ['ngconstant:dev']
            },<% if (useCompass) { %>
            compass: {
                files: ['src/main/scss/**/*.{scss,sass}'],
                tasks: ['compass:server']
            },<% } %>
            styles: {
                files: ['src/main/webapp/assets/styles/**/*.css']
            }
        },
        autoprefixer: {
        // not used since Uglify task does autoprefixer,
        //    options: ['last 1 version'],
        //    dist: {
        //        files: [{
        //            expand: true,
        //            cwd: '.tmp/styles/',
        //            src: '**/*.css',
        //            dest: '.tmp/styles/'
        //        }]
        //    }
        },
        wiredep: {
            app: {<% if (useCompass) { %>
                src: ['src/main/webapp/index.html', 'src/main/scss/main.scss'],
                exclude: [
                    /angular-i18n/, // localizations are loaded dynamically
                    /swagger-ui/,
                    'bower_components/bootstrap/' // Exclude Bootstrap LESS as we use bootstrap-sass
                ],
                ignorePath: /\.\.\/webapp\/bower_components\// // remove ../webapp/bower_components/ from paths of injected sass files <% } else { %>
                src: ['src/main/webapp/index.html'],
                exclude: [
                    /angular-i18n/,  // localizations are loaded dynamically
                    /swagger-ui/
                ]<% } %>
            },
            test: {
                src: 'src/test/javascript/karma.conf.js',
                exclude: [/angular-i18n/, /swagger-ui/, /angular-scenario/],
                ignorePath: /\.\.\/\.\.\//, // remove ../../ from paths of injected javascripts
                devDependencies: true,
                fileTypes: {
                    js: {
                        block: /(([\s\t]*)\/\/\s*bower:*(\S*))(\n|\r|.)*?(\/\/\s*endbower)/gi,
                        detect: {
                            js: /'(.*\.js)'/gi
                        },
                        replace: {
                            js: '\'{{filePath}}\','
                        }
                    }
                }
            }
        },
        browserSync: {
            dev: {
                bsFiles: {
                    src : [
                        'src/main/webapp/**/*.html',
                        'src/main/webapp/**/*.json',
                        'src/main/webapp/assets/styles/**/*.css',
                        'src/main/webapp/scripts/**/*.js',
                        'src/main/webapp/assets/images/**/*.{png,jpg,jpeg,gif,webp,svg}',
                        'tmp/**/*.{css,js}'
                    ]
                }
            },
            options: {
                watchTask: true,
                proxy: "localhost:8080"
            }
        },
        clean: {
            dist: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%%= yeoman.dist %>/*',
                        '!<%%= yeoman.dist %>/.git*'
                    ]
                }]
            },
            server: '.tmp'
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            all: [
                'Gruntfile.js',
                'src/main/webapp/scripts/app.js',
                'src/main/webapp/scripts/app/**/*.js',
                'src/main/webapp/scripts/components/**/*.js'
            ]
        },
        coffee: {
            options: {
                sourceMap: true,
                sourceRoot: ''
            },
            dist: {
                files: [{
                    expand: true,
                    cwd: 'src/main/webapp/scripts',
                    src: ['scripts/app/**/*.coffee', 'scripts/components/**/*.coffee'],
                    dest: '.tmp/scripts',
                    ext: '.js'
                }]
            },
            test: {
                files: [{
                    expand: true,
                    cwd: 'test/spec',
                    src: '**/*.coffee',
                    dest: '.tmp/spec',
                    ext: '.js'
                }]
            }
        },<% if (useCompass) { %>
        compass: {
            options: {
                sassDir: 'src/main/scss',
                cssDir: 'src/main/webapp/assets/styles',
                generatedImagesDir: '.tmp/assets/images/generated',
                imagesDir: 'src/main/webapp/assets/images',
                javascriptsDir: 'src/main/webapp/scripts',
                fontsDir: 'src/main/webapp/assets/fonts',
                importPath: 'src/main/webapp/bower_components',
                httpImagesPath: '/assets/images',
                httpGeneratedImagesPath: '/assets/images/generated',
                httpFontsPath: '/assets/fonts',
                relativeAssets: false
            },
            dist: {},
            server: {
                options: {
                    debugInfo: true
                }
            }
        },<% } %>
        concat: {
        // not used since Uglify task does concat,
        // but still available if needed
        //    dist: {}
        },
        rev: {
            dist: {
                files: {
                    src: [
                        '<%%= yeoman.dist %>/scripts/**/*.js',
                        '<%%= yeoman.dist %>/assets/styles/**/*.css',
                        '<%%= yeoman.dist %>/assets/images/**/*.{png,jpg,jpeg,gif,webp,svg}',
                        '<%%= yeoman.dist %>/assets/fonts/*'
                    ]
                }
            }
        },
        useminPrepare: {
            html: 'src/main/webapp/**/*.html',
            options: {
                dest: '<%%= yeoman.dist %>',
                flow: {
                    html: {
                        steps: {
                            js: ['concat', 'uglifyjs'],
                            css: ['cssmin', useminAutoprefixer] // Let cssmin concat files so it corrects relative paths to fonts and images
                        },
                            post: {}
                        }
                    }
            }
        },
        usemin: {
            html: ['<%%= yeoman.dist %>/**/*.html'],
            css: ['<%%= yeoman.dist %>/assets/styles/**/*.css'],
            js: ['<%%= yeoman.dist %>/scripts/**/*.js'],
            options: {
                assetsDirs: ['<%%= yeoman.dist %>', '<%%= yeoman.dist %>/assets/styles', '<%%= yeoman.dist %>/assets/images', '<%%= yeoman.dist %>/assets/fonts'],
                patterns: {
                    js: [
                        [/(assets\/images\/.*?\.(?:gif|jpeg|jpg|png|webp|svg))/gm, 'Update the JS to reference our revved images']
                    ]
                },
                dirs: ['<%%= yeoman.dist %>']
            }
        },
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: 'src/main/webapp/assets/images',
                src: '**/*.{jpg,jpeg}', // we don't optimize PNG files as it doesn't work on Linux. If you are not on Linux, feel free to use '**/*.{png,jpg,jpeg}'
                    dest: '<%%= yeoman.dist %>/assets/images'
                }]
            }
        },
        svgmin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: 'src/main/webapp/assets/images',
                    src: '**/*.svg',
                    dest: '<%%= yeoman.dist %>/assets/images'
                }]
            }
        },
        cssmin: {
            // By default, your `index.html` <!-- Usemin Block --> will take care of
            // minification. This option is pre-configured if you do not wish to use
            // Usemin blocks.
            // dist: {
            //     files: {
            //         '<%%= yeoman.dist %>/styles/main.css': [
            //             '.tmp/styles/**/*.css',
            //             'styles/**/*.css'
            //         ]
            //     }
            // }
            options: {
                root: 'src/main/webapp' // Replace relative paths for static resources with absolute path
            }
        },
        ngtemplates:    {
            dist: {
                cwd: 'src/main/webapp',
                src: ['scripts/app/**/*.html', 'scripts/components/**/*.html',],
                dest: '.tmp/templates/templates.js',
                options: {
                    module: '<%= angularAppName%>',
                    usemin: 'scripts/app.js',
                    htmlmin:  {
                        removeCommentsFromCDATA: true,
                        // https://github.com/yeoman/grunt-usemin/issues/44
                        collapseWhitespace: true,
                        collapseBooleanAttributes: true,
                        conservativeCollapse: true,
                        removeAttributeQuotes: true,
                        removeRedundantAttributes: true,
                        useShortDoctype: true,
                        removeEmptyAttributes: true
                    }
                }
            }
        },
        htmlmin: {
            dist: {
                options: {
                    removeCommentsFromCDATA: true,
                    // https://github.com/yeoman/grunt-usemin/issues/44
                    collapseWhitespace: true,
                    collapseBooleanAttributes: true,
                    conservativeCollapse: true,
                    removeAttributeQuotes: true,
                    removeRedundantAttributes: true,
                    useShortDoctype: true,
                    removeEmptyAttributes: true,
                    keepClosingSlash: true
                },
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.dist %>',
                    src: ['*.html'],
                    dest: '<%%= yeoman.dist %>'
                }]
            }
        },
        // Put files not handled in other tasks here
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: 'src/main/webapp',
                    dest: '<%%= yeoman.dist %>',
                    src: [
                        '*.html',
                        'scripts/**/*.html',
                        'assets/images/**/*.{png,gif,webp,jpg,jpeg,svg}',
                        'assets/fonts/*'
                    ]
                }, {
                    expand: true,
                    cwd: '.tmp/assets/images',
                    dest: '<%%= yeoman.dist %>/assets/images',
                    src: [
                        'generated/*'
                    ]
                }]
            },
            generateHerokuDirectory: {
                    expand: true,
                    dest: 'deploy/heroku',
                    src: [
                        'pom.xml',
                        'gradlew',
                        '*.gradle',
                        'gradle.properties',
                        'gradle/**',
                        'src/main/**'
                ]
            },
            generateOpenshiftDirectory: {
                    expand: true,
                    dest: 'deploy/openshift',
                    src: [
                        'pom.xml',
                        'src/main/**'
                ]
            }
        },
        concurrent: {
            server: [<% if (useCompass) { %>
                'compass:server'<% } %>
            ],
            test: [<% if (useCompass) { %>
                'compass'<% } %>
            ],
            dist: [<% if (useCompass) { %>
                'compass:dist',<% } %>
                'imagemin',
                'svgmin'
            ]
        },
        karma: {
            unit: {
                configFile: 'src/test/javascript/karma.conf.js',
                singleRun: true
            }
        },
        cdnify: {
            dist: {
                html: ['<%%= yeoman.dist %>/*.html']
            }
        },
        ngAnnotate: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '.tmp/concat/scripts',
                    src: '*.js',
                    dest: '.tmp/concat/scripts'
                }]
            }
        },
        buildcontrol: {
            options: {
                commit: true,
                push: false,
                connectCommits: false,
                message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%'
            },
            heroku: {
                options: {
                    dir: 'deploy/heroku',
                    remote: 'heroku',
                    branch: 'master'
                }
            },
            openshift: {
                options: {
                    dir: 'deploy/openshift',
                    remote: 'openshift',
                    branch: 'master'
                }
            }
        },
        ngconstant: {
            options: {
                name: '<%= angularAppName%>',
                deps: false,
                wrap: '"use strict";\n// DO NOT EDIT THIS FILE, EDIT THE GRUNT TASK NGCONSTANT SETTINGS INSTEAD WHICH GENERATES THIS FILE\n{%= __ngModule %}'
            },
            dev: {
                options: {
                    dest: 'src/main/webapp/scripts/app/app.constants.js'
                },
                constants: {
                    ENV: 'dev',
                    VERSION: <% if(buildTool == 'maven') { %>parseVersionFromPomXml()<% } else { %>parseVersionFromBuildGradle()<% } %>
                }
            },
            prod: {
                options: {
                    dest: '.tmp/scripts/app/app.constants.js'
                },
                constants: {
                    ENV: 'prod',
                    VERSION: <% if(buildTool == 'maven') { %>parseVersionFromPomXml()<% } else { %>parseVersionFromBuildGradle()<% } %>
                }
            }
        }
    });

    grunt.registerTask('serve', [
        'clean:server',
        'wiredep',
        'ngconstant:dev',
        'concurrent:server',
        'browserSync',
        'watch'
    ]);

    grunt.registerTask('server', function (target) {
        grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
        grunt.task.run([target ? ('serve:' + target) : 'serve']);
    });

    grunt.registerTask('test', [
        'clean:server',
        'wiredep:test',
        'ngconstant:dev',
        'concurrent:test',
        'karma'
    ]);

    grunt.registerTask('build', [
        'clean:dist',
        'wiredep:app',
        'ngconstant:prod',
        'useminPrepare',
        'ngtemplates',
        'concurrent:dist',
        'concat',
        'copy:dist',
        'ngAnnotate',
        'cssmin',
        'autoprefixer',
        'uglify',
        'rev',
        'usemin',
        'htmlmin'
    ]);

	grunt.registerTask('appendSkipBower', 'Force skip of bower for Gradle', function () {
		var filepath = 'deploy/heroku/gradle.properties';

		if (!grunt.file.exists(filepath)) {
			// Assume this is a maven project
			return true;
		}

		var fileContent = grunt.file.read(filepath);
		var skipBowerIndex = fileContent.indexOf("skipBower=true");

		if (skipBowerIndex != -1) {
			return true;
		}

		grunt.file.write(filepath, fileContent + "\nskipBower=true\n");
	});

    grunt.registerTask('buildHeroku', [
        'test',
        'build',
        'copy:generateHerokuDirectory',
        'appendSkipBower'
    ]);

    grunt.registerTask('deployHeroku', [
        'test',
        'build',
        'copy:generateHerokuDirectory',
        'appendSkipBower',
        'buildcontrol:heroku'
    ]);

    grunt.registerTask('buildOpenshift', [
        'test',
        'build',
        'copy:generateOpenshiftDirectory',
    ]);

    grunt.registerTask('deployOpenshift', [
        'test',
        'build',
        'copy:generateOpenshiftDirectory',
        'buildcontrol:openshift'
    ]);

    grunt.registerTask('default', [
        'test',
        'build'
    ]);
};
<commit_msg>Avoid grunt autoprefixer to fail grunt build when no vendor css files are included with bower install, Fix #1453<commit_after>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %>
'use strict';
var fs = require('fs');
<% if (buildTool == 'maven') { %>
var parseString = require('xml2js').parseString;
// Returns the second occurence of the version number
var parseVersionFromPomXml = function() {
    var version;
    var pomXml = fs.readFileSync('pom.xml', "utf8");
    parseString(pomXml, function (err, result){
        version = result.project.version[0];
    });
    return version;
};<% } else { %>
// Returns the first occurence of the version number
var parseVersionFromBuildGradle = function() {
    var versionRegex = /^version\s*=\s*[',"]([^',"]*)[',"]/gm; // Match and group the version number
    var buildGradle = fs.readFileSync('build.gradle', "utf8");
    return versionRegex.exec(buildGradle)[1];
};<% } %>

// usemin custom step
var useminAutoprefixer = {
    name: 'autoprefixer',
    createConfig: function(context, block) {
        if(block.src.length === 0) {
            return {};
        } else {
            return require('grunt-usemin/lib/config/cssmin').createConfig(context, block) // Reuse cssmins createConfig
        }
    }
};

module.exports = function (grunt) {
    require('load-grunt-tasks')(grunt);
    require('time-grunt')(grunt);

    grunt.initConfig({
        yeoman: {
            // configurable paths
            app: require('./bower.json').appPath || 'app',
            dist: 'src/main/webapp/dist'
        },
        watch: {
            bower: {
                files: ['bower.json'],
                tasks: ['wiredep']
            },
            ngconstant: {
                files: ['Gruntfile.js', <% if(buildTool == 'maven') { %>'pom.xml'<% } else { %>'build.gradle'<% } %>],
                tasks: ['ngconstant:dev']
            },<% if (useCompass) { %>
            compass: {
                files: ['src/main/scss/**/*.{scss,sass}'],
                tasks: ['compass:server']
            },<% } %>
            styles: {
                files: ['src/main/webapp/assets/styles/**/*.css']
            }
        },
        autoprefixer: {
        // not used since Uglify task does autoprefixer,
        //    options: ['last 1 version'],
        //    dist: {
        //        files: [{
        //            expand: true,
        //            cwd: '.tmp/styles/',
        //            src: '**/*.css',
        //            dest: '.tmp/styles/'
        //        }]
        //    }
        },
        wiredep: {
            app: {<% if (useCompass) { %>
                src: ['src/main/webapp/index.html', 'src/main/scss/main.scss'],
                exclude: [
                    /angular-i18n/, // localizations are loaded dynamically
                    /swagger-ui/,
                    'bower_components/bootstrap/' // Exclude Bootstrap LESS as we use bootstrap-sass
                ],
                ignorePath: /\.\.\/webapp\/bower_components\// // remove ../webapp/bower_components/ from paths of injected sass files <% } else { %>
                src: ['src/main/webapp/index.html'],
                exclude: [
                    /angular-i18n/,  // localizations are loaded dynamically
                    /swagger-ui/
                ]<% } %>
            },
            test: {
                src: 'src/test/javascript/karma.conf.js',
                exclude: [/angular-i18n/, /swagger-ui/, /angular-scenario/],
                ignorePath: /\.\.\/\.\.\//, // remove ../../ from paths of injected javascripts
                devDependencies: true,
                fileTypes: {
                    js: {
                        block: /(([\s\t]*)\/\/\s*bower:*(\S*))(\n|\r|.)*?(\/\/\s*endbower)/gi,
                        detect: {
                            js: /'(.*\.js)'/gi
                        },
                        replace: {
                            js: '\'{{filePath}}\','
                        }
                    }
                }
            }
        },
        browserSync: {
            dev: {
                bsFiles: {
                    src : [
                        'src/main/webapp/**/*.html',
                        'src/main/webapp/**/*.json',
                        'src/main/webapp/assets/styles/**/*.css',
                        'src/main/webapp/scripts/**/*.js',
                        'src/main/webapp/assets/images/**/*.{png,jpg,jpeg,gif,webp,svg}',
                        'tmp/**/*.{css,js}'
                    ]
                }
            },
            options: {
                watchTask: true,
                proxy: "localhost:8080"
            }
        },
        clean: {
            dist: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%%= yeoman.dist %>/*',
                        '!<%%= yeoman.dist %>/.git*'
                    ]
                }]
            },
            server: '.tmp'
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            all: [
                'Gruntfile.js',
                'src/main/webapp/scripts/app.js',
                'src/main/webapp/scripts/app/**/*.js',
                'src/main/webapp/scripts/components/**/*.js'
            ]
        },
        coffee: {
            options: {
                sourceMap: true,
                sourceRoot: ''
            },
            dist: {
                files: [{
                    expand: true,
                    cwd: 'src/main/webapp/scripts',
                    src: ['scripts/app/**/*.coffee', 'scripts/components/**/*.coffee'],
                    dest: '.tmp/scripts',
                    ext: '.js'
                }]
            },
            test: {
                files: [{
                    expand: true,
                    cwd: 'test/spec',
                    src: '**/*.coffee',
                    dest: '.tmp/spec',
                    ext: '.js'
                }]
            }
        },<% if (useCompass) { %>
        compass: {
            options: {
                sassDir: 'src/main/scss',
                cssDir: 'src/main/webapp/assets/styles',
                generatedImagesDir: '.tmp/assets/images/generated',
                imagesDir: 'src/main/webapp/assets/images',
                javascriptsDir: 'src/main/webapp/scripts',
                fontsDir: 'src/main/webapp/assets/fonts',
                importPath: 'src/main/webapp/bower_components',
                httpImagesPath: '/assets/images',
                httpGeneratedImagesPath: '/assets/images/generated',
                httpFontsPath: '/assets/fonts',
                relativeAssets: false
            },
            dist: {},
            server: {
                options: {
                    debugInfo: true
                }
            }
        },<% } %>
        concat: {
        // not used since Uglify task does concat,
        // but still available if needed
        //    dist: {}
        },
        rev: {
            dist: {
                files: {
                    src: [
                        '<%%= yeoman.dist %>/scripts/**/*.js',
                        '<%%= yeoman.dist %>/assets/styles/**/*.css',
                        '<%%= yeoman.dist %>/assets/images/**/*.{png,jpg,jpeg,gif,webp,svg}',
                        '<%%= yeoman.dist %>/assets/fonts/*'
                    ]
                }
            }
        },
        useminPrepare: {
            html: 'src/main/webapp/**/*.html',
            options: {
                dest: '<%%= yeoman.dist %>',
                flow: {
                    html: {
                        steps: {
                            js: ['concat', 'uglifyjs'],
                            css: ['cssmin', useminAutoprefixer] // Let cssmin concat files so it corrects relative paths to fonts and images
                        },
                            post: {}
                        }
                    }
            }
        },
        usemin: {
            html: ['<%%= yeoman.dist %>/**/*.html'],
            css: ['<%%= yeoman.dist %>/assets/styles/**/*.css'],
            js: ['<%%= yeoman.dist %>/scripts/**/*.js'],
            options: {
                assetsDirs: ['<%%= yeoman.dist %>', '<%%= yeoman.dist %>/assets/styles', '<%%= yeoman.dist %>/assets/images', '<%%= yeoman.dist %>/assets/fonts'],
                patterns: {
                    js: [
                        [/(assets\/images\/.*?\.(?:gif|jpeg|jpg|png|webp|svg))/gm, 'Update the JS to reference our revved images']
                    ]
                },
                dirs: ['<%%= yeoman.dist %>']
            }
        },
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: 'src/main/webapp/assets/images',
                src: '**/*.{jpg,jpeg}', // we don't optimize PNG files as it doesn't work on Linux. If you are not on Linux, feel free to use '**/*.{png,jpg,jpeg}'
                    dest: '<%%= yeoman.dist %>/assets/images'
                }]
            }
        },
        svgmin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: 'src/main/webapp/assets/images',
                    src: '**/*.svg',
                    dest: '<%%= yeoman.dist %>/assets/images'
                }]
            }
        },
        cssmin: {
            // By default, your `index.html` <!-- Usemin Block --> will take care of
            // minification. This option is pre-configured if you do not wish to use
            // Usemin blocks.
            // dist: {
            //     files: {
            //         '<%%= yeoman.dist %>/styles/main.css': [
            //             '.tmp/styles/**/*.css',
            //             'styles/**/*.css'
            //         ]
            //     }
            // }
            options: {
                root: 'src/main/webapp' // Replace relative paths for static resources with absolute path
            }
        },
        ngtemplates:    {
            dist: {
                cwd: 'src/main/webapp',
                src: ['scripts/app/**/*.html', 'scripts/components/**/*.html',],
                dest: '.tmp/templates/templates.js',
                options: {
                    module: '<%= angularAppName%>',
                    usemin: 'scripts/app.js',
                    htmlmin:  {
                        removeCommentsFromCDATA: true,
                        // https://github.com/yeoman/grunt-usemin/issues/44
                        collapseWhitespace: true,
                        collapseBooleanAttributes: true,
                        conservativeCollapse: true,
                        removeAttributeQuotes: true,
                        removeRedundantAttributes: true,
                        useShortDoctype: true,
                        removeEmptyAttributes: true
                    }
                }
            }
        },
        htmlmin: {
            dist: {
                options: {
                    removeCommentsFromCDATA: true,
                    // https://github.com/yeoman/grunt-usemin/issues/44
                    collapseWhitespace: true,
                    collapseBooleanAttributes: true,
                    conservativeCollapse: true,
                    removeAttributeQuotes: true,
                    removeRedundantAttributes: true,
                    useShortDoctype: true,
                    removeEmptyAttributes: true,
                    keepClosingSlash: true
                },
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.dist %>',
                    src: ['*.html'],
                    dest: '<%%= yeoman.dist %>'
                }]
            }
        },
        // Put files not handled in other tasks here
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: 'src/main/webapp',
                    dest: '<%%= yeoman.dist %>',
                    src: [
                        '*.html',
                        'scripts/**/*.html',
                        'assets/images/**/*.{png,gif,webp,jpg,jpeg,svg}',
                        'assets/fonts/*'
                    ]
                }, {
                    expand: true,
                    cwd: '.tmp/assets/images',
                    dest: '<%%= yeoman.dist %>/assets/images',
                    src: [
                        'generated/*'
                    ]
                }]
            },
            generateHerokuDirectory: {
                    expand: true,
                    dest: 'deploy/heroku',
                    src: [
                        'pom.xml',
                        'gradlew',
                        '*.gradle',
                        'gradle.properties',
                        'gradle/**',
                        'src/main/**'
                ]
            },
            generateOpenshiftDirectory: {
                    expand: true,
                    dest: 'deploy/openshift',
                    src: [
                        'pom.xml',
                        'src/main/**'
                ]
            }
        },
        concurrent: {
            server: [<% if (useCompass) { %>
                'compass:server'<% } %>
            ],
            test: [<% if (useCompass) { %>
                'compass'<% } %>
            ],
            dist: [<% if (useCompass) { %>
                'compass:dist',<% } %>
                'imagemin',
                'svgmin'
            ]
        },
        karma: {
            unit: {
                configFile: 'src/test/javascript/karma.conf.js',
                singleRun: true
            }
        },
        cdnify: {
            dist: {
                html: ['<%%= yeoman.dist %>/*.html']
            }
        },
        ngAnnotate: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '.tmp/concat/scripts',
                    src: '*.js',
                    dest: '.tmp/concat/scripts'
                }]
            }
        },
        buildcontrol: {
            options: {
                commit: true,
                push: false,
                connectCommits: false,
                message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%'
            },
            heroku: {
                options: {
                    dir: 'deploy/heroku',
                    remote: 'heroku',
                    branch: 'master'
                }
            },
            openshift: {
                options: {
                    dir: 'deploy/openshift',
                    remote: 'openshift',
                    branch: 'master'
                }
            }
        },
        ngconstant: {
            options: {
                name: '<%= angularAppName%>',
                deps: false,
                wrap: '"use strict";\n// DO NOT EDIT THIS FILE, EDIT THE GRUNT TASK NGCONSTANT SETTINGS INSTEAD WHICH GENERATES THIS FILE\n{%= __ngModule %}'
            },
            dev: {
                options: {
                    dest: 'src/main/webapp/scripts/app/app.constants.js'
                },
                constants: {
                    ENV: 'dev',
                    VERSION: <% if(buildTool == 'maven') { %>parseVersionFromPomXml()<% } else { %>parseVersionFromBuildGradle()<% } %>
                }
            },
            prod: {
                options: {
                    dest: '.tmp/scripts/app/app.constants.js'
                },
                constants: {
                    ENV: 'prod',
                    VERSION: <% if(buildTool == 'maven') { %>parseVersionFromPomXml()<% } else { %>parseVersionFromBuildGradle()<% } %>
                }
            }
        }
    });

    grunt.registerTask('serve', [
        'clean:server',
        'wiredep',
        'ngconstant:dev',
        'concurrent:server',
        'browserSync',
        'watch'
    ]);

    grunt.registerTask('server', function (target) {
        grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
        grunt.task.run([target ? ('serve:' + target) : 'serve']);
    });

    grunt.registerTask('test', [
        'clean:server',
        'wiredep:test',
        'ngconstant:dev',
        'concurrent:test',
        'karma'
    ]);

    grunt.registerTask('build', [
        'clean:dist',
        'wiredep:app',
        'ngconstant:prod',
        'useminPrepare',
        'ngtemplates',
        'concurrent:dist',
        'concat',
        'copy:dist',
        'ngAnnotate',
        'cssmin',
        'autoprefixer',
        'uglify',
        'rev',
        'usemin',
        'htmlmin'
    ]);

	grunt.registerTask('appendSkipBower', 'Force skip of bower for Gradle', function () {
		var filepath = 'deploy/heroku/gradle.properties';

		if (!grunt.file.exists(filepath)) {
			// Assume this is a maven project
			return true;
		}

		var fileContent = grunt.file.read(filepath);
		var skipBowerIndex = fileContent.indexOf("skipBower=true");

		if (skipBowerIndex != -1) {
			return true;
		}

		grunt.file.write(filepath, fileContent + "\nskipBower=true\n");
	});

    grunt.registerTask('buildHeroku', [
        'test',
        'build',
        'copy:generateHerokuDirectory',
        'appendSkipBower'
    ]);

    grunt.registerTask('deployHeroku', [
        'test',
        'build',
        'copy:generateHerokuDirectory',
        'appendSkipBower',
        'buildcontrol:heroku'
    ]);

    grunt.registerTask('buildOpenshift', [
        'test',
        'build',
        'copy:generateOpenshiftDirectory',
    ]);

    grunt.registerTask('deployOpenshift', [
        'test',
        'build',
        'copy:generateOpenshiftDirectory',
        'buildcontrol:openshift'
    ]);

    grunt.registerTask('default', [
        'test',
        'build'
    ]);
};
<|endoftext|>


<commit_before>var request = require('request');
var utils = require('./db/utils');
var NanoTimer = require('nanotimer');

var timer = new NanoTimer();

var port = process.env.PORT || 8080;
var io = require('socket.io')(port);

var dSay = function(msg) {
  console.log(msg);
  // push to some MQ or other storages for TTS
}

var tSay = function(msg) {
  console.log(msg);
  // push to some MQ or other storages for TTS
}

// Drones that we are currently connected with
var drones = {};

io.on('connection', function(socket){

  // socket.emit('whoYouAre',{});

  // Simple test socket communication
  socket.on('tellMyName', function(msg){
    socket.emit('greetings', 'hello world ' + msg.name); // emit with a string!
  });

//*********************************************************
// Client Server Communication
//*********************************************************

  socket.on('CT_allDronesState', function(msg){
    socket.emit('update', drones);
  });

//*********************************************************
// Drone Communication
//*********************************************************

  socket.on('DT_update', function(msg){
    dSay(msg.transcript);
    drones[msg.callSign] = msg;

    for ( d in drones ) {
      console.log(drones[d]);
    }
  });

  socket.on('DT_ack', function(msg){
    dSay(msg.transcript);
  });

  socket.on('DT_register', function(msg){
    dSay(msg.transcript);
    drones[msg.callSign] = msg;

    socket.emit('TD_fileInFlightPlan');
  });

  socket.on('DT_fileInFlightPlan', function(msg){
    dSay(msg.transcript);
    drones[msg.callSign] = msg;

    // check flight path
    // var approved = utils.checkPathConflicts(path stuff);

    socket.emit('TD_flightPlanDecision', {approved: true})
  });

  socket.on('DT_readyTakeOff', function(msg){
    dSay(msg.transcript);
    drones[msg.callSign] = msg;

    // maybe add some checks/tests b4 take off
    socket.emit('TD_takeOff')
  });

  // Tower requests all drones for an update every 4 seconds
  timer.setInterval(function(){
    socket.emit('TD_update', {});
  }, '', '4s');

  // On detect restriction zone 3 min ahead (interval check?)
  // tSay(transcript)
  // socket.emit('TD_notify',{transcript})
  //
  // On reroute creation
  // socket.emit('TD_changeRoute', {pivotPointInd, substitutePath})

});

// Client Example
// var socket = io.connect('http://server:port');
//
// socket.on('whoYouAre', function(msg){
//   socket.emit('tellMyName', { name:"Bob" }); // emit with an object!
// });

// socket.on('greetings', function(msg){
//   console.log(msg);
// });

// FlightPathCheck() {
//   pull restriction data from db;
//   calculate
//   notifies drones if anything goes wrong
// }
// setInterval(FlightPathCheck, 1500);
<commit_msg>still implementing sockt<commit_after>var request = require('request');
var utils = require('./db/utils');
var NanoTimer = require('nanotimer');

var timer = new NanoTimer();

var port = process.env.PORT || 8080;
var io = require('socket.io')(port);

var dSay = function(msg) {
  console.log(msg);
  // push to some MQ or other storages for TTS
}

var tSay = function(msg) {
  console.log(msg);
  // push to some MQ or other storages for TTS
}

// Drones that we are currently connected with
var drones = {};

io.on('connection', function(socket){

  // socket.emit('whoYouAre',{});

  // Simple test socket communication
  socket.on('tellMyName', function(msg){
    socket.emit('greetings', 'hello world ' + msg.name); // emit with a string!
  });

//*********************************************************
// Client Server Communication
//*********************************************************

  socket.on('CT_allDronesState', function(msg){
    socket.emit('update', drones);
  });

  socket.on('DT_addFlightPath', function(request) {
  /* input:  request.drone_id,  the id of the associated drone
          request.drone_operator_id, the id of the associated operator
          request.flight_start, the ISO string for the start date of the flight
          request.flight_end, the ISO string for th end date for the flight
          request.flightPathWGS84 the GeoJSON string for the proposed geometry.*/

 });

//*********************************************************
// Drone Communication
//*********************************************************

  socket.on('DT_update', function(msg){
    dSay(msg.transcript);
    drones[msg.callSign] = msg;

    for ( d in drones ) {
      console.log(drones[d]);
    }
  });

  socket.on('DT_ack', function(msg){
    dSay(msg.transcript);
  });

  socket.on('DT_register', function(msg){
    dSay(msg.transcript);
    drones[msg.callSign] = msg;

    socket.emit('TD_fileInFlightPlan');
  });

  socket.on('DT_fileInFlightPlan', function(msg){
    dSay(msg.transcript);
    drones[msg.callSign] = msg;

    // check flight path
    // var approved = utils.checkPathConflicts(path stuff);
    utils.getPathConflicts(request).exec(function(err, pathConflicts) {
      if (err) {
        socket.emit('TD_flightPlanDecision', {approved: false, error: err});
      }
      else if (pathConflicts.length === 0) {
        utils.addFlightPath(request).exec(function(err, pathInfo) {
          if (err) {
            socket.emit('TD_flightPlanDecision', {approved: false, error: err});
          } else {
            socket.emit('TD_flightPlanDecision', {approved: true});
          }
        });
      } else {
        socket.emit('TD_flightPlanDecision', {approved: false, pathConflicts: pathConflicts});
      }
    });

    socket.emit('TD_flightPlanDecision', {approved: true});
  });

  socket.on('DT_readyTakeOff', function(msg){
    dSay(msg.transcript);
    drones[msg.callSign] = msg;

    // maybe add some checks/tests b4 take off
    socket.emit('TD_takeOff')
  });

  // Tower requests all drones for an update every 4 seconds
  timer.setInterval(function(){
    socket.emit('TD_update', {});
  }, '', '4s');

  // On detect restriction zone 3 min ahead (interval check?)
  // tSay(transcript)
  // socket.emit('TD_notify',{transcript})
  //
  // On reroute creation
  // socket.emit('TD_changeRoute', {pivotPointInd, substitutePath})

});

// Client Example
// var socket = io.connect('http://server:port');
//
// socket.on('whoYouAre', function(msg){
//   socket.emit('tellMyName', { name:"Bob" }); // emit with an object!
// });

// socket.on('greetings', function(msg){
//   console.log(msg);
// });

// FlightPathCheck() {
//   pull restriction data from db;
//   calculate
//   notifies drones if anything goes wrong
// }
// setInterval(FlightPathCheck, 1500);
<|endoftext|>


<commit_before>import Ember from 'ember';
import C from 'ui/utils/constants';
import { parseCatalogSetting } from 'ui/utils/parse-catalog-setting';

export default Ember.Component.extend({
  settings: Ember.inject.service(),
  catalog: Ember.inject.service(),
  kindChoices: [
    {translationKey: 'catalogSettings.more.kind.native', value: 'native'},
    {translationKey: 'catalogSettings.more.kind.helm', value: 'helm'},
  ],

  initialValue: null,

  parsed: null,
  ary: null,
  enableLibrary: null,
  enableCommunity: null,

  actions: {
    add() {
      this.get('ary').pushObject(Ember.Object.create({name: '', branch: C.CATALOG.DEFAULT_BRANCH, kind: 'native', url: ''}));
      Ember.run.next(() => {
        if ( this.isDestroyed || this.isDestroying ) {
          return;
        }

        this.$('INPUT.name').last()[0].focus();
      });
    },

    remove(obj) {
      this.get('ary').removeObject(obj);
    },

    save(btnCb) {
      const def = C.CATALOG.DEFAULT_BRANCH;

      let map = {};
      // Start with ours, then load the users in case they override the value
      if (this.get('enableLibrary')) {
        map[C.CATALOG.LIBRARY_KEY] = {url: C.CATALOG.LIBRARY_VALUE, branch: C.CATALOG.LIBRARY_BRANCH};
      }

      if (this.get('enableCommunity')) {
        map[C.CATALOG.COMMUNITY_KEY] = {url: C.CATALOG.COMMUNITY_VALUE, branch: C.CATALOG.COMMUNITY_BRANCH};
      }

      // Load the user's non-empty rows
      this.get('ary').forEach((row) => {
        let name = (row.name||'').trim();
        let url = (row.url||'').trim();
        let branch = (row.branch||'').trim() || def;
        let kind = (row.kind||'').trim() || 'native';

        if (name && url) {
          map[name] = {url: url, branch: branch, kind: kind};
        }
      });

      let neu = this.get('parsed')||{};
      neu.catalogs = map;

      this.get('settings').set(C.SETTING.CATALOG_URL, JSON.stringify(neu));
      this.get('settings').one('settingsPromisesResolved', () => {
        btnCb(true);
        this.sendAction('saved');
        this.get('catalog').reset();
      });
    },
  },

  init() {
    this._super(...arguments);

    const def = C.CATALOG.DEFAULT_BRANCH;
    let parsed = parseCatalogSetting(this.get('initialValue'));
    let map = parsed.catalogs || {};

    let library = false;
    let entry = map[C.CATALOG.LIBRARY_KEY];
    if ( entry && entry.url === C.CATALOG.LIBRARY_VALUE && entry.branch === C.CATALOG.LIBRARY_BRANCH ) {
      library = true;
      delete map[C.CATALOG.LIBRARY_KEY];
    }

    let community = false;
    entry = map[C.CATALOG.COMMUNITY_KEY]
    if ( entry && entry.url === C.CATALOG.COMMUNITY_VALUE && entry.branch === C.CATALOG.COMMUNITY_BRANCH ) {
      community = true;
      delete map[C.CATALOG.COMMUNITY_KEY];
    }

    var ary = [];
    Object.keys(map).forEach((name) => {
      ary.push(Ember.Object.create({name: name, kind: map[name].kind||'native', branch: map[name].branch, url: map[name].url}));
    });

    this.setProperties({
      ary: ary,
      parsed: parsed,
      enableLibrary: library,
      enableCommunity: community
    });
  },
});
<commit_msg>test fix<commit_after>import Ember from 'ember';
import C from 'ui/utils/constants';
import { parseCatalogSetting } from 'ui/utils/parse-catalog-setting';

export default Ember.Component.extend({
  settings: Ember.inject.service(),
  catalog: Ember.inject.service(),
  kindChoices: [
    {translationKey: 'catalogSettings.more.kind.native', value: 'native'},
    {translationKey: 'catalogSettings.more.kind.helm', value: 'helm'},
  ],

  initialValue: null,

  parsed: null,
  ary: null,
  enableLibrary: null,
  enableCommunity: null,

  actions: {
    add() {
      this.get('ary').pushObject(Ember.Object.create({name: '', branch: C.CATALOG.DEFAULT_BRANCH, kind: 'native', url: ''}));
      Ember.run.next(() => {
        if ( this.isDestroyed || this.isDestroying ) {
          return;
        }

        this.$('INPUT.name').last()[0].focus();
      });
    },

    remove(obj) {
      this.get('ary').removeObject(obj);
    },

    save(btnCb) {
      const def = C.CATALOG.DEFAULT_BRANCH;

      let map = {};
      // Start with ours, then load the users in case they override the value
      if (this.get('enableLibrary')) {
        map[C.CATALOG.LIBRARY_KEY] = {url: C.CATALOG.LIBRARY_VALUE, branch: C.CATALOG.LIBRARY_BRANCH};
      }

      if (this.get('enableCommunity')) {
        map[C.CATALOG.COMMUNITY_KEY] = {url: C.CATALOG.COMMUNITY_VALUE, branch: C.CATALOG.COMMUNITY_BRANCH};
      }

      // Load the user's non-empty rows
      this.get('ary').forEach((row) => {
        let name = (row.name||'').trim();
        let url = (row.url||'').trim();
        let branch = (row.branch||'').trim() || def;
        let kind = (row.kind||'').trim() || 'native';

        if (name && url) {
          map[name] = {url: url, branch: branch, kind: kind};
        }
      });

      let neu = this.get('parsed')||{};
      neu.catalogs = map;

      this.get('settings').set(C.SETTING.CATALOG_URL, JSON.stringify(neu));
      this.get('settings').one('settingsPromisesResolved', () => {
        btnCb(true);
        this.sendAction('saved');
        this.get('catalog').reset();
      });
    },
  },

  init() {
    this._super(...arguments);

    // const def = C.CATALOG.DEFAULT_BRANCH;
    let parsed = parseCatalogSetting(this.get('initialValue'));
    let map = parsed.catalogs || {};

    let library = false;
    let entry = map[C.CATALOG.LIBRARY_KEY];
    if ( entry && entry.url === C.CATALOG.LIBRARY_VALUE && entry.branch === C.CATALOG.LIBRARY_BRANCH ) {
      library = true;
      delete map[C.CATALOG.LIBRARY_KEY];
    }

    let community = false;
    entry = map[C.CATALOG.COMMUNITY_KEY]
    if ( entry && entry.url === C.CATALOG.COMMUNITY_VALUE && entry.branch === C.CATALOG.COMMUNITY_BRANCH ) {
      community = true;
      delete map[C.CATALOG.COMMUNITY_KEY];
    }

    var ary = [];
    Object.keys(map).forEach((name) => {
      ary.push(Ember.Object.create({name: name, kind: map[name].kind||'native', branch: map[name].branch, url: map[name].url}));
    });

    this.setProperties({
      ary: ary,
      parsed: parsed,
      enableLibrary: library,
      enableCommunity: community
    });
  },
});
<|endoftext|>


<commit_before>/***********************************************
||          WELCOME TO EGGS GENNNY's          ||
||                gulpfile.js                 ||
||                                            ||
||     Alter to suit your needs, this is      ||
||          just a starting place =)          ||
||                                            ||
************************************************/

/***********************************************
**               Require Stuff                **
************************************************/
var gulp    = require('gulp'),
    connect = require('connect'),
    chalk   = require('chalk'),
    del     = require('del'),
    dirlist = require('dirlist'),
    glob    = require('glob'),
    plug    = require('gulp-load-plugins')({
              scope: ['devDependencies'],
              replaceString: 'gulp-',
            }),
//  Here's where you can specify which browsers Autoprefixer tests against
//  The default you see here goes back really far, in reality something like 'last 2 versions' gets you > 90% coverage
    supportedBrowsers = [ 'last 4 versions', '> 0.5%', 'ie 7', 'ff 3', 'Firefox ESR', 'Android 2.1' ];

/***********************************************
**          Default Task (dev/watch)          **
************************************************/
gulp.task( 'default', [ 'serve-me', 'reload-me' ]);

/***********************************************
**          Development/Watch Task            **
************************************************/
gulp.task( 'reload-me', function(){

  gulp.watch( 'app/css/*.less', ['compile-me'] );
  gulp.watch( 'app/js/*.js', ['validate-js'] );

  plug.livereload.listen();
  gulp.watch( ['app/css/*.css', 'app/js/*.js', 'app/index.html'<% if(deps.angular){ %>, 'app/partials/*.html'<% } %> ], function(){
    loggit("I've reloaded your page, <% if(greeting === 'sir'){ %>sir!<% } if(greeting === 'ma\'am'){ %>ma'am!<% } if(greeting === 'cap\'n'){ %>cap'n!<% } if(greeting === 'homie'){ %>homie!<% } if(greeting === 'hombre'){ %>hombre!<% } %>\n    "+timePlz());
  })
  .on('change', plug.livereload.changed);
});

/***********************************************
**               Server Task                  **
************************************************/
gulp.task( 'serve-me', function(){

  var base = __dirname,
      host = "localhost",
      port = 6969;

  connect(  connect.favicon(),
          dirlist(base),
          connect.static(base) ).listen(port, host);
  loggit('Server running at http://'+host+':'+port+'/');

});

/***********************************************
**              Validation Task               **
************************************************/
gulp.task( 'validate-me', [ 'validate-js', 'validate-css' ]);

//  VALIDATION JS
gulp.task( 'validate-js', function(){

  return gulp.src('app/js/*.js')
          .pipe(plug.jshint())
          .pipe(plug.jshint.reporter('default'));

});
//  VALIDATION CSS
gulp.task( 'validate-css', function(){

  return gulp.src('app/css/*.css')
          .pipe(plug.csslint())
          .pipe(plug.csslint.reporter(CSSReport));

});

/***********************************************
**                   build                    **
************************************************/

gulp.task( 'build', [ 'compile-me', 'css-me', <% if (deps.angular) { %>'annotate-me', 'partials-me',<% } %>'js-me', 'assets-me', 'html-me', 'clean-me', 'uncss-me' ]);

//  LESS compile
gulp.task( 'compile-me', function(){

  return gulp.src('app/css/*.less')
          .pipe( plug.less() )
          .on('error', errorLog)
          .pipe( gulp.dest('app/css/') );

});
//  CSSTASKS
gulp.task( 'css-me', ['compile-me'], function(){

  return  gulp.src( [ <% if (deps.bootstrap) { %>'app/lib/bootstrap.css',<% } %> 'app/css/*.css' ] )
            .pipe( plug.concat('styles.css') )
            .pipe( gulp.dest( 'tmp/css' ) )
            .pipe( plug.autoprefixer({
                      browsers: supportedBrowsers,
                      cascade: false
                    }))
            .pipe( plug.csscomb() )
            .pipe( gulp.dest( 'build/css/' ) );

});
gulp.task( 'uncss-me', ['css-me',<% if (deps.angular) { %> 'partials-me',<% } %> 'html-me'], function(){

  return gulp.src('build/css/styles.css')
          .pipe(plug.uncss({
            html: <% if (deps.angular) { %>glob.sync('build/**/*.html')<% }else { %>['build/index.html']<% } %>
          }))
          .pipe( plug.minifyCss() )
          .pipe(gulp.dest('build/css/'));
});

//  JSTASKS
<% if (deps.angular) { %>
gulp.task( 'annotate-me',  function(){

  return  gulp.src( 'app/js/app.js' )
          .pipe( plug.ngAnnotate() )
          .on('error', errorLog)
          .pipe(gulp.dest('app/js/'));

});
<% } %>gulp.task( 'js-me',<% if (deps.angular) { %> ['annotate-me'],<% } %> function(){

  return  gulp.src([<% if (deps.jquery) { %>
                  'app/lib/js/jquery.js',<% } if(deps.angular){ %>
                  'app/lib/js/angular.js',<% } if(deps.gsap){ if(deps.gsap.minMax === 'TweenLite'){ %>
                  'app/lib/js/TweenLite.js',
                  'app/lib/js/TimelineLite.js',<% }else { %>
                  'app/lib/js/TweenMax.js',
                  'app/lib/js/TimelineMax.js',<% } deps.gsap.plugs.forEach(function(plug){ %>
                  'app/lib/js/<%= plug %>.js',<% }) } %>
                  'app/js/*.js' ])
          .pipe( plug.concat('scripts.js') )
          .pipe( gulp.dest( 'tmp/js' ) )
          .pipe( plug.uglify( {mangle: false} ) )
          .pipe( gulp.dest( 'build/js' ) );

});

//MOVE ASSETS
gulp.task( 'assets-me', function(){

  //  IMAGES
  gulp.src( 'app/img/*' )
    .pipe(plug.imagemin({
      progressive: true,
      optimizationLevel: 5
    }))
    .pipe( gulp.dest('build/img/') );
  //  Favicon move
  gulp.src( 'app/favicon.ico' )
    .pipe( gulp.dest('build/favicon.ico') );

});<%  if(deps.angular){ %>

gulp.task( 'partials-me', function(){

  return gulp.src( 'app/partials/*' )
          .pipe(plug.angularHtmlify())
          .pipe( gulp.dest('build/partials/') );

});<% } %>

//HTMLMOVE/REPLACE
gulp.task( 'html-me', function(){

  return gulp.src( 'app/index.html' )<%  if(deps.angular){ %>
          .pipe(plug.angularHtmlify())
          <% } %>.pipe(plug.htmlReplace({
              css: {
                src: 'css/styles.css',
                tpl: '  <link rel="stylesheet" type="text/css" href="%s" />'
              },
              js: {
                src: 'js/scripts.js',
                tpl: '  <script type="text/javascript" src="%s"></script>'
              }
          }))
          .pipe(gulp.dest( 'build/' ));
});

gulp.task( 'clean-me', [ 'css-me', 'js-me' ], function(){

  var dels = 'Cleaned up the following: \n';
  del( ['tmp/**','tmp'] , function (err, deletedFiles) {
    deletedFiles.forEach( function( val, index ){
        dels +=  '  - '+val+'\n';
    });
    loggit(dels);
  });

});

/***********************************************
**          Utility/Logging Functions         **
**   Nothing (gulp) to see here, move along   **
************************************************/
var loggit = function (l){
  var log = "*****************************************\n"+
            l+"\n"+
            "*****************************************\n";
  console.log( chalk.cyan(log) );
},
errorLog = function (er){
  var log = "*****************************************\n"+
            "**          CATASTROPHIC ERROR!        **\n"+
            "**                                     **\n"+
            "**       User attempted to use the     **\n"+
            "**     program in the manner it was    **\n"+
            "**          intended to be used!       **\n"+
            "**                                     **\n"+
            "**            ERROR MESSAGE:           **\n"+
            "**                                     **\n"+
            er+"\n"+
            "*****************************************\n";

  console.log( chalk.red( log )  );
},
timePlz = function(){

  var D  = new Date(),
      h  = D.getHours(),
      m  = D.getMinutes(),
      s  = D.getSeconds(),
      dt = D.getDate(),
      yr = D.getFullYear(),
      months = [
        "January",
        "February",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
        "October",
        "November",
        "December"
      ],
      mt = months[D.getMonth()];

      //  convert to 12 hour time
      if(h > 12){ h = h - 12; }
      if(h === 0){ h = 12; }

      //  in case seconds is lower than 10
      if( s < 10 ){ s = '0' + s; }

      return mt + ' ' + dt + ', ' + yr + ' at ' + h + ':' + m + ':' + s;

},
CSSReport = function(file) {

  var ers = file.csslint.errorCount+' errors in '+file.path+'\n';

  file.csslint.results.forEach(function(result) {

    var col = 'yellow';
    if( result.error.type === "error" ){
      col = "red";
    }

    if(result.error.line !== undefined){
      ers += chalk.underline[col]('LINE '+result.error.line+':') + ' ' +result.error.message + "\n";
    }else{
      ers += chalk.underline.green('GENERAL:') + ' ' + result.error.message + "\n";
    }

  });

  loggit(ers);

};
<commit_msg>fixes #18 bootstrap css location<commit_after>/***********************************************
||          WELCOME TO EGGS GENNNY's          ||
||                gulpfile.js                 ||
||                                            ||
||     Alter to suit your needs, this is      ||
||          just a starting place =)          ||
||                                            ||
************************************************/

/***********************************************
**               Require Stuff                **
************************************************/
var gulp    = require('gulp'),
    connect = require('connect'),
    chalk   = require('chalk'),
    del     = require('del'),
    dirlist = require('dirlist'),
    glob    = require('glob'),
    plug    = require('gulp-load-plugins')({
              scope: ['devDependencies'],
              replaceString: 'gulp-',
            }),
//  Here's where you can specify which browsers Autoprefixer tests against
//  The default you see here goes back really far, in reality something like 'last 2 versions' gets you > 90% coverage
    supportedBrowsers = [ 'last 4 versions', '> 0.5%', 'ie 7', 'ff 3', 'Firefox ESR', 'Android 2.1' ];

/***********************************************
**          Default Task (dev/watch)          **
************************************************/
gulp.task( 'default', [ 'serve-me', 'reload-me' ]);

/***********************************************
**          Development/Watch Task            **
************************************************/
gulp.task( 'reload-me', function(){

  gulp.watch( 'app/css/*.less', ['compile-me'] );
  gulp.watch( 'app/js/*.js', ['validate-js'] );

  plug.livereload.listen();
  gulp.watch( ['app/css/*.css', 'app/js/*.js', 'app/index.html'<% if(deps.angular){ %>, 'app/partials/*.html'<% } %> ], function(){
    loggit("I've reloaded your page, <% if(greeting === 'sir'){ %>sir!<% } if(greeting === 'ma\'am'){ %>ma'am!<% } if(greeting === 'cap\'n'){ %>cap'n!<% } if(greeting === 'homie'){ %>homie!<% } if(greeting === 'hombre'){ %>hombre!<% } %>\n    "+timePlz());
  })
  .on('change', plug.livereload.changed);
});

/***********************************************
**               Server Task                  **
************************************************/
gulp.task( 'serve-me', function(){

  var base = __dirname,
      host = "localhost",
      port = 6969;

  connect(  connect.favicon(),
          dirlist(base),
          connect.static(base) ).listen(port, host);
  loggit('Server running at http://'+host+':'+port+'/');

});

/***********************************************
**              Validation Task               **
************************************************/
gulp.task( 'validate-me', [ 'validate-js', 'validate-css' ]);

//  VALIDATION JS
gulp.task( 'validate-js', function(){

  return gulp.src('app/js/*.js')
          .pipe(plug.jshint())
          .pipe(plug.jshint.reporter('default'));

});
//  VALIDATION CSS
gulp.task( 'validate-css', function(){

  return gulp.src('app/css/*.css')
          .pipe(plug.csslint())
          .pipe(plug.csslint.reporter(CSSReport));

});

/***********************************************
**                   build                    **
************************************************/

gulp.task( 'build', [ 'compile-me', 'css-me', <% if (deps.angular) { %>'annotate-me', 'partials-me',<% } %>'js-me', 'assets-me', 'html-me', 'clean-me', 'uncss-me' ]);

//  LESS compile
gulp.task( 'compile-me', function(){

  return gulp.src('app/css/*.less')
          .pipe( plug.less() )
          .on('error', errorLog)
          .pipe( gulp.dest('app/css/') );

});
//  CSSTASKS
gulp.task( 'css-me', ['compile-me'], function(){

  return  gulp.src( [ <% if (deps.bootstrap) { %>'app/lib/css/bootstrap.css',<% } %> 'app/css/*.css' ] )
            .pipe( plug.concat('styles.css') )
            .pipe( gulp.dest( 'tmp/css' ) )
            .pipe( plug.autoprefixer({
                      browsers: supportedBrowsers,
                      cascade: false
                    }))
            .pipe( plug.csscomb() )
            .pipe( gulp.dest( 'build/css/' ) );

});
gulp.task( 'uncss-me', ['css-me',<% if (deps.angular) { %> 'partials-me',<% } %> 'html-me'], function(){

  return gulp.src('build/css/styles.css')
          .pipe(plug.uncss({
            html: <% if (deps.angular) { %>glob.sync('build/**/*.html')<% }else { %>['build/index.html']<% } %>
          }))
          .pipe( plug.minifyCss() )
          .pipe(gulp.dest('build/css/'));
});

//  JSTASKS
<% if (deps.angular) { %>
gulp.task( 'annotate-me',  function(){

  return  gulp.src( 'app/js/app.js' )
          .pipe( plug.ngAnnotate() )
          .on('error', errorLog)
          .pipe(gulp.dest('app/js/'));

});
<% } %>gulp.task( 'js-me',<% if (deps.angular) { %> ['annotate-me'],<% } %> function(){

  return  gulp.src([<% if (deps.jquery) { %>
                  'app/lib/js/jquery.js',<% } if(deps.angular){ %>
                  'app/lib/js/angular.js',<% } if(deps.gsap){ if(deps.gsap.minMax === 'TweenLite'){ %>
                  'app/lib/js/TweenLite.js',
                  'app/lib/js/TimelineLite.js',<% }else { %>
                  'app/lib/js/TweenMax.js',
                  'app/lib/js/TimelineMax.js',<% } deps.gsap.plugs.forEach(function(plug){ %>
                  'app/lib/js/<%= plug %>.js',<% }) } %>
                  'app/js/*.js' ])
          .pipe( plug.concat('scripts.js') )
          .pipe( gulp.dest( 'tmp/js' ) )
          .pipe( plug.uglify( {mangle: false} ) )
          .pipe( gulp.dest( 'build/js' ) );

});

//MOVE ASSETS
gulp.task( 'assets-me', function(){

  //  IMAGES
  gulp.src( 'app/img/*' )
    .pipe(plug.imagemin({
      progressive: true,
      optimizationLevel: 5
    }))
    .pipe( gulp.dest('build/img/') );
  //  Favicon move
  gulp.src( 'app/favicon.ico' )
    .pipe( gulp.dest('build/favicon.ico') );

});<%  if(deps.angular){ %>

gulp.task( 'partials-me', function(){

  return gulp.src( 'app/partials/*' )
          .pipe(plug.angularHtmlify())
          .pipe( gulp.dest('build/partials/') );

});<% } %>

//HTMLMOVE/REPLACE
gulp.task( 'html-me', function(){

  return gulp.src( 'app/index.html' )<%  if(deps.angular){ %>
          .pipe(plug.angularHtmlify())
          <% } %>.pipe(plug.htmlReplace({
              css: {
                src: 'css/styles.css',
                tpl: '  <link rel="stylesheet" type="text/css" href="%s" />'
              },
              js: {
                src: 'js/scripts.js',
                tpl: '  <script type="text/javascript" src="%s"></script>'
              }
          }))
          .pipe(gulp.dest( 'build/' ));
});

gulp.task( 'clean-me', [ 'css-me', 'js-me' ], function(){

  var dels = 'Cleaned up the following: \n';
  del( ['tmp/**','tmp'] , function (err, deletedFiles) {
    deletedFiles.forEach( function( val, index ){
        dels +=  '  - '+val+'\n';
    });
    loggit(dels);
  });

});

/***********************************************
**          Utility/Logging Functions         **
**   Nothing (gulp) to see here, move along   **
************************************************/
var loggit = function (l){
  var log = "*****************************************\n"+
            l+"\n"+
            "*****************************************\n";
  console.log( chalk.cyan(log) );
},
errorLog = function (er){
  var log = "*****************************************\n"+
            "**          CATASTROPHIC ERROR!        **\n"+
            "**                                     **\n"+
            "**       User attempted to use the     **\n"+
            "**     program in the manner it was    **\n"+
            "**          intended to be used!       **\n"+
            "**                                     **\n"+
            "**            ERROR MESSAGE:           **\n"+
            "**                                     **\n"+
            er+"\n"+
            "*****************************************\n";

  console.log( chalk.red( log )  );
},
timePlz = function(){

  var D  = new Date(),
      h  = D.getHours(),
      m  = D.getMinutes(),
      s  = D.getSeconds(),
      dt = D.getDate(),
      yr = D.getFullYear(),
      months = [
        "January",
        "February",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
        "October",
        "November",
        "December"
      ],
      mt = months[D.getMonth()];

      //  convert to 12 hour time
      if(h > 12){ h = h - 12; }
      if(h === 0){ h = 12; }

      //  in case seconds is lower than 10
      if( s < 10 ){ s = '0' + s; }

      return mt + ' ' + dt + ', ' + yr + ' at ' + h + ':' + m + ':' + s;

},
CSSReport = function(file) {

  var ers = file.csslint.errorCount+' errors in '+file.path+'\n';

  file.csslint.results.forEach(function(result) {

    var col = 'yellow';
    if( result.error.type === "error" ){
      col = "red";
    }

    if(result.error.line !== undefined){
      ers += chalk.underline[col]('LINE '+result.error.line+':') + ' ' +result.error.message + "\n";
    }else{
      ers += chalk.underline.green('GENERAL:') + ' ' + result.error.message + "\n";
    }

  });

  loggit(ers);

};
<|endoftext|>


<commit_before>var definition = {
    frame: {
        header: [ 16, {
            fin: 1, rsv1: 1, rsv2: 1, rsv3: 1, opcode: 4,
            mask: 1, length: 7
        } ],
        length: [ function (object) {
            switch (object.header.length) {
                case 127:
                    return 0
                case 126:
                    return 1
                default:
                    object.length = object.header.length
            }
        }, 16, 32 ],
        mask: [ function (object) {
            return object.mask ? 1 : 0
        }, 0, 16 ]
    },
    mysql: {
        value: [ 8, function (value) {
            if (value < 0xfb) {
                return 0
            } else if (value & 0xfc) {
                return 1
            }
        }, 'b8', [ 'x8', 'b16' ] ]
    }
}

var packets = {
    frame: function (object, parsing) {
        if (!parsing) {
            header.mask = object.mask == null ? 0 : 1
        }
        _(object.header, {
            fin: 1, rsv1: 1, rsv2: 2, rsv3: 3, opcode: 4,
            mask: 1, length: 7
        })
        if (header.length == 127) {
            _(header.length, 16)
        } else if (header.length == 126) {
            _(header.length, 32)
        } else if (parsing) {
            object.length = header.length
        }
        if (header.mask) {
            _(object.mask, 16)
        }
    },
    mysql: function (object) {
        if (parsing) {
            _(object.value, 8)
            if (object.value & 0x0fc) {
                _(object.value, 16)
            } else if (object.value & 0xfd) {
                _(object.value, 24)
            } else if (object.value & 0xfe) {
                _(object.value, 64)
            }
        } else {
            if (object.value < 251) {
                _(object.value, 8)
            } else if (object.value > 251 && object.value < 0xffff) {
                _(0xfc)
                _(object.value, 16)
            } else if (object.value >= 0xffff && object.value < 0xffffff) {
                _(0xfd)
                _(object.value, 24)
            } else {
                _(0xfe)
                _(object.value, 64)
            }
        }
    },
    nested: function (object) {
        _(object.numbers, 16, [32])
        _(object.structures, 16, [function (struct) {
            _(struct.count, packets.mysql)
            _(struct.string, [8], [0])
        }])
    }
}

packets.lengthEncoded = function (_, object) {
    _(object.array, 16, [function () {
        _('name', 'b16')
    }])
}

packets.wsframe = function (_) {
    _(16, { fin: 1, rsv1: 1, rsv2: 1, rsv3: 1, opcode: 4,
            mask: 1, length: 7 })
}

var packets = {
    frame: function (object) {
        if (serializing) {
            header.mask = object.mask == null ? 0 : 1
        }
        header = packed(object.header, 16, {
            fin: 1, rsv1: 1, rsv2: 2, rsv3: 3, opcode: 4,
            mask: 1, length: 7
        })
        switch (header.length) {
        case 127:
            unsigned(header.length, 16)
        case 126:
            unsigned(header.length, 32)
        default:
            if (parsing) {
                object.length = header.length
            }
        }
        if (header.mask) {
            unsigned(object.mask, 16)
        }
    },
    mysql: function (object) {
        object.value = get(8)
        if (object.value & 0xfc) {
            object.value = get(16)
        }
    },
    nested: function (object) {
    }
}
<commit_msg>Further thoughts on language.<commit_after>var definition = {
    frame: {
        header: [ 16, {
            fin: 1, rsv1: 1, rsv2: 1, rsv3: 1, opcode: 4,
            mask: 1, length: 7
        } ],
        length: [ function (object) {
            switch (object.header.length) {
                case 127:
                    return 0
                case 126:
                    return 1
                default:
                    object.length = object.header.length
            }
        }, 16, 32 ],
        mask: [ function (object) {
            return object.mask ? 1 : 0
        }, 0, 16 ]
    },
    mysql: {
        value: [ 8, function (value) {
            if (value < 0xfb) {
                return 0
            } else if (value & 0xfc) {
                return 1
            }
        }, 'b8', [ 'x8', 'b16' ] ]
    }
}

var packets = {
    frame: function (object, parsing) {
        if (!parsing) {
            header.mask = object.mask == null ? 0 : 1
        }
        _(object.header, {
            fin: 1, rsv1: 1, rsv2: 2, rsv3: 3, opcode: 4,
            mask: 1, length: 7
        })
        if (header.length == 127) {
            _(header.length, 16)
        } else if (header.length == 126) {
            _(header.length, 32)
        } else if (parsing) {
            object.length = header.length
        }
        if (header.mask) {
            _(object.mask, 16)
        }
    },
    mysql: function (object) {
        if (parsing) {
            _(object.value, 8)
            if (object.value & 0x0fc) {
                _(object.value, 16)
            } else if (object.value & 0xfd) {
                _(object.value, 24)
            } else if (object.value & 0xfe) {
                _(object.value, 64)
            }
        } else {
            if (object.value < 251) {
                _(object.value, 8)
            } else if (object.value > 251 && object.value < 0xffff) {
                _(0xfc)
                _(object.value, 16)
            } else if (object.value >= 0xffff && object.value < 0xffffff) {
                _(0xfd)
                _(object.value, 24)
            } else {
                _(0xfe)
                _(object.value, 64)
            }
        }
    },
    nested: function (object) {
        _(object.numbers, 16, [32])
        _(object.structures, 16, [function (struct) {
            _(struct.count, packets.mysql)
            _(struct.string, [8], [0])
        }])
    }
}

packets.lengthEncoded = function (_, object) {
    _(object.array, 16, [function () {
        _('name', 'b16')
    }])
}

packets.websocket = function (_, object) {
    _('header', function (_) {
        _({ fin: 1, rsv1: 1, rsv2: 1, rsv3: 1, opcode: 4, mask: 1, length: 7 }))
    })
    var header = object.header
    if (header.length == 127) {
        _('length', 16)
    } else if (header.length == 126) {
        _('length', 32)
    } else if (parsing) {
        object.length = header.length
    }
    if (header.mask == 1) {
        _(object.mask, 16)
    }
}

var packets = {
    frame: function (object) {
        if (serializing) {
            header.mask = object.mask == null ? 0 : 1
        }
        header = packed(object.header, 16, {
            fin: 1, rsv1: 1, rsv2: 2, rsv3: 3, opcode: 4,
            mask: 1, length: 7
        })
        switch (header.length) {
        case 127:
            unsigned(header.length, 16)
        case 126:
            unsigned(header.length, 32)
        default:
            if (parsing) {
                object.length = header.length
            }
        }
        if (header.mask) {
            unsigned(object.mask, 16)
        }
    },
    mysql: function (object) {
        object.value = get(8)
        if (object.value & 0xfc) {
            object.value = get(16)
        }
    },
    nested: function (object) {
    }
}
<|endoftext|>


<commit_before>'use strict';
const SocketServer = require('ws').Server;
const express      = require('express');
const request      = require('request');
const crypto       = require('crypto');
const sharp        = require('sharp');
const path         = require('path');
const url          = require('url');
const aws          = require('aws-sdk');
const fs           = require('fs');

const S3_BUCKET = process.env.S3_BUCKET || 'bandwidth-hero';
const JPEG_QLT  = process.env.JPEG_QUALITY || 40;
const PORT      = process.env.PORT || 5000;

const server = express()
    .use((req, res) => res.end('Bandwidth Hero Server'))
    .listen(PORT, () => console.log(`Listening on ${ PORT }`));

const wss = new SocketServer({server});

wss.on('connection', ws => {
    console.log('Client connected');

    ws.on('message', message => processImage(ws, JSON.parse(message)));
    ws.on('close', () => console.log('Client disconnected'));
});

function processImage(socket, message) {
    const imageUrl = url.parse(message.url);
    if (!imageUrl) return;

    const key = generateS3FileKey(imageUrl);
    const s3 = new aws.S3({params: {Bucket: S3_BUCKET, Key: key}});

    s3.headObject(err => {
        if (!err) {
            const compressed = `https://${S3_BUCKET}.s3.amazonaws.com/${key}`;
            console.log(`From cache: ${message.url} => ${compressed}`);
            respond(compressed);
        } else if (err.code == 'NotFound') {
            var failed = false;
            const transformer = prepareImageTransformer();
            const stream = request(message.url).pipe(transformer);

            transformer.on('error', err => {
                console.log(`Error in ${message.url}:`);
                console.log(err);
                failed = true;
            });

            s3.upload({Body: stream}, (err, data) => {
                if (!err && !failed) {
                    console.log(`Compressed: ${message.url} => ${data.Location}`);
                    respond(data.Location);
                }
            });
        }
    });

    function respond(compressedImageUrl) {
        socket.send(JSON.stringify({
            tabId: message.tabId,
            original: message.url,
            compressed: compressedImageUrl
        }));
    }
}

function generateS3FileKey(imageUrl) {
    const dir = crypto
        .createHash('sha1')
        .update(imageUrl.host)
        .digest('hex');
    const filename = crypto
        .createHash('sha1')
        .update(path.basename(imageUrl.path))
        .digest('hex');
    const extension = path.extname(imageUrl.pathname);

    return `${dir}/${filename}${extension}`;
}

function prepareImageTransformer() {
    return sharp()
        .grayscale()
        .normalise()
        .quality(JPEG_QLT)
        .progressive()
        .toFormat('jpeg');
}
<commit_msg>Refactor server implementation<commit_after>'use strict';
const SocketServer = require('ws').Server;
const express      = require('express');
const request      = require('request');
const crypto       = require('crypto');
const sharp        = require('sharp');
const path         = require('path');
const url          = require('url');
const aws          = require('aws-sdk');
const fs           = require('fs');

const S3_BUCKET = process.env.S3_BUCKET || 'bandwidth-hero';
const JPEG_QLT  = process.env.JPEG_QUALITY || 40;
const PORT      = process.env.PORT || 5000;

const server = express()
    .use((req, res) => res.end('Bandwidth Hero Server'))
    .listen(PORT, () => console.log(`Listening on ${ PORT }`));

const wss = new SocketServer({server});

wss.on('connection', ws => {
    console.log('Client connected');

    ws.on('message', processImage);
    ws.on('close', () => console.log('Client disconnected'));

    function processImage(imageUrl) {
        const parsedUrl = url.parse(imageUrl);
        if (!parsedUrl) return;

        const key = generateS3FileKey(parsedUrl);
        const s3 = new aws.S3({params: {Bucket: S3_BUCKET, Key: key}});

        s3.headObject(err => {
            if (!err) {
                const compressed = `https://${S3_BUCKET}.s3.amazonaws.com/${key}`;
                console.log(`From cache: ${imageUrl} => ${compressed}`);
                respond(compressed);
            } else if (err.code == 'NotFound') {
                var failed = false;
                const transformer = prepareImageTransformer();
                const stream = request(imageUrl).pipe(transformer);

                transformer.on('error', err => {
                    console.log(`Error in ${imageUrl}:`);
                    console.log(err);
                    failed = true;
                });

                s3.upload({Body: stream}, (err, data) => {
                    if (!err && !failed) {
                        console.log(`Compressed: ${imageUrl} => ${data.Location}`);
                        respond(data.Location);
                    }
                });
            }
        });

        function respond(compressedImageUrl) {
            ws.send(JSON.stringify({
                original: imageUrl,
                compressed: compressedImageUrl
            }));
        }
    }
});

function generateS3FileKey(imageUrl) {
    const dir = crypto
        .createHash('sha1')
        .update(imageUrl.host)
        .digest('hex');
    const filename = crypto
        .createHash('sha1')
        .update(path.basename(imageUrl.path))
        .digest('hex');
    const extension = path.extname(imageUrl.pathname);

    return `${dir}/${filename}${extension}`;
}

function prepareImageTransformer() {
    return sharp()
        .grayscale()
        .normalise()
        .quality(JPEG_QLT)
        .progressive()
        .toFormat('jpeg');
}
<|endoftext|>


<commit_before>import rangy from 'rangy'
import error from './util/error'
import * as nodeType from './node-type'

/**
 * Inspired by the Selection save and restore module for Rangy by Tim Down
 * Saves and restores ranges using invisible marker elements in the DOM.
 */
let boundaryMarkerId = 0

// (U+FEFF) zero width no-break space
const markerTextChar = '\ufeff'

function isChildOf (parent, possibleChild) {
  for (let i = 0; i < parent.children.length; i++) {
    if (parent.children[i] === possibleChild) return true
  }
  return false
}

function startContainerIsChild (range) {
  const parent = range.endContainer.parentElement
  const possibleChild = range.startContainer.parentElement
  return isChildOf(parent, possibleChild)
}

function endContainerIsChild (range) {
  const parent = range.startContainer.parentElement
  const possibleChild = range.endContainer.parentElement
  return isChildOf(parent, possibleChild)
}

export function insertRangeBoundaryMarker (range, atStart) {
  const container = range.commonAncestorContainer
  const directlyBeforeFormatTag = startContainerIsChild(range) && atStart
  const directlyAfterFormatTag = endContainerIsChild(range) && !atStart

  // If ownerDocument is null the commonAncestorContainer is window.document
  if (container.ownerDocument === null || container.ownerDocument === undefined) {
    error('Cannot save range: range is emtpy')
  }

  // Create the marker element containing a single
  // invisible character using DOM methods and insert it
  const doc = container.ownerDocument.defaultView.document
  const markerEl = doc.createElement('span')
  markerEl.id = `editable-range-boundary-${++boundaryMarkerId}`
  markerEl.setAttribute('data-editable', 'remove')
  markerEl.style.lineHeight = '0'
  markerEl.style.display = 'none'
  markerEl.appendChild(doc.createTextNode(markerTextChar))

  // if another tag is trailing exactly at the start or end, prepend
  // or append the marker element directly on the parent in order to prevent breaking HTML markup.
  if (directlyBeforeFormatTag) {
    range.endContainer.parentElement.insertBefore(markerEl, range.startContainer.parentElement)
  } else if (directlyAfterFormatTag) {
    // emulating insertAfter with nextSibling
    range.startContainer.parentElement.insertBefore(markerEl,
      range.endContainer.parentElement.nextSibling)
  } else {
    // Clone the Range and collapse to the appropriate boundary point
    const boundaryRange = range.cloneRange()
    boundaryRange.collapse(atStart)
    boundaryRange.insertNode(markerEl)
  }

  return markerEl
}

export function setRangeBoundary (host, range, markerId, atStart) {
  const markerEl = getMarker(host, markerId)
  if (!markerEl) return console.log('Marker element has been removed. Cannot restore selection.')
  range[atStart ? 'setStartBefore' : 'setEndBefore'](markerEl)
  markerEl.remove()
}

export function save (range) {
  let rangeInfo, startEl, endEl

  // insert markers
  if (range.collapsed) {
    endEl = insertRangeBoundaryMarker(range, false)
    rangeInfo = {
      markerId: endEl.id,
      collapsed: true
    }
  } else {
    endEl = insertRangeBoundaryMarker(range, false)
    startEl = insertRangeBoundaryMarker(range, true)

    rangeInfo = {
      startMarkerId: startEl.id,
      endMarkerId: endEl.id,
      collapsed: false
    }
  }

  // Adjust each range's boundaries to lie between its markers
  if (range.collapsed) {
    range.collapseBefore(endEl)
  } else {
    range.setEndBefore(endEl)
    range.setStartAfter(startEl)
  }

  return rangeInfo
}

export function restore (host, rangeInfo) {
  if (rangeInfo.restored) return

  const range = rangy.createRange()
  if (rangeInfo.collapsed) {
    const markerEl = getMarker(host, rangeInfo.markerId)
    if (markerEl) {
      markerEl.style.display = 'inline'
      const previousNode = markerEl.previousSibling

      // Workaround for rangy issue 17
      if (previousNode && previousNode.nodeType === nodeType.textNode) {
        markerEl.remove()
        range.collapseToPoint(previousNode, previousNode.length)
      } else {
        range.collapseBefore(markerEl)
        markerEl.remove()
      }
    } else {
      console.log('Marker element has been removed. Cannot restore selection.')
    }
  } else {
    setRangeBoundary(host, range, rangeInfo.startMarkerId, true)
    setRangeBoundary(host, range, rangeInfo.endMarkerId, false)
  }

  range.normalizeBoundaries()
  return range
}

function getMarker (host, id) {
  return host.querySelector(`#${id}`)
}
<commit_msg>fix(save-and-restore): use correct parent<commit_after>import rangy from 'rangy'
import error from './util/error'
import * as nodeType from './node-type'

/**
 * Inspired by the Selection save and restore module for Rangy by Tim Down
 * Saves and restores ranges using invisible marker elements in the DOM.
 */
let boundaryMarkerId = 0

// (U+FEFF) zero width no-break space
const markerTextChar = '\ufeff'

function isChildOf (parent, possibleChild) {
  for (let i = 0; i < parent.children.length; i++) {
    if (parent.children[i] === possibleChild) return true
  }
  return false
}

function startContainerIsChild (range) {
  const parent = range.commonAncestorContainer
  if (parent.nodeType === 3) return false // if we are on the text node it can't be a parent
  const possibleChild = range.startContainer.parentElement
  return isChildOf(parent, possibleChild)
}

function endContainerIsChild (range) {
  const parent = range.commonAncestorContainer
  if (parent.nodeType === 3) return false // if we are on the text node it can't be a parent
  const possibleChild = range.endContainer.parentElement
  return isChildOf(parent, possibleChild)
}

export function insertRangeBoundaryMarker (range, atStart) {
  const container = range.commonAncestorContainer
  const directlyBeforeFormatTag = startContainerIsChild(range) && atStart
  const directlyAfterFormatTag = endContainerIsChild(range) && !atStart

  // If ownerDocument is null the commonAncestorContainer is window.document
  if (container.ownerDocument === null || container.ownerDocument === undefined) {
    error('Cannot save range: range is emtpy')
  }

  // Create the marker element containing a single
  // invisible character using DOM methods and insert it
  const doc = container.ownerDocument.defaultView.document
  const markerEl = doc.createElement('span')
  markerEl.id = `editable-range-boundary-${++boundaryMarkerId}`
  markerEl.setAttribute('data-editable', 'remove')
  markerEl.style.lineHeight = '0'
  markerEl.style.display = 'none'
  markerEl.appendChild(doc.createTextNode(markerTextChar))

  // if another tag is trailing exactly at the start or end, prepend
  // or append the marker element directly on the parent in order to prevent breaking HTML markup.
  if (directlyBeforeFormatTag) {
    range.endContainer.parentElement.insertBefore(markerEl, range.startContainer.parentElement)
  } else if (directlyAfterFormatTag) {
    // emulating insertAfter with nextSibling
    range.startContainer.parentElement.insertBefore(markerEl,
      range.endContainer.parentElement.nextSibling)
  } else {
    // Clone the Range and collapse to the appropriate boundary point
    const boundaryRange = range.cloneRange()
    boundaryRange.collapse(atStart)
    boundaryRange.insertNode(markerEl)
  }

  return markerEl
}

export function setRangeBoundary (host, range, markerId, atStart) {
  const markerEl = getMarker(host, markerId)
  if (!markerEl) return console.log('Marker element has been removed. Cannot restore selection.')
  range[atStart ? 'setStartBefore' : 'setEndBefore'](markerEl)
  markerEl.remove()
}

export function save (range) {
  let rangeInfo, startEl, endEl

  // insert markers
  if (range.collapsed) {
    endEl = insertRangeBoundaryMarker(range, false)
    rangeInfo = {
      markerId: endEl.id,
      collapsed: true
    }
  } else {
    endEl = insertRangeBoundaryMarker(range, false)
    startEl = insertRangeBoundaryMarker(range, true)

    rangeInfo = {
      startMarkerId: startEl.id,
      endMarkerId: endEl.id,
      collapsed: false
    }
  }

  // Adjust each range's boundaries to lie between its markers
  if (range.collapsed) {
    range.collapseBefore(endEl)
  } else {
    range.setEndBefore(endEl)
    range.setStartAfter(startEl)
  }

  return rangeInfo
}

export function restore (host, rangeInfo) {
  if (rangeInfo.restored) return

  const range = rangy.createRange()
  if (rangeInfo.collapsed) {
    const markerEl = getMarker(host, rangeInfo.markerId)
    if (markerEl) {
      markerEl.style.display = 'inline'
      const previousNode = markerEl.previousSibling

      // Workaround for rangy issue 17
      if (previousNode && previousNode.nodeType === nodeType.textNode) {
        markerEl.remove()
        range.collapseToPoint(previousNode, previousNode.length)
      } else {
        range.collapseBefore(markerEl)
        markerEl.remove()
      }
    } else {
      console.log('Marker element has been removed. Cannot restore selection.')
    }
  } else {
    setRangeBoundary(host, range, rangeInfo.startMarkerId, true)
    setRangeBoundary(host, range, rangeInfo.endMarkerId, false)
  }

  range.normalizeBoundaries()
  return range
}

function getMarker (host, id) {
  return host.querySelector(`#${id}`)
}
<|endoftext|>