<commit_before>/*
 * grunt-html-build
 * https://github.com/spatools/grunt-html-build
 * Copyright (c) 2013 SPA Tools
 * Code below is licensed under MIT License
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

module.exports = function (grunt) {
    //#region Global Properties

    var // Init
        _ = grunt.util._,
        EOL = grunt.util.linefeed,
        path = require('path'),
        beautifier = require('js-beautify'),
        beautify = {
            js: beautifier.js,
            css: beautifier.css,
            html: beautifier.html
        },

        // Tags Regular Expressions
        regexTagStart = "<!--\\s*%parseTag%:(\\w+)\\s*(inline)?\\s*(optional)?\\s*([^\\s]*)\\s*-->", // <!-- build:{type} [inline] [optional] {name} --> {} required [] optional
        regexTagEnd = "<!--\\s*\\/%parseTag%\\s*-->";  // <!-- /build -->

    //#endregion

    //#region Private Methods

    function getBuildTags(content) {
        var lines = content.replace(/\r\n/g, '\n').split(/\n/),
            tag = false,
            tags = [],
            last;

        lines.forEach(function (l) {
            var tagStart = l.match(new RegExp(regexTagStart)),
                tagEnd = new RegExp(regexTagEnd).test(l);

            if (tagStart) {
                tag = true;
                last = { type: tagStart[1], inline: !!tagStart[2], optional: !!tagStart[3], name: tagStart[4], lines: [] };
                tags.push(last);
            }

            // switch back tag flag when endbuild
            if (tag && tagEnd) {
                last.lines.push(l);
                tag = false;
            }

            if (tag && last) {
                last.lines.push(l);
            }
        });

        return tags;
    }
    function validateBlockWithName(tag, params) {
        var src = params[tag.type + "s"][tag.name];
        if (src) {
            var opt = {},
                files = src;

            if (_.isObject(src)) {
                opt = src;
                files = src.files;

                delete opt.files;
            }

            return grunt.file.expand(opt, files);
        }
    }
    function validateBlockAlways(tag) {
        return true;
    }

    function setTagRegexes(parseTag) {
        regexTagStart = regexTagStart.replace(/%parseTag%/, function (){return parseTag});
        regexTagEnd = regexTagEnd.replace(/%parseTag%/, function (){return parseTag});
    }

    //#endregion

    //#region Processors Methods

    function createTemplateData(options, extend) {
        return {
            data: extend ?
                    _.extend({}, options.data, extend) :
                    options.data
        };
    }
    function processTemplate(template, options, extend) {
        return grunt.template.process(template, createTemplateData(options, extend));
    }
    function processHtmlTagTemplate(options, extend, inline) {
        var template = templates[options.type + (inline ? "-inline" : "")];
        return processTemplate(template, options, extend);
    }

    function processHtmlTag(options) {
        if (options.inline) {
            var content = options.files.map(grunt.file.read).join(EOL);
            return processHtmlTagTemplate(options, { content: content }, true);
        }
        else {
            return options.files.map(function (f) {
                var url = path.relative(options.dest, f).replace(/\\/g, '/');
                return processHtmlTagTemplate(options, { src: url });
            }).join(EOL);
        }
    }

    //#endregion

    //#region Processors / Validators / Templates

    var
        templates = {
            'script': '<script type="text/javascript" src="<%= src %>"></script>',
            'script-inline': '<script type="text/javascript"><%= content %></script>',
            'style': '<link type="text/css" rel="stylesheet" href="<%= src %>" />',
            'style-inline': '<style><%= content %></style>'
        },
        validators = {
            script: validateBlockWithName,
            style: validateBlockWithName,
            section: validateBlockWithName,

            process: validateBlockAlways,
            remove: validateBlockAlways,

            //base method
            validate: function (tag, params) {
                return validators[tag.type](tag, params);
            }
        },
        processors = {
            script: processHtmlTag,
            style: processHtmlTag,
            section: function (options) {
                return options.files.map(grunt.file.read).join(EOL);
            },

            process: function (options) {
                return options.lines
                                .map(function (l) { return processTemplate(l, options); })
                                .join(EOL)
                                .replace(new RegExp(regexTagStart), "")
                                .replace(new RegExp(regexTagEnd), "");
            },
            remove: function (options) {
                return "";
            },

            //base method
            transform: function (options) {
                return processors[options.type](options);
            }
        };

    //#endregion

    grunt.registerMultiTask('htmlbuild', "Grunt HTML Builder - Replace scripts and styles, Removes debug parts, append html partials, Template options", function () {
        var config = grunt.config(),
            params = this.options({
                beautify: false,
                logOptionals: false,
                scripts: {},
                styles: {},
                sections: {},
                data: {},
                parseTag: 'build'
            });

        setTagRegexes(params.parseTag);

        this.files.forEach(function (file) {
            var dest = file.dest || "",
                destPath, content, tags;

            file.src.forEach(function (src) {
<<<<<<< HEAD
                destPath = path.join(dest, path.basename(src));
                content = grunt.util.normalizelf(grunt.file.read(src).toString());
=======
                if(params.replace) {
                  destPath = path.join(src);
                } else {
                  destPath = path.join(dest, path.basename(src));
                }
                content = grunt.file.read(src).toString();
>>>>>>> 704b9d616e07574459e86288c9b034ee8fb5f3e6
                tags = getBuildTags(content);

                tags.forEach(function (tag) {
                    var raw = tag.lines.join(EOL),
                        result = "",
                        tagFiles = validators.validate(tag, params);

                    if (tagFiles) {
                        var options = _.extend({}, tag, {
                            data: _.extend({}, config, params.data),
                            files: tagFiles,
                            dest: dest
                        });

                        result = processors.transform(options);
                    }
                    else if (tag.optional) {
                        if (params.logOptionals)
                            grunt.log.error().error("Tag with type: '" + tag.type + "' and name: '" + tag.name + "' is not configured in your Gruntfile.js but is set optional, deleting block !");
                    }
                    else {
                        grunt.fail.warn("Tag with type '" + tag.type + "' and name: '" + tag.name + "' is not configured in your Gruntfile.js !");
                    }

                    content = content.replace(raw, function (){return result});
                });

                if (params.beautify) {
                    content = beautify.html(content, _.isObject(params.beautify) ? params.beautify : {});
                }

                // write the contents to destination
                grunt.file.write(destPath, content);
                grunt.log.writeln("File " + destPath + " created !");
            });
        });
    });
};
<commit_msg>Fix conflicts between two repo<commit_after>/*
 * grunt-html-build
 * https://github.com/spatools/grunt-html-build
 * Copyright (c) 2013 SPA Tools
 * Code below is licensed under MIT License
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

module.exports = function (grunt) {
    //#region Global Properties

    var // Init
        _ = grunt.util._,
        EOL = grunt.util.linefeed,
        path = require('path'),
        beautifier = require('js-beautify'),
        beautify = {
            js: beautifier.js,
            css: beautifier.css,
            html: beautifier.html
        },

        // Tags Regular Expressions
        regexTagStart = "<!--\\s*%parseTag%:(\\w+)\\s*(inline)?\\s*(optional)?\\s*([^\\s]*)\\s*-->", // <!-- build:{type} [inline] [optional] {name} --> {} required [] optional
        regexTagEnd = "<!--\\s*\\/%parseTag%\\s*-->";  // <!-- /build -->

    //#endregion

    //#region Private Methods

    function getBuildTags(content) {
        var lines = content.replace(/\r\n/g, '\n').split(/\n/),
            tag = false,
            tags = [],
            last;

        lines.forEach(function (l) {
            var tagStart = l.match(new RegExp(regexTagStart)),
                tagEnd = new RegExp(regexTagEnd).test(l);

            if (tagStart) {
                tag = true;
                last = { type: tagStart[1], inline: !!tagStart[2], optional: !!tagStart[3], name: tagStart[4], lines: [] };
                tags.push(last);
            }

            // switch back tag flag when endbuild
            if (tag && tagEnd) {
                last.lines.push(l);
                tag = false;
            }

            if (tag && last) {
                last.lines.push(l);
            }
        });

        return tags;
    }
    function validateBlockWithName(tag, params) {
        var src = params[tag.type + "s"][tag.name];
        if (src) {
            var opt = {},
                files = src;

            if (_.isObject(src)) {
                opt = src;
                files = src.files;

                delete opt.files;
            }

            return grunt.file.expand(opt, files);
        }
    }
    function validateBlockAlways(tag) {
        return true;
    }

    function setTagRegexes(parseTag) {
        regexTagStart = regexTagStart.replace(/%parseTag%/, function () { return parseTag });
        regexTagEnd = regexTagEnd.replace(/%parseTag%/, function () { return parseTag });
    }

    //#endregion

    //#region Processors Methods

    function createTemplateData(options, extend) {
        return {
            data: extend ?
                    _.extend({}, options.data, extend) :
                    options.data
        };
    }
    function processTemplate(template, options, extend) {
        return grunt.template.process(template, createTemplateData(options, extend));
    }
    function processHtmlTagTemplate(options, extend, inline) {
        var template = templates[options.type + (inline ? "-inline" : "")];
        return processTemplate(template, options, extend);
    }

    function processHtmlTag(options) {
        if (options.inline) {
            var content = options.files.map(grunt.file.read).join(EOL);
            return processHtmlTagTemplate(options, { content: content }, true);
        }
        else {
            return options.files.map(function (f) {
                var url = path.relative(options.dest, f).replace(/\\/g, '/');
                return processHtmlTagTemplate(options, { src: url });
            }).join(EOL);
        }
    }

    //#endregion

    //#region Processors / Validators / Templates

    var
        templates = {
            'script': '<script type="text/javascript" src="<%= src %>"></script>',
            'script-inline': '<script type="text/javascript"><%= content %></script>',
            'style': '<link type="text/css" rel="stylesheet" href="<%= src %>" />',
            'style-inline': '<style><%= content %></style>'
        },
        validators = {
            script: validateBlockWithName,
            style: validateBlockWithName,
            section: validateBlockWithName,

            process: validateBlockAlways,
            remove: validateBlockAlways,

            //base method
            validate: function (tag, params) {
                return validators[tag.type](tag, params);
            }
        },
        processors = {
            script: processHtmlTag,
            style: processHtmlTag,
            section: function (options) {
                return options.files.map(grunt.file.read).join(EOL);
            },

            process: function (options) {
                return options.lines
                                .map(function (l) { return processTemplate(l, options); })
                                .join(EOL)
                                .replace(new RegExp(regexTagStart), "")
                                .replace(new RegExp(regexTagEnd), "");
            },
            remove: function (options) {
                return "";
            },

            //base method
            transform: function (options) {
                return processors[options.type](options);
            }
        };

    //#endregion

    grunt.registerMultiTask('htmlbuild', "Grunt HTML Builder - Replace scripts and styles, Removes debug parts, append html partials, Template options", function () {
        var config = grunt.config(),
            params = this.options({
                beautify: false,
                logOptionals: false,
                scripts: {},
                styles: {},
                sections: {},
                data: {},
                parseTag: 'build'
            });

        setTagRegexes(params.parseTag);

        this.files.forEach(function (file) {
            var dest = file.dest || "",
                destPath, content, tags;

            file.src.forEach(function (src) {
                destPath = params.replace ? src : path.join(dest, path.basename(src));
                content = grunt.util.normalizelf(grunt.file.read(src).toString());
                tags = getBuildTags(content);

                tags.forEach(function (tag) {
                    var raw = tag.lines.join(EOL),
                        result = "",
                        tagFiles = validators.validate(tag, params);

                    if (tagFiles) {
                        var options = _.extend({}, tag, {
                            data: _.extend({}, config, params.data),
                            files: tagFiles,
                            dest: dest
                        });

                        result = processors.transform(options);
                    }
                    else if (tag.optional) {
                        if (params.logOptionals)
                            grunt.log.error().error("Tag with type: '" + tag.type + "' and name: '" + tag.name + "' is not configured in your Gruntfile.js but is set optional, deleting block !");
                    }
                    else {
                        grunt.fail.warn("Tag with type '" + tag.type + "' and name: '" + tag.name + "' is not configured in your Gruntfile.js !");
                    }

                    content = content.replace(raw, function () { return result });
                });

                if (params.beautify) {
                    content = beautify.html(content, _.isObject(params.beautify) ? params.beautify : {});
                }

                // write the contents to destination
                grunt.file.write(destPath, content);
                grunt.log.writeln("File " + destPath + " created !");
            });
        });
    });
};
<|endoftext|>


<commit_before>"use strict";

var React = require('react');

var FluxMixin = require('fluxxor').FluxMixin(React);
var StoreWatchMixin = require('fluxxor').StoreWatchMixin;
var StateMixin = require('react-router').State;

var TrainsGridRow = require('./TrainsGridRow');
var CallingPointsGrid = require('./CallingPointsGrid');

var Alert = require('react-bootstrap').Alert;
var Panel = require('react-bootstrap').Panel;

var TrainsGrid = React.createClass({

  mixins: [
    FluxMixin,
    StoreWatchMixin('SegmentsStore', 'RoutesStore', 'StationsStore', 'TrainsStore', 'CallingPointsStore'),
    StateMixin
  ],

  getInitialState: function() {
    return {
    };
  },

  getStateFromFlux: function() {
    var routesStore = this.getFlux().store('RoutesStore');
    var segmentsStore = this.getFlux().store('SegmentsStore');
    var stationsStore = this.getFlux().store('StationsStore');
    var trainsStore = this.getFlux().store('TrainsStore');
    var callingPointsStore = this.getFlux().store('CallingPointsStore');
    return {
      loading: routesStore.loading,
      error: routesStore.error,
      routes: routesStore.routes,
      segments: segmentsStore.segments,
      stations: stationsStore.stations,
      trains: trainsStore.trains,
      callingPoints: callingPointsStore.callingPoints,
      callingPointTrain: callingPointsStore.train,
      callingPointLoading: callingPointsStore.loading,
      callingPointLoaded: callingPointsStore.loaded
    };
  },

  render: function() {
    var shouldIncludeCallingPointsGrid = false;
    if (this.state.callingPointTrain !== null) {
      shouldIncludeCallingPointsGrid = true;
    }
    var externalScope = this;
    var alertBox = this.state.callingPointLoading ?
<Alert bsStyle="info" style={{ textAlign: "center" }}>Loading Data...</Alert>
 : null;
    var limitationsBox = this.state.trains.length == 0 ?
<Alert bsStyle="warning" style={{ textAlign: "center" }}>We can't show you what you're looking for. To understand more about the limitations of our application click here</Alert>
 : null;

    if (limitationsBox !== null || this.state.error) {
      return (
      <Panel className="TrainsPanel">
        {this.state.error ? <Alert bsStyle="danger">Something has gone wrong! Error: {this.state.error}</Alert> : null}
        {limitationsBox}
      </Panel>
      );
    }
    return (
      <Panel className="TrainsPanel">
        {this.state.loading ? <Alert bsStyle="info">Loading Data...</Alert> : null}

M

T

W

T

F

S

S

            {this.state.trains.map(function(train) {

              if (train.id === externalScope.state.callingPointTrain) {
                if (externalScope.state.callingPointLoading) {
                  return [
                    <TrainsGridRow key={train.id} train={train} isSelected={true} popoverTitle={train.name} origin={externalScope.props.from} destination={externalScope.props.to}/>,
                    alertBox
                  ];
                } else if (externalScope.state.callingPointLoaded) {
                  return [
                    <TrainsGridRow key={train.id} train={train} isSelected={true} popoverTitle={train.name} origin={externalScope.props.from} destination={externalScope.props.to}/>,

                    <CallingPointsGrid key={train.id + "callingPointsGrid"} train={train} callingPoints={externalScope.state.callingPoints} trainID={train.id} />

                  ];
                } else {
                  return <TrainsGridRow key={train.id} train={train} isSelected={false} popoverTitle={train.name} origin={externalScope.props.from} destination={externalScope.props.to}/>;
                }
              } else {
                return <TrainsGridRow key={train.id} train={train} isSelected={false} popoverTitle={train.name} origin={externalScope.props.from} destination={externalScope.props.to} />;
              }
            })}

      </Panel>
    );
  }

});

module.exports = TrainsGrid;
<commit_msg>(Hopefully) fixes issue where limitationsBox was shown when a valid query was loading.<commit_after>"use strict";

var React = require('react');

var FluxMixin = require('fluxxor').FluxMixin(React);
var StoreWatchMixin = require('fluxxor').StoreWatchMixin;
var StateMixin = require('react-router').State;

var TrainsGridRow = require('./TrainsGridRow');
var CallingPointsGrid = require('./CallingPointsGrid');

var Alert = require('react-bootstrap').Alert;
var Panel = require('react-bootstrap').Panel;

var TrainsGrid = React.createClass({

  mixins: [
    FluxMixin,
    StoreWatchMixin('SegmentsStore', 'RoutesStore', 'StationsStore', 'TrainsStore', 'CallingPointsStore'),
    StateMixin
  ],

  getInitialState: function() {
    return {
    };
  },

  getStateFromFlux: function() {
    var routesStore = this.getFlux().store('RoutesStore');
    var segmentsStore = this.getFlux().store('SegmentsStore');
    var stationsStore = this.getFlux().store('StationsStore');
    var trainsStore = this.getFlux().store('TrainsStore');
    var callingPointsStore = this.getFlux().store('CallingPointsStore');
    return {
      loading: routesStore.loading,
      error: routesStore.error,
      routes: routesStore.routes,
      segments: segmentsStore.segments,
      stations: stationsStore.stations,
      trains: trainsStore.trains,
      callingPoints: callingPointsStore.callingPoints,
      callingPointTrain: callingPointsStore.train,
      callingPointLoading: callingPointsStore.loading,
      callingPointLoaded: callingPointsStore.loaded
    };
  },

  render: function() {
    var shouldIncludeCallingPointsGrid = false;
    if (this.state.callingPointTrain !== null) {
      shouldIncludeCallingPointsGrid = true;
    }
    var externalScope = this;
    var alertBox = this.state.callingPointLoading ?
<Alert bsStyle="info" style={{ textAlign: "center" }}>Loading Data...</Alert>
 : null;
    var limitationsBox = this.state.trains.length === 0 && !this.state.loading ?
<Alert bsStyle="warning" style={{ textAlign: "center" }}>We can't show you what you're looking for. To understand more about the limitations of our application click here</Alert>
 : null;

    if (limitationsBox !== null || this.state.error) {
      return (
      <Panel className="TrainsPanel">
        {this.state.error ? <Alert bsStyle="danger">Something has gone wrong! Error: {this.state.error}</Alert> : null}
        {limitationsBox}
      </Panel>
      );
    }
    return (
      <Panel className="TrainsPanel">
        {this.state.loading ? <Alert bsStyle="info">Loading Data...</Alert> : null}

M

T

W

T

F

S

S

            {this.state.trains.map(function(train) {

              if (train.id === externalScope.state.callingPointTrain) {
                if (externalScope.state.callingPointLoading) {
                  return [
                    <TrainsGridRow key={train.id} train={train} isSelected={true} popoverTitle={train.name} origin={externalScope.props.from} destination={externalScope.props.to}/>,
                    alertBox
                  ];
                } else if (externalScope.state.callingPointLoaded) {
                  return [
                    <TrainsGridRow key={train.id} train={train} isSelected={true} popoverTitle={train.name} origin={externalScope.props.from} destination={externalScope.props.to}/>,

                    <CallingPointsGrid key={train.id + "callingPointsGrid"} train={train} callingPoints={externalScope.state.callingPoints} trainID={train.id} />

                  ];
                } else {
                  return <TrainsGridRow key={train.id} train={train} isSelected={false} popoverTitle={train.name} origin={externalScope.props.from} destination={externalScope.props.to}/>;
                }
              } else {
                return <TrainsGridRow key={train.id} train={train} isSelected={false} popoverTitle={train.name} origin={externalScope.props.from} destination={externalScope.props.to} />;
              }
            })}

      </Panel>
    );
  }

});

module.exports = TrainsGrid;
<|endoftext|>


<commit_before>'use strict';

var chalk = require('chalk');
var util = require('util');
var conf = require('./lib/conf.js');
var commands = require('./lib/commands.js');
var workflow = require('./lib/workflow.js');
var ssh = require('./lib/ssh.js');
var sshCredentials = require('./lib/sshCredentials.js');

module.exports = function (grunt) {

    grunt.registerTask('ec2-deploy', 'Deploys to the instance using `rsync`, reloads `pm2` and `nginx`', function (name) {
        conf.init(grunt);

        if (arguments.length === 0) {
            grunt.fatal([
                'You should provide an instance name.',
                'e.g: ' + chalk.yellow('grunt ec2-deploy:name')
            ].join('\n'));
        }

        var done = this.async();
        var target = conf('SRV_CURRENT');
        var versions = conf('SRV_VERSIONS');
        var version = conf('SRV_VERSION');
        var v = grunt.config('pkg.version');
        var dest = util.format(version, v);
        var local = conf('RSYNC_LOCAL');

        var rsync = {
            name: 'v' + v,
            local: local,
            remote: conf('SRV_RSYNC_LATEST'),
            dest: dest,
            includes: conf('RSYNC_INCLUDES').map(env),
            includeFrom: conf('RSYNC_INCLUDE_FROM'),
            excludes: conf('RSYNC_EXCLUDES').map(env),
            excludeFrom: conf('RSYNC_EXCLUDE_FROM')
        };

        function env (pattern) {
            return pattern.replace('%NODE_ENV%', name);
        }

        var verbosity = conf('VERBOSITY_NPM');
        var steps = [{
            rsync: rsync
        }, [
            util.format('sudo rm -rf `ls -t %s | tail -n +11`', versions)
        ], workflow.if_not('NPM_INSTALL_DISABLED', [
            util.format('sudo npm --prefix %s install --production --loglevel %s', dest, verbosity)
        ]), workflow.if_has('NPM_REBUILD', [
            'sudo npm rebuild'
        ]), [
            util.format('sudo ln -sfn %s %s', dest, target),
            commands.pm2_reload(),
            commands.pm2_start(name)
        ], workflow.if_has('NGINX_ENABLED', [
            'sudo nginx -s reload'
        ])];

        workflow(steps, { name: name }, function () {
            sshCredentials(name, function (c) {
                log(c);
            });
        });

        var scheme = conf('SSL_ENABLED') ? 'https' : 'http';

        function log (c) {
            var url = util.format('%s://%s/', scheme, c.ip);
            var text = chalk.magenta(url);

            grunt.task.run('ec2-pagespeed:' + c.ip);

            grunt.log.writeln('You can access the instance via %s on %s', scheme.toUpperCase(), text);
            grunt.log.write('Will tail nginx error logs and flush pm2 logs in 5s.');

            setTimeout(peek, 5000);
        }

        function peek () {
            grunt.log.writeln('Flushing...');

            var commands = [
                'pm2 flush',
                'pm2 list'
            ];

            if (conf('NGINX_ENABLED')) {
                commands.unshift('tail -3 /var/log/nginx/error.log');
            }

            ssh(commands, { name: name }, done);
        }
    });
};
<commit_msg>Call `pm2_save` on deploys for resurrect purposes.<commit_after>'use strict';

var chalk = require('chalk');
var util = require('util');
var conf = require('./lib/conf.js');
var commands = require('./lib/commands.js');
var workflow = require('./lib/workflow.js');
var ssh = require('./lib/ssh.js');
var sshCredentials = require('./lib/sshCredentials.js');

module.exports = function (grunt) {

    grunt.registerTask('ec2-deploy', 'Deploys to the instance using `rsync`, reloads `pm2` and `nginx`', function (name) {
        conf.init(grunt);

        if (arguments.length === 0) {
            grunt.fatal([
                'You should provide an instance name.',
                'e.g: ' + chalk.yellow('grunt ec2-deploy:name')
            ].join('\n'));
        }

        var done = this.async();
        var target = conf('SRV_CURRENT');
        var versions = conf('SRV_VERSIONS');
        var version = conf('SRV_VERSION');
        var v = grunt.config('pkg.version');
        var dest = util.format(version, v);
        var local = conf('RSYNC_LOCAL');

        var rsync = {
            name: 'v' + v,
            local: local,
            remote: conf('SRV_RSYNC_LATEST'),
            dest: dest,
            includes: conf('RSYNC_INCLUDES').map(env),
            includeFrom: conf('RSYNC_INCLUDE_FROM'),
            excludes: conf('RSYNC_EXCLUDES').map(env),
            excludeFrom: conf('RSYNC_EXCLUDE_FROM')
        };

        function env (pattern) {
            return pattern.replace('%NODE_ENV%', name);
        }

        var verbosity = conf('VERBOSITY_NPM');
        var steps = [{
            rsync: rsync
        }, [
            util.format('sudo rm -rf `ls -t %s | tail -n +11`', versions)
        ], workflow.if_not('NPM_INSTALL_DISABLED', [
            util.format('sudo npm --prefix %s install --production --loglevel %s', dest, verbosity)
        ]), workflow.if_has('NPM_REBUILD', [
            'sudo npm rebuild'
        ]), [
            util.format('sudo ln -sfn %s %s', dest, target),
            commands.pm2_reload(),
            commands.pm2_start(name),
            commands.pm2_save()
        ], workflow.if_has('NGINX_ENABLED', [
            'sudo nginx -s reload'
        ])];

        workflow(steps, { name: name }, function () {
            sshCredentials(name, function (c) {
                log(c);
            });
        });

        var scheme = conf('SSL_ENABLED') ? 'https' : 'http';

        function log (c) {
            var url = util.format('%s://%s/', scheme, c.ip);
            var text = chalk.magenta(url);

            grunt.task.run('ec2-pagespeed:' + c.ip);

            grunt.log.writeln('You can access the instance via %s on %s', scheme.toUpperCase(), text);
            grunt.log.write('Will tail nginx error logs and flush pm2 logs in 5s.');

            setTimeout(peek, 5000);
        }

        function peek () {
            grunt.log.writeln('Flushing...');

            var commands = [
                'pm2 flush',
                'pm2 list'
            ];

            if (conf('NGINX_ENABLED')) {
                commands.unshift('tail -3 /var/log/nginx/error.log');
            }

            ssh(commands, { name: name }, done);
        }
    });
};
<|endoftext|>


<commit_before>define(function(require) {
    'use strict';

    var angular = require('angular'),
        str = require('js/app-config').string,
        appController = require('js/app-controller'),
        notification = require('js/util/notification'),
        _ = require('underscore'),
        emailDao, outboxBo;

    //
    // Controller
    //

    var NavigationCtrl = function($scope) {
        emailDao = appController._emailDao;
        outboxBo = appController._outboxBo;

        //
        // scope functions
        //

        $scope.state.nav = {
            open: false,
            toggle: function(to) {
                this.open = to;
            }
        };

        $scope.openFolder = function(folder) {
            $scope.state.nav.currentFolder = folder;
            $scope.state.nav.toggle(false);
        };

        $scope.onOutboxUpdate = function(err, count) {
            if (err) {
                $scope.onError(err);
                return;
            }

            // update the outbox mail count. this should normally happen during the delta sync
            // problem is that the outbox continuously retries in the background, whereas the delta sync only runs
            // when the outbox is currently viewed...
            var outbox = _.findWhere($scope.account.folders, {
                type: 'Outbox'
            });

            if (outbox === $scope.state.nav.currentFolder) {
                $scope.state.mailList.synchronize();
            } else {
                outbox.count = count;
                $scope.$apply();
            }
        };

        //
        // Start
        //

        // init folders
        initFolders();
        // select inbox as the current folder on init
        if ($scope.account.folders && $scope.account.folders.length > 0) {
            $scope.openFolder($scope.account.folders[0]);
        }
        // connect imap/smtp clients on first startup
        appController.onConnect(function(err) {
            if (err) {
                $scope.onError(err);
                return;
            }

            // select inbox if not yet selected
            if (!$scope.state.nav.currentFolder) {
                $scope.openFolder($scope.account.folders[0]);
            }
        });

        //
        // helper functions
        //

        function initFolders() {
            if (window.chrome && chrome.identity) {
                // get pointer to account/folder/message tree on root scope
                $scope.$root.account = emailDao._account;

                // set notificatio handler for sent messages
                outboxBo.onSent = sentNotification;
                // start checking outbox periodically
                outboxBo.startChecking($scope.onOutboxUpdate);
                // make function available globally for write controller
                $scope.emptyOutbox = outboxBo._processOutbox.bind(outboxBo);
                return;
            }

            // attach dummy folders for development
            $scope.$root.account = {};
            $scope.account.folders = [{
                type: 'Inbox',
                count: 2,
                path: 'INBOX'
            }, {
                type: 'Sent',
                count: 0,
                path: 'SENT'
            }, {
                type: 'Outbox',
                count: 0,
                path: 'OUTBOX'
            }, {
                type: 'Drafts',
                count: 0,
                path: 'DRAFTS'
            }, {
                type: 'Trash',
                count: 0,
                path: 'TRASH'
            }];
        }

        function sentNotification(email) {
            notification.create({
                id: 'o' + email.id,
                title: 'Message sent',
                message: email.subject.replace(str.subjectPrefix, '')
            }, function() {});
        }
    };

    //
    // Directives
    //

    var ngModule = angular.module('navigation', []);
    ngModule.directive('keyShortcuts', function($timeout) {
        return function(scope, elm) {
            elm.bind('keydown', function(e) {
                // global state is not yet set, ignore keybaord shortcuts
                if (!scope.state) {
                    return;
                }

                var modifier = e.ctrlKey || e.metaKey;

                if (modifier && e.keyCode === 78 && scope.state.writer && !scope.state.writer.open) {
                    // n -> new mail
                    e.preventDefault();
                    scope.state.writer.write();
                    scope.$apply();

                } else if (modifier && e.keyCode === 70 && !scope.state.writer.open) {
                    // f -> find
                    e.preventDefault();
                    scope.state.mailList.searching = true;
                    $timeout(function() {
                        scope.state.mailList.searching = false;
                    }, 200);
                    scope.$apply();

                } else if (modifier && e.keyCode === 82 && scope.state.writer && !scope.state.writer.open && scope.state.mailList.selected) {
                    // r -> reply
                    e.preventDefault();
                    scope.state.writer.write(scope.state.mailList.selected);
                    scope.$apply();

                } else if (modifier && e.keyCode === 83 && scope.state.writer && !scope.state.writer.open && scope.state.mailList.synchronize) {
                    // s -> sync folder
                    e.preventDefault();
                    scope.state.mailList.synchronize();
                    scope.$apply();

                } else if (e.keyCode === 27 && scope.state.writer.open) {
                    // escape -> close writer
                    e.preventDefault();
                    scope.state.writer.close();
                    scope.$apply();

                } else if (e.keyCode === 27 && scope.state.account.open) {
                    // escape -> close account view
                    e.preventDefault();
                    scope.state.account.toggle(false);
                    scope.$apply();

                } else if (e.keyCode === 27 && scope.state.contacts.open) {
                    // escape -> close contacts view
                    e.preventDefault();
                    scope.state.contacts.toggle(false);
                    scope.$apply();

                } else if (e.keyCode === 27 && scope.state.nav.open) {
                    // escape -> close nav view
                    e.preventDefault();
                    scope.state.nav.toggle(false);
                    scope.$apply();
                }

            });
        };
    });

    return NavigationCtrl;
});<commit_msg>Global key shortcut to close lightbox<commit_after>define(function(require) {
    'use strict';

    var angular = require('angular'),
        str = require('js/app-config').string,
        appController = require('js/app-controller'),
        notification = require('js/util/notification'),
        _ = require('underscore'),
        emailDao, outboxBo;

    //
    // Controller
    //

    var NavigationCtrl = function($scope) {
        emailDao = appController._emailDao;
        outboxBo = appController._outboxBo;

        //
        // scope functions
        //

        $scope.state.nav = {
            open: false,
            toggle: function(to) {
                this.open = to;
            }
        };

        $scope.openFolder = function(folder) {
            $scope.state.nav.currentFolder = folder;
            $scope.state.nav.toggle(false);
        };

        $scope.onOutboxUpdate = function(err, count) {
            if (err) {
                $scope.onError(err);
                return;
            }

            // update the outbox mail count. this should normally happen during the delta sync
            // problem is that the outbox continuously retries in the background, whereas the delta sync only runs
            // when the outbox is currently viewed...
            var outbox = _.findWhere($scope.account.folders, {
                type: 'Outbox'
            });

            if (outbox === $scope.state.nav.currentFolder) {
                $scope.state.mailList.synchronize();
            } else {
                outbox.count = count;
                $scope.$apply();
            }
        };

        //
        // Start
        //

        // init folders
        initFolders();
        // select inbox as the current folder on init
        if ($scope.account.folders && $scope.account.folders.length > 0) {
            $scope.openFolder($scope.account.folders[0]);
        }
        // connect imap/smtp clients on first startup
        appController.onConnect(function(err) {
            if (err) {
                $scope.onError(err);
                return;
            }

            // select inbox if not yet selected
            if (!$scope.state.nav.currentFolder) {
                $scope.openFolder($scope.account.folders[0]);
            }
        });

        //
        // helper functions
        //

        function initFolders() {
            if (window.chrome && chrome.identity) {
                // get pointer to account/folder/message tree on root scope
                $scope.$root.account = emailDao._account;

                // set notificatio handler for sent messages
                outboxBo.onSent = sentNotification;
                // start checking outbox periodically
                outboxBo.startChecking($scope.onOutboxUpdate);
                // make function available globally for write controller
                $scope.emptyOutbox = outboxBo._processOutbox.bind(outboxBo);
                return;
            }

            // attach dummy folders for development
            $scope.$root.account = {};
            $scope.account.folders = [{
                type: 'Inbox',
                count: 2,
                path: 'INBOX'
            }, {
                type: 'Sent',
                count: 0,
                path: 'SENT'
            }, {
                type: 'Outbox',
                count: 0,
                path: 'OUTBOX'
            }, {
                type: 'Drafts',
                count: 0,
                path: 'DRAFTS'
            }, {
                type: 'Trash',
                count: 0,
                path: 'TRASH'
            }];
        }

        function sentNotification(email) {
            notification.create({
                id: 'o' + email.id,
                title: 'Message sent',
                message: email.subject.replace(str.subjectPrefix, '')
            }, function() {});
        }
    };

    //
    // Directives
    //

    var ngModule = angular.module('navigation', []);
    ngModule.directive('keyShortcuts', function($timeout) {
        return function(scope, elm) {
            elm.bind('keydown', function(e) {
                // global state is not yet set, ignore keybaord shortcuts
                if (!scope.state) {
                    return;
                }

                var modifier = e.ctrlKey || e.metaKey;

                if (modifier && e.keyCode === 78 && scope.state.lightbox !== 'write') {
                    // n -> new mail
                    e.preventDefault();
                    scope.state.writer.write();
                    scope.$apply();

                } else if (modifier && e.keyCode === 70 && scope.state.lightbox !== 'write') {
                    // f -> find
                    e.preventDefault();
                    scope.state.mailList.searching = true;
                    $timeout(function() {
                        scope.state.mailList.searching = false;
                    }, 200);
                    scope.$apply();

                } else if (modifier && e.keyCode === 82 && scope.state.lightbox !== 'write' && scope.state.mailList.selected) {
                    // r -> reply
                    e.preventDefault();
                    scope.state.writer.write(scope.state.mailList.selected);
                    scope.$apply();

                } else if (modifier && e.keyCode === 83 && scope.state.lightbox !== 'write' && scope.state.mailList.synchronize) {
                    // s -> sync folder
                    e.preventDefault();
                    scope.state.mailList.synchronize();
                    scope.$apply();

                } else if (e.keyCode === 27 && scope.state.lightbox !== undefined) {
                    // escape -> close current lightbox
                    e.preventDefault();
                    scope.state.lightbox = undefined;
                    scope.$apply();

                } else if (e.keyCode === 27 && scope.state.nav.open) {
                    // escape -> close nav view
                    e.preventDefault();
                    scope.state.nav.toggle(false);
                    scope.$apply();
                }

            });
        };
    });

    return NavigationCtrl;
});<|endoftext|>


<commit_before>module.exports = {
    all : ['_site/test.html'],
    options : {
        reporter: 'Spec',
        threshold : 75, // <- each file has to have this much coverage
        globalThreshold : 80, // <- average coverage
        // the below is temporary, there is an issue on GitHub to get them up to 75
        customThreshold: {
            './src/js/toolkit/components/tooltip.js': 41,
            './src/js/toolkit/utils/polyfill.js': 67,
            './src/js/toolkit/utils/responsive-images.js': 40,
            './src/js/toolkit/utils/skycons.js': 54,
            './src/js/toolkit/utils/validation.js': 44
        },
        log : true,
        logErrors: true // outputs Phantom JS errors
    }
};
<commit_msg>fixed custom coverage thresholds<commit_after>module.exports = {
    all : ['_site/test.html'],
    options : {
        reporter: 'Spec',
        threshold : 75, // <- each file has to have this much coverage
        globalThreshold : 80, // <- average coverage
        // the below is temporary, there is an issue on GitHub to get them up to 75
        customThreshold: {
            'src/js/toolkit/components/tooltip.js': 41,
            'src/js/toolkit/utils/polyfill.js': 67,
            'src/js/toolkit/utils/responsive-images.js': 40,
            'src/js/toolkit/utils/skycons.js': 54,
            'src/js/toolkit/utils/validation.js': 44
        },
        log : true,
        logErrors: true // outputs Phantom JS errors
    }
};
<|endoftext|>


<commit_before>/*
 * grunt-contrib-handlebars
 * http://gruntjs.com/
 *
 * Copyright (c) 2016 Tim Branyen, contributors
 * Licensed under the MIT license.
 */

'use strict';
var chalk = require('chalk');
var nsdeclare = require('nsdeclare');

module.exports = function(grunt) {
  var _ = grunt.util._;

  // content conversion for templates
  var defaultProcessContent = function(content) { return content; };

  // AST processing for templates
  var defaultProcessAST = function(ast) { return ast; };

  // filename conversion for templates
  var defaultProcessName = function(name) { return name; };

  // filename conversion for partials
  var defaultProcessPartialName = function(filepath) {
    var pieces = _.last(filepath.split('/')).split('.');
    var name   = _(pieces).without(_.last(pieces)).join('.'); // strips file extension
    if (name.charAt(0) === '_') {
      name = name.substr(1, name.length); // strips leading _ character
    }
    return name;
  };

  var extractGlobalNamespace = function(nsDeclarations) {
    // Extract global namespace from any existing namespace declaration.
    // The purpose of this method is too fix an issue with AMD when using namespace as a function where the
    // nsInfo.namespace will contains the last namespace, not the global namespace.

    var declarations = _.keys(nsDeclarations);

    // no declaration found
    if (!declarations.length) {
      return '';
    }

    // In case only one namespace has been declared it will only return it.
    if (declarations.length === 1) {
      return declarations[0];
    }
    // We only need to take any declaration to extract the global namespace.
    // Another option might be find the shortest declaration which is the global one.
    var matches = declarations[0].match(/(this\[[^\[]+\])/g);
    return matches[0];
  };

  grunt.registerMultiTask('handlebars', 'Compile handlebars templates and partials.', function() {
    var options = this.options({
      namespace: 'JST',
      separator: grunt.util.linefeed + grunt.util.linefeed,
      wrapped: true,
      amd: false,
      commonjs: false,
      knownHelpers: [],
      knownHelpersOnly: false
    });

    // assign regex for partials directory detection
    var partialsPathRegex = options.partialsPathRegex || /./;

    // assign regex for partial detection
    var isPartialRegex = options.partialRegex || /^_/;

    // assign transformation functions
    var processContent = options.processContent || defaultProcessContent;
    var processName = options.processName || defaultProcessName;
    var processPartialName = options.processPartialName || defaultProcessPartialName;
    var processAST = options.processAST || defaultProcessAST;
    var useNamespace = options.namespace !== false;

    // assign compiler options
    var compilerOptions = options.compilerOptions || {};
    var filesCount = 0;

    this.files.forEach(function(f) {
      var declarations = [];
      var partials = {};
      var templates = {};
      // template identifying parts
      var ast, compiled, filename;

      // Namespace info for current template
      var nsInfo;

      // Map of already declared namespace parts
      var nsDeclarations = {};

      // nsdeclare options when fetching namespace info
      var nsDeclareOptions = {response: 'details', declared: nsDeclarations};

      // Just get the namespace info for a given template
      var getNamespaceInfo = _.memoize(function(filepath) {
        if (!useNamespace) {
          return undefined;
        }
        if (_.isFunction(options.namespace)) {
          return nsdeclare(options.namespace(filepath), nsDeclareOptions);
        }
        return nsdeclare(options.namespace, nsDeclareOptions);
      });

      // iterate files, processing partials and templates separately
      f.src.filter(function(filepath) {
        // Warn on and remove invalid source files (if nonull was set).
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        }
        return true;
      })
      .forEach(function(filepath) {
        var src = processContent(grunt.file.read(filepath), filepath);

        var Handlebars = require('handlebars');
        try {
          // parse the handlebars template into it's AST
          ast = processAST(Handlebars.parse(src));
          compiled = Handlebars.precompile(ast, compilerOptions);

          // if configured to, wrap template in Handlebars.template call
          if (options.wrapped === true) {
            compiled = 'Handlebars.template(' + compiled + ')';
          }
        } catch (e) {
          grunt.log.error(e);
          grunt.fail.warn('Handlebars failed to compile ' + filepath + '.');
        }

        // register partial or add template to namespace
        if (partialsPathRegex.test(filepath) && isPartialRegex.test(_.last(filepath.split('/')))) {
          filename = processPartialName(filepath);
          if (options.partialsUseNamespace === true) {
            nsInfo = getNamespaceInfo(filepath);
            if (nsInfo.declaration) {
              declarations.push(nsInfo.declaration);
            }
            partials[JSON.stringify(filename) + ', ' + nsInfo.namespace] = ('Handlebars.registerPartial(' +
              JSON.stringify(filename) + ', ' + nsInfo.namespace + '[' + JSON.stringify(filename) + '] = ' +
              compiled + ');');
          } else {
            partials[JSON.stringify(filename)] = ('Handlebars.registerPartial(' + JSON.stringify(filename) +
              ', ' + compiled + ');');
          }
        } else {
          if ((options.amd || options.commonjs) && !useNamespace) {
            compiled = 'return ' + compiled;
          }
          filename = processName(filepath);
          if (useNamespace) {
            nsInfo = getNamespaceInfo(filepath);
            if (nsInfo.declaration) {
              declarations.push(nsInfo.declaration);
            }
            templates[JSON.stringify(filename) + ', ' + nsInfo.namespace] = (nsInfo.namespace + '[' +
              JSON.stringify(filename) + '] = ' + compiled + ';');
          } else if (options.commonjs === true) {
            templates[JSON.stringify(filename)] = compiled + ';';
          } else {
            templates[JSON.stringify(filename)] = compiled;
          }
        }
      });

      var output = declarations.concat(_.values(partials), _.values(templates));
      if (output.length < 1) {
        grunt.log.warn('Destination not written because compiled files were empty.');
      } else {
        if (useNamespace) {
          if (options.node) {
            output.unshift('Handlebars = glob.Handlebars || require(\'handlebars\');');
            output.unshift('var glob = (\'undefined\' === typeof window) ? global : window,');

            var nodeExport = 'if (typeof exports === \'object\' && exports) {';
            nodeExport += 'module.exports = ' + nsInfo.namespace + ';}';

            output.push(nodeExport);
          }

        }

        if (options.amd) {
          // Wrap the file in an AMD define fn.
          if (typeof options.amd === 'boolean') {
            output.unshift('define([\'handlebars\'], function(Handlebars) {');
          } else if (typeof options.amd === 'string') {
            output.unshift('define([\'' + options.amd + '\'], function(Handlebars) {');
          } else if (typeof options.amd === 'function') {
            output.unshift('define([\'' + options.amd(filename, ast, compiled) + '\'], function(Handlebars) {');
          } else if (Array.isArray(options.amd)) {
            // convert options.amd to a string of dependencies for require([...])
            var amdString = '';
            for (var i = 0; i < options.amd.length; i++) {
              if (i !== 0) {
                amdString += ', ';
              }

              amdString += '\'' + options.amd[i] + '\'';
            }

            // Wrap the file in an AMD define fn.
            output.unshift('define([' + amdString + '], function(Handlebars) {');
          }

          if (useNamespace) {
            // Namespace has not been explicitly set to false; the AMD
            // wrapper will return the object containing the template.
            output.push('return ' + extractGlobalNamespace(nsDeclarations) + ';');
          }
          output.push('});');
        }

        if (options.commonjs) {
          if (useNamespace) {
            output.push('return ' + nsInfo.namespace + ';');
          }
          // Export the templates object for CommonJS environments.
          output.unshift('module.exports = function(Handlebars) {');
          output.push('};');
        }

        filesCount++;
        grunt.file.write(f.dest, output.join(grunt.util.normalizelf(options.separator)));
        grunt.verbose.writeln('File ' + chalk.cyan(f.dest) + ' created.');
      }
    });

    grunt.log.ok(filesCount + ' ' + grunt.util.pluralize(filesCount, 'file/files') + ' created.');
  });
};
<commit_msg>Update handlebars.js<commit_after>/*
 * grunt-contrib-handlebars
 * http://gruntjs.com/
 *
 * Copyright (c) 2016 Tim Branyen, contributors
 * Licensed under the MIT license.
 */

'use strict';
var chalk = require('chalk');
var nsdeclare = require('nsdeclare');

module.exports = function(grunt) {
  var _ = grunt.util._;

  // content conversion for templates
  var defaultProcessContent = function(content) { return content; };

  // AST processing for templates
  var defaultProcessAST = function(ast) { return ast; };

  // filename conversion for templates
  var defaultProcessName = function(name) { return name; };

  // filename conversion for partials
  var defaultProcessPartialName = function(filepath) {
    var pieces = _.last(filepath.split('/')).split('.');
    var name   = _(pieces).without(_.last(pieces)).join('.'); // strips file extension
    if (name.charAt(0) === '_') {
      name = name.substr(1, name.length); // strips leading _ character
    }
    return name;
  };

  var extractGlobalNamespace = function(nsDeclarations) {
    // Extract global namespace from any existing namespace declaration.
    // The purpose of this method is too fix an issue with AMD when using namespace as a function where the
    // nsInfo.namespace will contains the last namespace, not the global namespace.

    var declarations = _.keys(nsDeclarations);

    // no declaration found
    if (!declarations.length) {
      return '';
    }

    // In case only one namespace has been declared it will only return it.
    if (declarations.length === 1) {
      return declarations[0];
    }
    // We only need to take any declaration to extract the global namespace.
    // Another option might be find the shortest declaration which is the global one.
    var matches = declarations[0].match(/(this\[[^\[]+\])/g);
    return matches[0];
  };

  grunt.registerMultiTask('handlebars', 'Compile handlebars templates and partials.', function() {
    var options = this.options({
      namespace: 'JST',
      separator: grunt.util.linefeed + grunt.util.linefeed,
      wrapped: true,
      amd: false,
      commonjs: false,
      knownHelpers: [],
      knownHelpersOnly: false
    });

    // assign regex for partials directory detection
    var partialsPathRegex = options.partialsPathRegex || /./;

    // assign regex for partial detection
    var isPartialRegex = options.partialRegex || /^_/;

    // assign transformation functions
    var processContent = options.processContent || defaultProcessContent;
    var processName = options.processName || defaultProcessName;
    var processPartialName = options.processPartialName || defaultProcessPartialName;
    var processAST = options.processAST || defaultProcessAST;
    var useNamespace = options.namespace !== false;

    // assign compiler options
    var compilerOptions = options.compilerOptions || {};
    var filesCount = 0;

    this.files.forEach(function(f) {
      var declarations = [];
      var partials = {};
      var templates = {};
      // template identifying parts
      var ast, compiled, filename;

      // Namespace info for current template
      var nsInfo;

      // Map of already declared namespace parts
      var nsDeclarations = {};

      // nsdeclare options when fetching namespace info
      var nsDeclareOptions = {response: 'details', declared: nsDeclarations};

      // Just get the namespace info for a given template
      var getNamespaceInfo = _.memoize(function(filepath) {
        if (!useNamespace) {
          return undefined;
        }
        if (_.isFunction(options.namespace)) {
          return nsdeclare(options.namespace(filepath), nsDeclareOptions);
        }
        return nsdeclare(options.namespace, nsDeclareOptions);
      });

      // iterate files, processing partials and templates separately
      f.src.filter(function(filepath) {
        // Warn on and remove invalid source files (if nonull was set).
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        }
        return true;
      })
      .forEach(function(filepath) {
        var src = processContent(grunt.file.read(filepath), filepath);

        var Handlebars = require('handlebars');
        try {
          // parse the handlebars template into it's AST
          ast = processAST(Handlebars.parse(src));
          compiled = Handlebars.precompile(ast, compilerOptions);

          // if configured to, wrap template in Handlebars.template call
          if (options.wrapped === true) {
            compiled = 'Handlebars.template(' + compiled + ')';
          }
        } catch (e) {
          grunt.log.error(e);
          grunt.fail.warn('Handlebars failed to compile ' + filepath + '.');
        }

        // register partial or add template to namespace
        if (partialsPathRegex.test(filepath) && isPartialRegex.test(_.last(filepath.split('/')))) {
          filename = processPartialName(filepath);
          if (options.partialsUseNamespace === true) {
            nsInfo = getNamespaceInfo(filepath);
            if (nsInfo.declaration) {
              declarations.push(nsInfo.declaration);
            }
            partials[nsInfo.namespace + ':' + JSON.stringify(filename)] = ('Handlebars.registerPartial(' +
              JSON.stringify(filename) + ', ' + nsInfo.namespace + '[' + JSON.stringify(filename) + '] = ' +
              compiled + ');');
          } else {
            partials[JSON.stringify(filename)] = ('Handlebars.registerPartial(' + JSON.stringify(filename) +
              ', ' + compiled + ');');
          }
        } else {
          if ((options.amd || options.commonjs) && !useNamespace) {
            compiled = 'return ' + compiled;
          }
          filename = processName(filepath);
          if (useNamespace) {
            nsInfo = getNamespaceInfo(filepath);
            if (nsInfo.declaration) {
              declarations.push(nsInfo.declaration);
            }
            templates[nsInfo.namespace + ':' + JSON.stringify(filename)] = (nsInfo.namespace + '[' +
              JSON.stringify(filename) + '] = ' + compiled + ';');
          } else if (options.commonjs === true) {
            templates[JSON.stringify(filename)] = compiled + ';';
          } else {
            templates[JSON.stringify(filename)] = compiled;
          }
        }
      });

      var output = declarations.concat(_.values(partials), _.values(templates));
      if (output.length < 1) {
        grunt.log.warn('Destination not written because compiled files were empty.');
      } else {
        if (useNamespace) {
          if (options.node) {
            output.unshift('Handlebars = glob.Handlebars || require(\'handlebars\');');
            output.unshift('var glob = (\'undefined\' === typeof window) ? global : window,');

            var nodeExport = 'if (typeof exports === \'object\' && exports) {';
            nodeExport += 'module.exports = ' + nsInfo.namespace + ';}';

            output.push(nodeExport);
          }

        }

        if (options.amd) {
          // Wrap the file in an AMD define fn.
          if (typeof options.amd === 'boolean') {
            output.unshift('define([\'handlebars\'], function(Handlebars) {');
          } else if (typeof options.amd === 'string') {
            output.unshift('define([\'' + options.amd + '\'], function(Handlebars) {');
          } else if (typeof options.amd === 'function') {
            output.unshift('define([\'' + options.amd(filename, ast, compiled) + '\'], function(Handlebars) {');
          } else if (Array.isArray(options.amd)) {
            // convert options.amd to a string of dependencies for require([...])
            var amdString = '';
            for (var i = 0; i < options.amd.length; i++) {
              if (i !== 0) {
                amdString += ', ';
              }

              amdString += '\'' + options.amd[i] + '\'';
            }

            // Wrap the file in an AMD define fn.
            output.unshift('define([' + amdString + '], function(Handlebars) {');
          }

          if (useNamespace) {
            // Namespace has not been explicitly set to false; the AMD
            // wrapper will return the object containing the template.
            output.push('return ' + extractGlobalNamespace(nsDeclarations) + ';');
          }
          output.push('});');
        }

        if (options.commonjs) {
          if (useNamespace) {
            output.push('return ' + nsInfo.namespace + ';');
          }
          // Export the templates object for CommonJS environments.
          output.unshift('module.exports = function(Handlebars) {');
          output.push('};');
        }

        filesCount++;
        grunt.file.write(f.dest, output.join(grunt.util.normalizelf(options.separator)));
        grunt.verbose.writeln('File ' + chalk.cyan(f.dest) + ' created.');
      }
    });

    grunt.log.ok(filesCount + ' ' + grunt.util.pluralize(filesCount, 'file/files') + ' created.');
  });
};
<|endoftext|>


<commit_before>/**
 * @module utils
 * @description
 * Contains small utilities for djv project
 */
function cleanId(id) {
  return (id || '').replace(/#/g, '');
}

function asExpression(fn, schema, tpl) {
  if (typeof fn !== 'function') {
    return fn;
  }

  return fn(schema, tpl);
}

function head(uri) {
  if (typeof uri !== 'string') {
    return uri;
  }

  const parts = uri.split(/#\/?/);
  return parts[0];
}

function isFullUri(uri) {
  return /:\/\//.test(uri);
}

/**
 * @name path
 * @type {function}
 * @description
 * Gets a scheme, domain and a path part from the uri
 * F.e. from http://domain.domain:2020/test/a?test
 * Should pick http://domain.domain:2020/test/
 * @param {string} uri
 * @returns {string} path
 */
function path(uri) {
  return uri.replace(/(^[^:]+:\/\/.*\/).*/, '$1');
}

/**
 * @description
 * Get the fragment (#...) part of the uri
 * @see https://tools.ietf.org/html/rfc3986#section-3
 * @param {string} uri
 * @returns {string} fragment
 */
function fragment(uri) {
  if (typeof uri !== 'string') {
    return uri;
  }

  const parts = uri.split(/#\/?/);
  return parts[1];
}

/**
 * @name makePath
 * @type function
 * @description
 * Concat parts into single uri
 * @see https://tools.ietf.org/html/rfc3986#section-3
 * @param {array[string]} parts
 * @returns {string} uri
 */
function makePath(parts) {
  return parts
    .filter(part => typeof part === 'string')
    .reduce((uri, id) => {
      if (!uri.length) {
        return id;
      }

      // if id is full replace uri
      if (isFullUri(id)) {
        return id;
      }

      // if sharp delimiter found
      if (id.indexOf('#') === 0) {
        // should replace uri's sharp with id
        const sharpUriIndex = uri.indexOf('#');
        return uri.slice(0, sharpUriIndex) + id;
      }

      // get path part of uri
      // and replace the rest with id
      const partialUri = path(uri) + id;
      return partialUri + (partialUri.indexOf('#') === -1 ? '#' : '');
    }, '');
}

function hasProperty(object, property) {
  return Object.prototype.hasOwnProperty.call(object, property);
}

function normalize(uri) {
  return uri.replace(/~1/g, '/').replace(/~0/g, '~');
}

function descent(reference, parentSchema) {
  const name = fragment(reference);
  const components = name && name.split('/');

  let currentSchema = parentSchema;
  // TODO change while to forEach
  while (components && components.length > 0) {
    const currentPath = decodeURIComponent(normalize(components[0]));
    currentSchema = currentSchema[currentPath] ||
      (currentSchema.definitions && currentSchema.definitions[currentPath]);

    if (!currentSchema) {
      throw new Error(`Schema ${name} not found`);
    }
    components.shift();
  }

  return currentSchema;
}

module.exports = {
  cleanId,
  asExpression,
  hasProperty,
  // TODO move to utils/uri
  makePath,
  isFullUri,
  head,
  fragment,
  descent,
};
<commit_msg>refactor(state): Clean descent utils method<commit_after>/**
 * @module utils
 * @description
 * Contains small utilities for djv project
 */

const REGEXP_URI = /:\/\//;
const REGEXP_URI_FRAGMENT = /#\/?/;
const REGEXP_URI_PATH = /(^[^:]+:\/\/.*\/).*/;

function cleanId(id) {
  return (id || '').replace(/#/g, '');
}

function asExpression(fn, schema, tpl) {
  if (typeof fn !== 'function') {
    return fn;
  }

  return fn(schema, tpl);
}

function head(uri) {
  if (typeof uri !== 'string') {
    return uri;
  }

  const parts = uri.split(REGEXP_URI_FRAGMENT);
  return parts[0];
}

function isFullUri(uri) {
  return REGEXP_URI.test(uri);
}

/**
 * @name path
 * @type {function}
 * @description
 * Gets a scheme, domain and a path part from the uri
 * F.e. from http://domain.domain:2020/test/a?test
 * Should pick http://domain.domain:2020/test/
 * @param {string} uri
 * @returns {string} path
 */
function path(uri) {
  return uri.replace(REGEXP_URI_PATH, '$1');
}

/**
 * @description
 * Get the fragment (#...) part of the uri
 * @see https://tools.ietf.org/html/rfc3986#section-3
 * @param {string} uri
 * @returns {string} fragment
 */
function fragment(uri) {
  if (typeof uri !== 'string') {
    return uri;
  }

  const parts = uri.split(REGEXP_URI_FRAGMENT);
  return parts[1];
}

/**
 * @name makePath
 * @type function
 * @description
 * Concat parts into single uri
 * @see https://tools.ietf.org/html/rfc3986#section-3
 * @param {array[string]} parts
 * @returns {string} uri
 */
function makePath(parts) {
  return parts
    .filter(part => typeof part === 'string')
    .reduce((uri, id) => {
      if (!uri.length) {
        return id;
      }

      // if id is full replace uri
      if (isFullUri(id)) {
        return id;
      }

      // if fragment found
      if (id.indexOf('#') === 0) {
        // should replace uri's sharp with id
        const sharpUriIndex = uri.indexOf('#');
        return uri.slice(0, sharpUriIndex) + id;
      }

      // get path part of uri
      // and replace the rest with id
      const partialUri = path(uri) + id;
      return partialUri + (partialUri.indexOf('#') === -1 ? '#' : '');
    }, '');
}

function hasProperty(object, property) {
  return Object.prototype.hasOwnProperty.call(object, property);
}

function normalize(uri) {
  return decodeURIComponent(uri.replace(/~1/g, '/').replace(/~0/g, '~'));
}

function descent(uri, parentSchema) {
  const uriFragment = fragment(uri);
  if (!uriFragment) {
    return parentSchema;
  }

  const parts = uriFragment.split('/');
  return parts
    .map(normalize)
    .reduce((schema, part) => (
      schema[part] || (
        schema.definitions &&
        schema.definitions[part]
      ))
    , parentSchema);
}

module.exports = {
  cleanId,
  asExpression,
  hasProperty,
  // TODO move to utils/uri
  makePath,
  isFullUri,
  head,
  fragment,
  descent,
};
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { Scrollbars } from 'react-custom-scrollbars'
import { SpringSystem } from 'rebound'
import css from 'dom-css'

const shadowStyle = {
  zIndex: 999,
  pointerEvents: 'none',
  position: 'absolute',
  left: 0,
  right: 0,
  height: '1.5rem'
}

const shadowTopStyle = {
  ...shadowStyle,
  top: 0,
  background: 'linear-gradient(to bottom, rgba(0, 0, 0, 0.25) 0%, rgba(0, 0, 0, 0) 100%)'
}

const shadowBottomStyle = {
  ...shadowStyle,
  bottom: 0,
  background: 'linear-gradient(to top, rgba(0, 0, 0, 0.25) 0%, rgba(0, 0, 0, 0) 100%)'
}

export default class ShadowScrollbars extends Component {
  node = React.createRef()
  scrollbarsRef = React.createRef()
  shadowBottom = React.createRef()
  shadowTop = React.createRef()

  onUpdate = (values) => {
    const { shadowTop, shadowBottom } = this
    const { scrollTop, scrollHeight, clientHeight } = values
    const shadowTopOpacity = 1 / 20 * Math.min(scrollTop, 20)
    const bottomScrollTop = scrollHeight - clientHeight
    const shadowBottomOpacity = 1 / 20 * (bottomScrollTop - Math.max(scrollTop, bottomScrollTop - 20))
    css(shadowTop.current, { opacity: shadowTopOpacity })
    css(shadowBottom.current, { opacity: shadowBottomOpacity })
  }

  getSpringUpdateFunc = (func) => (spring) => {
    if (func && typeof func === 'function') {
      func(spring.getCurrentValue())
    }
  }

  getBoundingClientRect = () => {
    return this.node.current.getBoundingClientRect()
  }

  scrollTo = ({ top = 0, left = 0 }) => {
    if (!top && !left) {
      return
    }
    const scrollbars = this.scrollbarsRef.current
    if (scrollbars) {
      const scrollTop = scrollbars.getScrollTop()
      const scrollLeft = scrollbars.getScrollLeft()
      this.leftSpring.setCurrentValue(scrollLeft).setAtRest()
      this.leftSpring.setEndValue(scrollLeft + left)
      this.spring.setCurrentValue(scrollTop).setAtRest()
      this.spring.setEndValue(scrollTop + top)
    }
  }

  componentDidMount () {
    const { scrollTop, scrollLeft } = this.scrollbarsRef.current
    this.springSystem = new SpringSystem()
    this.spring = this.springSystem.createSpring()
    this.spring.addListener({
      onSpringUpdate: this.getSpringUpdateFunc(scrollTop)
    })
    this.leftSpring = this.springSystem.createSpring()
    this.leftSpring.addListener({
      onSpringUpdate: this.getSpringUpdateFunc(scrollLeft)
    })
  }

  componentWillUnmount () {
    this.springSystem.deregisterSpring(this.spring)
    this.springSystem.removeAllListeners()
    this.spring.destroy()
    this.leftSpring.destroy()
    this.spring = null
    this.leftSpring = null
    this.springSystem = null
  }

  render () {
    const { style, ...props } = this.props
    const containerStyle = {
      ...style,
      position: 'relative'
    }
    return (
      <div
        ref={this.node}
        style={containerStyle}
      >
        <Scrollbars
          ref={this.scrollbarsRef}
          onUpdate={this.onUpdate}
          {...props} />
        <div
          ref={this.shadowTop}
          style={shadowTopStyle} />
        <div
          ref={this.shadowBottom}
          style={shadowBottomStyle} />
      </div>
    )
  }
}
<commit_msg>Narrow the shadow of ShadowScrollbars<commit_after>import React, { Component } from 'react'
import { Scrollbars } from 'react-custom-scrollbars'
import { SpringSystem } from 'rebound'
import css from 'dom-css'

const shadowStyle = {
  zIndex: 999,
  pointerEvents: 'none',
  position: 'absolute',
  left: 0,
  right: 0,
  height: '1.2rem'
}

const shadowTopStyle = {
  ...shadowStyle,
  top: 0,
  background: 'linear-gradient(to bottom, rgba(0, 0, 0, 0.25) 0%, rgba(0, 0, 0, 0) 100%)'
}

const shadowBottomStyle = {
  ...shadowStyle,
  bottom: 0,
  background: 'linear-gradient(to top, rgba(0, 0, 0, 0.25) 0%, rgba(0, 0, 0, 0) 100%)'
}

export default class ShadowScrollbars extends Component {
  node = React.createRef()
  scrollbarsRef = React.createRef()
  shadowBottom = React.createRef()
  shadowTop = React.createRef()

  onUpdate = (values) => {
    const { shadowTop, shadowBottom } = this
    const { scrollTop, scrollHeight, clientHeight } = values
    const shadowTopOpacity = 1 / 20 * Math.min(scrollTop, 20)
    const bottomScrollTop = scrollHeight - clientHeight
    const shadowBottomOpacity = 1 / 20 * (bottomScrollTop - Math.max(scrollTop, bottomScrollTop - 20))
    css(shadowTop.current, { opacity: shadowTopOpacity })
    css(shadowBottom.current, { opacity: shadowBottomOpacity })
  }

  getSpringUpdateFunc = (func) => (spring) => {
    if (func && typeof func === 'function') {
      func(spring.getCurrentValue())
    }
  }

  getBoundingClientRect = () => {
    return this.node.current.getBoundingClientRect()
  }

  scrollTo = ({ top = 0, left = 0 }) => {
    if (!top && !left) {
      return
    }
    const scrollbars = this.scrollbarsRef.current
    if (scrollbars) {
      const scrollTop = scrollbars.getScrollTop()
      const scrollLeft = scrollbars.getScrollLeft()
      this.leftSpring.setCurrentValue(scrollLeft).setAtRest()
      this.leftSpring.setEndValue(scrollLeft + left)
      this.spring.setCurrentValue(scrollTop).setAtRest()
      this.spring.setEndValue(scrollTop + top)
    }
  }

  componentDidMount () {
    const { scrollTop, scrollLeft } = this.scrollbarsRef.current
    this.springSystem = new SpringSystem()
    this.spring = this.springSystem.createSpring()
    this.spring.addListener({
      onSpringUpdate: this.getSpringUpdateFunc(scrollTop)
    })
    this.leftSpring = this.springSystem.createSpring()
    this.leftSpring.addListener({
      onSpringUpdate: this.getSpringUpdateFunc(scrollLeft)
    })
  }

  componentWillUnmount () {
    this.springSystem.deregisterSpring(this.spring)
    this.springSystem.removeAllListeners()
    this.spring.destroy()
    this.leftSpring.destroy()
    this.spring = null
    this.leftSpring = null
    this.springSystem = null
  }

  render () {
    const { style, ...props } = this.props
    const containerStyle = {
      ...style,
      position: 'relative'
    }
    return (
      <div
        ref={this.node}
        style={containerStyle}
      >
        <Scrollbars
          ref={this.scrollbarsRef}
          onUpdate={this.onUpdate}
          {...props} />
        <div
          ref={this.shadowTop}
          style={shadowTopStyle} />
        <div
          ref={this.shadowBottom}
          style={shadowBottomStyle} />
      </div>
    )
  }
}
<|endoftext|>


<commit_before>/* Animate views */

var transitionend = 'transitionend';

$(document).on(transitionend, '.animate.active', function() {
	$(this).dequeue();
});

function transition(className, options, complete) {
	options = options || {};

	if (options.className)
		className += ' ' + options.className;

	var stop;

	return {
		start: function(next, hooks) {
			hooks.stop = stop = animate.call(this, className, options);
		},

		finish: function() {
			if (complete) complete.call(this);
			stop();
			$(this).removeClass('animate active').css({ height: '' }).dequeue();
		}
	};
}

function animate(className, options) {
	// The extra offsetHeight is required to fix IE bug. if there is button in the page,
	// the page will be placed at it's end location, then aniamted out until the enter active class is added.
	//
	// this bug can apparently be sorted by setting the start position in .animate instead of .page
	//$(this).addClass('enter');

	// force redraw
	//this.offsetHeight;
	var elem = $(this).addClass('animate ' + className);

	// force redraw
	this.offsetHeight;

	var timeout = setTimeout(function() {
		elem.addClass('active');

		var duration = parseFloat(elem.css('transition-duration'));

		timeout = setTimeout(function() {
			// finish animation if we are still waiting for transitionend

			if (elem.is('.animate.active')) elem.dequeue();
		}, duration > 0 ? duration * 1100 : 0);
	});

	return function() {
		clearTimeout(timeout);
		elem.removeClass(className);
	};
}

$.fn.extend({

	toggle: function(options) {
		if(this.hasClass('hidden') || this.hasClass('leave'))
			this.show(options);
		else
			this.hide(options);
	},

	enter: function(element, options) {
		options = options || {};

		var enter = transition('enter', options);

		return this.queue(function() {
			$(element)[options.method || 'append'](this);

			$(this).removeClass('hidden');

			if (options.animateHeight)
				$(this).css('height', this.scrollHeight);

			enter.start.apply(this, arguments);
		}).queue(enter.finish);
	},

	leave: function(options, complete) {

		var leave = transition('leave', options, complete || function() {
			// remove element when transition ends
			$(this).remove();
		});

		this.finish();

		if (options && options.animateHeight && !this.hasClass('animate')) {
			this.queue(function(next, hooks) {
				$(this).css('height', this.scrollHeight);

				this.offsetHeight;

				var timeout = setTimeout(next);

				hooks.stop = function() {
					clearTimeout(timeout);
				};
			});
		}

		return this.queue(leave.start).queue(leave.finish);
	},

	show: function(options) {
		this.finish()
			.queue(function(next) {
				$(this).addClass('visible');

				next();
			});

		return this.enter(null, options);
	},

	hide: function(options) {

		return this.leave(options, function() {
			$(this).addClass('hidden').removeClass('visible');
		});
	}
});
<commit_msg>Enable passing 'complete' callback (was implemented, but not 'activated')<commit_after>/* Animate views */

var transitionend = 'transitionend';

$(document).on(transitionend, '.animate.active', function() {
	$(this).dequeue();
});

function transition(className, options, complete) {
	options = options || {};

	if (options.className)
		className += ' ' + options.className;

	var stop;

	return {
		start: function(next, hooks) {
			hooks.stop = stop = animate.call(this, className, options);
		},

		finish: function() {
			if (complete) complete.call(this);
			stop();
			$(this).removeClass('animate active').css({ height: '' }).dequeue();
		}
	};
}

function animate(className, options) {
	// The extra offsetHeight is required to fix IE bug. if there is button in the page,
	// the page will be placed at it's end location, then aniamted out until the enter active class is added.
	//
	// this bug can apparently be sorted by setting the start position in .animate instead of .page
	//$(this).addClass('enter');

	// force redraw
	//this.offsetHeight;
	var elem = $(this).addClass('animate ' + className);

	// force redraw
	this.offsetHeight;

	var timeout = setTimeout(function() {
		elem.addClass('active');

		var duration = parseFloat(elem.css('transition-duration'));

		timeout = setTimeout(function() {
			// finish animation if we are still waiting for transitionend

			if (elem.is('.animate.active')) elem.dequeue();
		}, duration > 0 ? duration * 1100 : 0);
	});

	return function() {
		clearTimeout(timeout);
		elem.removeClass(className);
	};
}

$.fn.extend({

	toggle: function(options) {
		if(this.hasClass('hidden') || this.hasClass('leave'))
			this.show(options);
		else
			this.hide(options);
	},

	enter: function(element, options, complete) {
		options = options || {};

		var enter = transition('enter', options, complete);

		return this.queue(function() {
			$(element)[options.method || 'append'](this);

			$(this).removeClass('hidden');

			if (options.animateHeight)
				$(this).css('height', this.scrollHeight);

			enter.start.apply(this, arguments);
		}).queue(enter.finish);
	},

	leave: function(options, complete) {

		var leave = transition('leave', options, complete || function() {
			// remove element when transition ends
			$(this).remove();
		});

		this.finish();

		if (options && options.animateHeight && !this.hasClass('animate')) {
			this.queue(function(next, hooks) {
				$(this).css('height', this.scrollHeight);

				this.offsetHeight;

				var timeout = setTimeout(next);

				hooks.stop = function() {
					clearTimeout(timeout);
				};
			});
		}

		return this.queue(leave.start).queue(leave.finish);
	},

	show: function(options) {
		this.finish()
			.queue(function(next) {
				$(this).addClass('visible');

				next();
			});

		return this.enter(null, options);
	},

	hide: function(options) {

		return this.leave(options, function() {
			$(this).addClass('hidden').removeClass('visible');
		});
	}
});
<|endoftext|>