<commit_before>(function (ns) {
    /**
     * Shade.js specific type inference that is also inferring
     * virtual types {@link Shade.TYPES }
     */

    var walk = require('estraverse'),
        enterExpression = require('./infer_expression.js').enterExpression,
        exitExpression = require('./infer_expression.js').exitExpression,
        enterStatement = require('./infer_statement.js').enterStatement,
        exitStatement = require('./infer_statement.js').exitStatement,
        assert = require("assert"),

        ObjectRegistry = require("./registry/index.js").Registry,
        Context = require("./../../base/context.js").getContext(ObjectRegistry),
        Base = require("../../base/index.js"),
        Annotation = require("./../../base/annotation.js").Annotation,
        FunctionAnnotation = require("./../../base/annotation.js").FunctionAnnotation;

    var Syntax = walk.Syntax;

    var registerGlobalContext = function (program) {
        var ctx = new Context(program, null, {name: "global"});
        ctx.registerObject("Math", ObjectRegistry.getByName("Math"));
        ctx.registerObject("Color", ObjectRegistry.getByName("Color"));
        ctx.registerObject("Vec2", ObjectRegistry.getByName("Vec2"));
        ctx.registerObject("Vec3", ObjectRegistry.getByName("Vec3"));
        ctx.registerObject("Vec4", ObjectRegistry.getByName("Vec4"));
        ctx.registerObject("Texture", ObjectRegistry.getByName("Texture"));
        ctx.registerObject("Shade", ObjectRegistry.getByName("Shade"));
        //ctx.registerObject("this", ObjectRegistry.getByName("System"));
        ctx.registerObject("Mat3", ObjectRegistry.getByName("Mat3"));
        ctx.declareVariable("this");
        ctx.declareVariable("_env");
        return ctx;
    };

    var registerGlobalObjects = function(context, thisObject, envObject) {
        if(thisObject) {
            var thisAnnotation = new Annotation({}, thisObject);
            context.updateExpression("this", thisAnnotation);
        }
        if (envObject) {
            var envAnnotation = new Annotation({}, envObject);
            context.updateExpression("_env", envAnnotation);
        }
    }

    var TypeInference = function (root, opt) {
        opt = opt || {};
        this.root = root;
        this.context = [];
        /** @type {Object.<String, Array.<TypeInfo>} **/
        this.entryPoint = opt.entry || "global.shade";
        this.functions = {
            orig: {},
            derived: {}
        }
        this.root.globalParameters = {};

    }

    Base.extend(TypeInference.prototype, {
        pushContext: function (context) {
            this.context.push(context);
            /*var injection = this.injections[context.str()];
            if (injection) {
                context.injectParameters(injection);
            }*/
        },
        popContext: function () {
            this.context.pop();
        },
        peekContext: function () {
            return this.context[this.context.length - 1];
        },
        createContext: function (node, parentContext, name) {
           var result = new Context(node, parentContext, {name: name } );
           return result;
        },

        annotateParameters: function(arr) {
            return arr ? arr.map(function(param) {
                var annotated =  new Annotation(param);
                return annotated;
            }) : [];
        },

        buildFunctionMap: function(prg) {
            var that = this;
            walk.replace(prg, {
                enter: function(node) {
                    if (node.type == Syntax.FunctionDeclaration) {
                        var result = new FunctionAnnotation(node);
                        var functionName = node.id.name;
                        var parentContext = that.peekContext();
                        var functionContext = that.createContext(node, parentContext, functionName);
                        functionContext.declareParameters(node.params);
                        parentContext.declareVariable(functionName);
                        parentContext.updateExpression(functionName, result);
                        that.pushContext(functionContext);
                        that.functions.orig[functionContext.str()] = node;
                    }
                },
                leave: function(node) {
                    if (node.type == Syntax.FunctionDeclaration) {
                        that.popContext();
                        return { type: Syntax.EmptyStatement };
                    }
                }
            });
           prg.body = prg.body.filter(function(a) { return a.type != Syntax.EmptyStatement; });
        },

        traverse: function (node) {
            walk.traverse(node, {
                enter: this.enterNode.bind(this),
                leave: this.exitNode.bind(this)
            });
            return node;
        },

        enterNode: function (node, parent) {
            var context = this.context[this.context.length - 1];
            return this.switchKind(node, parent, context, enterStatement, enterExpression);
        },

        exitNode: function (node, parent) {
            var context = this.context[this.context.length - 1];
            return this.switchKind(node, parent, context, exitStatement, exitExpression);
        },

        switchKind: function (node, parent, ctx, statement, expression) {
            switch (node.type) {
                case Syntax.BlockStatement:
                case Syntax.BreakStatement:
                case Syntax.CatchClause:
                case Syntax.ContinueStatement:
                case Syntax.DirectiveStatement:
                case Syntax.DoWhileStatement:
                case Syntax.DebuggerStatement:
                case Syntax.EmptyStatement:
                case Syntax.ExpressionStatement:
                case Syntax.ForStatement:
                case Syntax.ForInStatement:
                case Syntax.FunctionDeclaration:
                case Syntax.IfStatement:
                case Syntax.LabeledStatement:
                case Syntax.Program:
                case Syntax.ReturnStatement:
                case Syntax.SwitchStatement:
                case Syntax.SwitchCase:
                case Syntax.ThrowStatement:
                case Syntax.TryStatement:
                case Syntax.VariableDeclaration:
                case Syntax.VariableDeclarator:
                case Syntax.WhileStatement:
                case Syntax.WithStatement:
                    return statement.call(this, node, parent, ctx);

                case Syntax.AssignmentExpression:
                case Syntax.ArrayExpression:
                case Syntax.ArrayPattern:
                case Syntax.BinaryExpression:
                case Syntax.CallExpression:
                case Syntax.ConditionalExpression:
                case Syntax.FunctionExpression:
                case Syntax.Identifier:
                case Syntax.Literal:
                case Syntax.LogicalExpression:
                case Syntax.MemberExpression:
                case Syntax.NewExpression:
                case Syntax.ObjectExpression:
                case Syntax.ObjectPattern:
                case Syntax.Property:
                case Syntax.SequenceExpression:
                case Syntax.ThisExpression:
                case Syntax.UnaryExpression:
                case Syntax.UpdateExpression:
                case Syntax.YieldExpression:
                    return expression.call(this, node, parent, ctx);

                default:
                    throw new Error('Unknown node type: ' + node.type);
            }
        },

        /**
         *
         * @param {Object} functionAST
         * @param {Array.<TypeInfo> params
         * @param {Context} parentContext
         * @returns {*}
         */
        inferFunction: function (functionAST, params, parentContext) {
            var functionName = functionAST.id.name;
            var targetContextName = parentContext.getVariableIdentifier(functionName);
            //this.injections[targetContextName] = params;

            // We have a specifc type set in params that we annotate to the
            // function AST
            for(var i = 0; i < params.length; i++) {
                if (i == functionAST.params.length)
                    break;
                var funcParam = new Annotation(functionAST.params[i]);
                funcParam.setFromExtra(params[i].getExtra());
            }

            var oldEntryPoint = this.entryPoint;
            this.entryPoint = targetContextName;
            this.pushContext(parentContext);
            // console.error("Starting to traverse: " + functionName + " in context " + parentContext.str())
            var ast = this.traverse(functionAST);
            this.popContext();
            this.entryPoint = oldEntryPoint;

            return ast;
        },

        inferProgram: function(prg, globalParameters) {
            var params = globalParameters || {};
            var globalContext = registerGlobalContext(prg);
            registerGlobalObjects(globalContext, params.this, params[this.entryPoint][0].extra);

            this.pushContext(globalContext);
            // Removes all functions from AST and puts them into a map
            this.buildFunctionMap(prg);
            // Traverse code outside of any function
            this.traverse(prg);
            this.popContext();

            var entryPoint = this.entryPoint;
            if (this.functions.orig.hasOwnProperty(entryPoint)) {
                var ast = this.functions.orig[entryPoint];
                var params = this.annotateParameters(params[entryPoint]);
                this.root.globalParameters[entryPoint] = params;
                // Analyse the main function
                var aast = this.inferFunction(ast, params, globalContext);

                // Put all functions that were used during analysis back into ast
                for(var func in this.functions.derived) {
                    var variations = this.functions.derived[func];
                    for (var signature in variations) {
                        prg.body.push(variations[signature].ast);
                    }

                }
                // Put main function back into ast
                prg.body.push(aast);
            }

            if (this.context.length)
                throw Error("Something went wrong");
            return prg;
        },
        getFunctionInformationByNameAndSignature: function(name, signature) {
            if (this.functions.derived.hasOwnProperty(name)) {
                var derivedFunction = this.functions.derived[name];
                if (derivedFunction.hasOwnProperty(signature)) {
                    return derivedFunction[signature].info;
                }
            }
            return null;
        },
        getFunctionInformationFor: function(name, args, definingContext) {
            var signature = args.reduce(function(str, arg) { return str + arg.getTypeString()}, "");
            var info = this.getFunctionInformationByNameAndSignature(name, signature);
            if (info)
                return info;

            return this.createFunctionInformationFor(name, args, definingContext);
        },
        createFunctionInformationFor: function(name, args, definingContext) {
            var signature = args.reduce(function(str, arg) { return str + arg.getTypeString()}, "");
            if (this.functions.orig.hasOwnProperty(name)) {
                var ast = this.functions.orig[name];
                var variations = this.functions.derived[name] = this.functions.derived[name] || {};
                var derived = variations[signature] = {};
                derived.ast = this.inferFunction(JSON.parse(JSON.stringify(ast)), args, definingContext);
                derived.info = derived.ast.extra.returnInfo;
                derived.info.newName = name.replace(/\./g, '_') + Object.keys(variations).length;
                derived.ast.id.name = derived.info.newName;
                return derived.info;
            }
            throw new Error("Could not resolve function " + name);
        },
        callGlobalFunction: function (name, args, context) {
            // context.declareVariable(func.name);
            var globalName = context.getVariableIdentifier(name),
                signature = args.reduce(function (str, arg) {
                    return str + arg.getTypeString()
                }, "");

            var info = this.getFunctionInformationByNameAndSignature(globalName, signature);
            if (info)
                return info;

            return this.createFunctionInformationFor(globalName, args, context);
        }
    });

    ns.infer = function (ast, opt) {
        var ti = new TypeInference(ast, opt);
        return ti.inferProgram(ti.root, opt.inject);
    };

}(exports));
<commit_msg>Fix for inference without external parameters<commit_after>(function (ns) {
    /**
     * Shade.js specific type inference that is also inferring
     * virtual types {@link Shade.TYPES }
     */

    var walk = require('estraverse'),
        enterExpression = require('./infer_expression.js').enterExpression,
        exitExpression = require('./infer_expression.js').exitExpression,
        enterStatement = require('./infer_statement.js').enterStatement,
        exitStatement = require('./infer_statement.js').exitStatement,
        assert = require("assert"),

        ObjectRegistry = require("./registry/index.js").Registry,
        Context = require("./../../base/context.js").getContext(ObjectRegistry),
        Base = require("../../base/index.js"),
        Annotation = require("./../../base/annotation.js").Annotation,
        FunctionAnnotation = require("./../../base/annotation.js").FunctionAnnotation;

    var Syntax = walk.Syntax;

    var registerGlobalContext = function (program) {
        var ctx = new Context(program, null, {name: "global"});
        ctx.registerObject("Math", ObjectRegistry.getByName("Math"));
        ctx.registerObject("Color", ObjectRegistry.getByName("Color"));
        ctx.registerObject("Vec2", ObjectRegistry.getByName("Vec2"));
        ctx.registerObject("Vec3", ObjectRegistry.getByName("Vec3"));
        ctx.registerObject("Vec4", ObjectRegistry.getByName("Vec4"));
        ctx.registerObject("Texture", ObjectRegistry.getByName("Texture"));
        ctx.registerObject("Shade", ObjectRegistry.getByName("Shade"));
        //ctx.registerObject("this", ObjectRegistry.getByName("System"));
        ctx.registerObject("Mat3", ObjectRegistry.getByName("Mat3"));
        ctx.declareVariable("this");
        ctx.declareVariable("_env");
        return ctx;
    };

    var registerGlobalObjects = function(context, thisObject, envObject) {
        if(thisObject) {
            var thisAnnotation = new Annotation({}, thisObject);
            context.updateExpression("this", thisAnnotation);
        }
        if (envObject) {
            var envAnnotation = new Annotation({}, envObject);
            context.updateExpression("_env", envAnnotation);
        }
    }

    var getFirstParameterOfEntryFunction = function(parameter, entryPoint) {
        if (!entryPoint || !parameter[entryPoint])
            return null;
        var entryPointParameters = parameter[entryPoint];
        if (!Array.isArray(entryPointParameters) || !entryPointParameters.length)
            return null;
        return entryPointParameters[0].extra || null;
    }

    var TypeInference = function (root, opt) {
        opt = opt || {};
        this.root = root;
        this.context = [];
        /** @type {Object.<String, Array.<TypeInfo>} **/
        this.entryPoint = opt.entry || "global.shade";
        this.functions = {
            orig: {},
            derived: {}
        }
        this.root.globalParameters = {};

    }

    Base.extend(TypeInference.prototype, {
        pushContext: function (context) {
            this.context.push(context);
            /*var injection = this.injections[context.str()];
            if (injection) {
                context.injectParameters(injection);
            }*/
        },
        popContext: function () {
            this.context.pop();
        },
        peekContext: function () {
            return this.context[this.context.length - 1];
        },
        createContext: function (node, parentContext, name) {
           var result = new Context(node, parentContext, {name: name } );
           return result;
        },

        annotateParameters: function(arr) {
            return arr ? arr.map(function(param) {
                var annotated =  new Annotation(param);
                return annotated;
            }) : [];
        },

        buildFunctionMap: function(prg) {
            var that = this;
            walk.replace(prg, {
                enter: function(node) {
                    if (node.type == Syntax.FunctionDeclaration) {
                        var result = new FunctionAnnotation(node);
                        var functionName = node.id.name;
                        var parentContext = that.peekContext();
                        var functionContext = that.createContext(node, parentContext, functionName);
                        functionContext.declareParameters(node.params);
                        parentContext.declareVariable(functionName);
                        parentContext.updateExpression(functionName, result);
                        that.pushContext(functionContext);
                        that.functions.orig[functionContext.str()] = node;
                    }
                },
                leave: function(node) {
                    if (node.type == Syntax.FunctionDeclaration) {
                        that.popContext();
                        return { type: Syntax.EmptyStatement };
                    }
                }
            });
           prg.body = prg.body.filter(function(a) { return a.type != Syntax.EmptyStatement; });
        },

        traverse: function (node) {
            walk.traverse(node, {
                enter: this.enterNode.bind(this),
                leave: this.exitNode.bind(this)
            });
            return node;
        },

        enterNode: function (node, parent) {
            var context = this.context[this.context.length - 1];
            return this.switchKind(node, parent, context, enterStatement, enterExpression);
        },

        exitNode: function (node, parent) {
            var context = this.context[this.context.length - 1];
            return this.switchKind(node, parent, context, exitStatement, exitExpression);
        },

        switchKind: function (node, parent, ctx, statement, expression) {
            switch (node.type) {
                case Syntax.BlockStatement:
                case Syntax.BreakStatement:
                case Syntax.CatchClause:
                case Syntax.ContinueStatement:
                case Syntax.DirectiveStatement:
                case Syntax.DoWhileStatement:
                case Syntax.DebuggerStatement:
                case Syntax.EmptyStatement:
                case Syntax.ExpressionStatement:
                case Syntax.ForStatement:
                case Syntax.ForInStatement:
                case Syntax.FunctionDeclaration:
                case Syntax.IfStatement:
                case Syntax.LabeledStatement:
                case Syntax.Program:
                case Syntax.ReturnStatement:
                case Syntax.SwitchStatement:
                case Syntax.SwitchCase:
                case Syntax.ThrowStatement:
                case Syntax.TryStatement:
                case Syntax.VariableDeclaration:
                case Syntax.VariableDeclarator:
                case Syntax.WhileStatement:
                case Syntax.WithStatement:
                    return statement.call(this, node, parent, ctx);

                case Syntax.AssignmentExpression:
                case Syntax.ArrayExpression:
                case Syntax.ArrayPattern:
                case Syntax.BinaryExpression:
                case Syntax.CallExpression:
                case Syntax.ConditionalExpression:
                case Syntax.FunctionExpression:
                case Syntax.Identifier:
                case Syntax.Literal:
                case Syntax.LogicalExpression:
                case Syntax.MemberExpression:
                case Syntax.NewExpression:
                case Syntax.ObjectExpression:
                case Syntax.ObjectPattern:
                case Syntax.Property:
                case Syntax.SequenceExpression:
                case Syntax.ThisExpression:
                case Syntax.UnaryExpression:
                case Syntax.UpdateExpression:
                case Syntax.YieldExpression:
                    return expression.call(this, node, parent, ctx);

                default:
                    throw new Error('Unknown node type: ' + node.type);
            }
        },

        /**
         *
         * @param {Object} functionAST
         * @param {Array.<TypeInfo> params
         * @param {Context} parentContext
         * @returns {*}
         */
        inferFunction: function (functionAST, params, parentContext) {
            var functionName = functionAST.id.name;
            var targetContextName = parentContext.getVariableIdentifier(functionName);
            //this.injections[targetContextName] = params;

            // We have a specifc type set in params that we annotate to the
            // function AST
            for(var i = 0; i < params.length; i++) {
                if (i == functionAST.params.length)
                    break;
                var funcParam = new Annotation(functionAST.params[i]);
                funcParam.setFromExtra(params[i].getExtra());
            }

            var oldEntryPoint = this.entryPoint;
            this.entryPoint = targetContextName;
            this.pushContext(parentContext);
            // console.error("Starting to traverse: " + functionName + " in context " + parentContext.str())
            var ast = this.traverse(functionAST);
            this.popContext();
            this.entryPoint = oldEntryPoint;

            return ast;
        },

        inferProgram: function(prg, globalParameters) {
            var params = globalParameters || {};
            var globalContext = registerGlobalContext(prg);
            registerGlobalObjects(globalContext, params.this, getFirstParameterOfEntryFunction(params, this.entryPoint));

            this.pushContext(globalContext);
            // Removes all functions from AST and puts them into a map
            this.buildFunctionMap(prg);
            // Traverse code outside of any function
            this.traverse(prg);
            this.popContext();

            var entryPoint = this.entryPoint;
            if (this.functions.orig.hasOwnProperty(entryPoint)) {
                var ast = this.functions.orig[entryPoint];
                var params = this.annotateParameters(params[entryPoint]);
                this.root.globalParameters[entryPoint] = params;
                // Analyse the main function
                var aast = this.inferFunction(ast, params, globalContext);

                // Put all functions that were used during analysis back into ast
                for(var func in this.functions.derived) {
                    var variations = this.functions.derived[func];
                    for (var signature in variations) {
                        prg.body.push(variations[signature].ast);
                    }

                }
                // Put main function back into ast
                prg.body.push(aast);
            }

            if (this.context.length)
                throw Error("Something went wrong");
            return prg;
        },
        getFunctionInformationByNameAndSignature: function(name, signature) {
            if (this.functions.derived.hasOwnProperty(name)) {
                var derivedFunction = this.functions.derived[name];
                if (derivedFunction.hasOwnProperty(signature)) {
                    return derivedFunction[signature].info;
                }
            }
            return null;
        },
        getFunctionInformationFor: function(name, args, definingContext) {
            var signature = args.reduce(function(str, arg) { return str + arg.getTypeString()}, "");
            var info = this.getFunctionInformationByNameAndSignature(name, signature);
            if (info)
                return info;

            return this.createFunctionInformationFor(name, args, definingContext);
        },
        createFunctionInformationFor: function(name, args, definingContext) {
            var signature = args.reduce(function(str, arg) { return str + arg.getTypeString()}, "");
            if (this.functions.orig.hasOwnProperty(name)) {
                var ast = this.functions.orig[name];
                var variations = this.functions.derived[name] = this.functions.derived[name] || {};
                var derived = variations[signature] = {};
                derived.ast = this.inferFunction(JSON.parse(JSON.stringify(ast)), args, definingContext);
                derived.info = derived.ast.extra.returnInfo;
                derived.info.newName = name.replace(/\./g, '_') + Object.keys(variations).length;
                derived.ast.id.name = derived.info.newName;
                return derived.info;
            }
            throw new Error("Could not resolve function " + name);
        },
        callGlobalFunction: function (name, args, context) {
            // context.declareVariable(func.name);
            var globalName = context.getVariableIdentifier(name),
                signature = args.reduce(function (str, arg) {
                    return str + arg.getTypeString()
                }, "");

            var info = this.getFunctionInformationByNameAndSignature(globalName, signature);
            if (info)
                return info;

            return this.createFunctionInformationFor(globalName, args, context);
        }
    });

    ns.infer = function (ast, opt) {
        var ti = new TypeInference(ast, opt);
        return ti.inferProgram(ti.root, opt.inject);
    };

}(exports));
<|endoftext|>


<commit_before>// For more information on the 'revealing module' pattern, see
//   http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript
var WebMonitor = (function($, undefined) {
  'use strict';

  var settings = {
    // Show `console.log` messages?
    debug: false,
    // Default job status polling timeout in milliseconds
    pollRate: 300,
    // Defaults for histogram drawing
    histogramDefaults: {
    },
    // See http://fgnass.github.io/spin.js/ for options and customisation
    spinnerDefaults: {
      lines: 12,
      length: 5,
      width: 2,
      radius: 5,
      trail: 50,
      shadow: false
    },
    // See http://eternicode.github.io/bootstrap-datepicker/
    datepickerDefaults: {
      format: 'dd/mm/yyyy',
      // This app doesn't now about the future
      endDate: '+0d',
      todayBtn: 'linked',
      // Always pop under the field
      orientation: 'top auto',
      autoclose: true,
      todayHighlight: true
    }
  };

  // Cross-browser compatible `console.log`. Only fires if settings.debug === true.
  // http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
  // Accepts:
  //   Any number of arguments of any type.
  // Returns:
  //   undefined
  var log = function() {
    log.history = log.history || [];
    log.history.push(arguments);
    if (window.console && settings.debug) {
      console.log(Array.prototype.slice.call(arguments));
    }
  };

  // Draw a histogram in the `container` using `options`.
  // Accepts:
  //   container: A jQuery object in which to draw the histogram
  //     If the jQuery object references multiple DOM nodes, the first is used
  //   data: An array of data points formatted for d3.chart.histogram
  //   options: Object of options passed to the plotting library
  //     Any present options override those in WebMonitor.settings.histogramDefaults
  // Returns:
  //   undefined
  var drawHistogram = function(container, data, options) {
    var opt = $.extend(true, {}, WebMonitor.settings.histogramDefaults, options);
    d3.select(container.get()[0]).append('svg')
      .attr('width', container.width())
      .attr('height', container.height())
      .chart('HistogramZoom')
      .xAxisLabel(opt.xAxis.title.text)
      .yAxisLabel(opt.yAxis.title.text)
      .draw(data);
  };

  // Display a histogram, described by `data`, in `container`.
  // Accepts:
  //   data: An object describing the histogram
  //   container: A jQuery object in which to draw the histogram
  // Returns:
  //   undefined
  var displayHistogram = function(data, container) {
    var name = data['name'],
        title = data['title'],
        binning = data['binning'],
        values = data['values'],
        uncertainties = data['uncertainties'],
        axisTitles = data['axis_titles'];
    var v, binCenter, uLow, uHigh;
    // We need to manipulate the values slightly for d3.chart.histogram
    // See the d3.chart.histogram documentation for the specifics
    var formattedData = [];
    for (var i = 0; i < values.length; i++) {
      var bins = binning[i];
      formattedData.push({
        x: bins[0],
        dx: bins[1],
        y: data['values'][i],
        xErr: uncertainties[i]
      });
    }
    var options = {
      title: {
        text: title
      },
      xAxis: {
        title: {
          text: axisTitles[0]
        }
      },
      yAxis: {
        title: {
          text: axisTitles[1]
        }
      },
    };
    // Remove the spinner
    container.find('.spinner').remove();
    // Draw the histogram in the container
    drawHistogram(container, formattedData, options);
  };

  // Fetches and draws the named `histogram`, residing in `file`, in to the `container`.
  // Accepts:
  //   histogram: String of the histogram's full path key name with in the file
  //   file: String of the file name
  //   container: jQuery element the histogram should be drawn in to. Any existing content will be replaced.
  var loadHistogramFromFileIntoContainer = function(histogram, file, container) {
      var task = createTask('get_key_from_file', {filename: file, key_name: histogram});
      task.done(function(job) {
          displayHistogram(job['result']['data']['key_data'], container);
      });
      task.fail(function(message) {
        var failMsg = '
There was a problem retrieving histogram '
          + '' + histogram + ''
          + ' from file '
          + '' + file + ''
          + '. Please contact the administrator.
'
          + message;
        displayFailure(container, failMsg);
      });
  };

  // Submit a job to the server
  // Accepts:
  //   taskName: Name of the task the job will run
  //   args: Object of arguments passed to the task as named arguments
  //   poll: Whether to poll the job until completion (default: true)
  //     The job is polled in intervals of WebMonitor.settings.pollRate until
  //     the job status is not `queued` or `started`.
  // Returns:
  //   jQuery.Deferred object which fires `resolve` on job completion and fires
  //     `reject` on either submission failure or job polling failure
  var submitJob = function(taskName, args, doPoll) {
    if (doPoll === undefined) {
      doPoll = true;
    }
    var jobRequest =  $.ajax('/jobs', {
      type: 'POST',
      contentType: 'application/json; charset=utf-8',
      dataType: 'json',
      data: JSON.stringify({task_name: taskName, args: args})
    });
    var jobPromise = $.Deferred();
    var poll = function(job) {
      var jobID = job['id'],
          jobStatus = job['status'];
      // Poll the job if it hasn't not completed, else fire `resolve`
      if (jobStatus === 'queued' || jobStatus === 'started') {
        setTimeout(function() {
          log('Polling job ID ' + jobID + ': ' + jobStatus);
          $.getJSON(job['uri'])
            .done(function(data, status) { poll(data['job']); })
            .fail(function(data, status) { jobPromise.reject(data, status); });
        }, settings.pollRate);
      } else {
        log('Job ' + jobID + ' completed: ' + jobStatus);
        jobPromise.resolve(job);
      }
    };
    jobRequest.done(function(data, status) {
      var job = data['job'];
      if (doPoll === true) {
        poll(job);
      }
    });
    // Fire `reject` if the submission fails
    jobRequest.fail(function(data, status) { jobPromise.reject(data, status); });
    return jobPromise;
  };

  // Create a task and submit a job for it to the queue
  //
  // Unlike submitJob, this method handles job failures by creating descriptive
  // HTML error messages.
  // This relies on the JSON response containing a `result` key which is the
  // task's return value, which itself contains a `success` key determining
  // whether the task completed successfully.
  // If `success` if false, the task's `message` key is retrieved.
  // Accepts:
  //   taskName: Name of the task the job will run
  //   args: Object of arguments passed to the task as named arguments
  // Returns:
  //   jQuery.Deferred object which fires `resolve` on job completion and fires
  //     `reject` on either submission failure, job polling failure, or task
  //     failure. On resolution, the JSON response object is passed, whereas
  //     on rejection a descriptive HTML error message is passed.
  var createTask = function(taskName, args) {
    // Create a polling job
    var jobPromise = submitJob(taskName, args, true);
    var taskPromise = $.Deferred();
    jobPromise.done(function(job) {
      // Did the job complete successfully or not?
      if (job['status'] === 'failed') {
        var message = '
The job completed unsuccessfully.
';
        taskPromise.reject(message);
      } else {
        // Did the task the job was running finish successfully or not?
        var result = job['result'];
        if (result['success'] === false) {
          var message = '
The task could not complete successfully. It returned the error message '
            + '' + result['message'] + '.'
            + '
';
          taskPromise.reject(message);
        } else {
          taskPromise.resolve(job);
        }
      }
    });
    jobPromise.fail(function(data, status) {
      var message;
      try {
        message = JSON.parse(data.responseText)['message'];
      } catch(e) {
        message = data.statusText;
      }
      message = '
The server responded with the error code '
        + '' + data.status + ''
        + ' and the message '
        + '' + message + '.'
        + '
';
      taskPromise.reject(message);
    });
    return taskPromise;
  };

  // Display msg inside container, styled as a red error box
  // Accepts:
  //   container: jQuery element to insert msg into
  //   msg: HTML message to display inside container
  var displayFailure = function(container, msg) {
    container.html('
' + msg + '
');
  };

  // Add a `Spinner` object to the `element`, using `settings.spinnerDefaults` as options.
  // Accepts:
  //   element: DOM element
  // Returns:
  //   Spinner object
  var appendSpinner = function(element) {
    return new Spinner(settings.spinnerDefaults).spin(element);
  }

  // Page-specific modules
  var pages = {
    examples: {
      init: function() {
        log('examples.init');
      },
      table: {
        init: function() {
          log('examples.table.init');
        }
      },
      singeLayout: {
        init: function() {
          log('examples.singleLayout.init');
        }
      },
      gridLayout: {
        init: function() {
          log('examples.gridLayout.init');
        }
      },
      tabs: {
        init: function() {
          log('examples.tabs.init');
        }
      },
    }
  };

  // Initialise globally required features, and call the chain of inits required for pageModule.
  // Accepts:
  //   pageModule: String of the form `x.y.z`. Starting from the top (`x`), the `init` function on each module is called, if it exists.
  // Returns:
  //   undefined
  var init = function(pageModule) {
    var components = pageModule.split('/'),
        parentModule = pages,
        modules = [],
        $main = $('.main');

    // Work our way down the module chain, top to bottom, calling `init` on each successive child, if it exists.
    $.each(components, function(index, component) {
      var current = parentModule[component];
      modules.push(current);
      parentModule = current;
      if (current !== undefined && current.init !== undefined) {
        current.init();
      }
    });

    // Find any elements requiring histograms from files and load them
    $main.find('.histogram').each(function(index, el) {
      var $el = $(el),
          file = $el.data('file'),
          histogram = $el.data('histogram');
      if (file && histogram) {
        appendSpinner(el);
        loadHistogramFromFileIntoContainer(histogram, file, $el);
      }
    });

    // Add datepicker to appropriate fields
    $main.find('.input-daterange').datepicker(settings.datepickerDefaults);
  };

  return {
    init: init,
    submitJob: submitJob,
    createTask: createTask,
    settings: settings
  };
})(jQuery);

$(function() {
  WebMonitor.settings.debug = true;
  // Away we go!
  WebMonitor.init(activePage);
});
<commit_msg>Expose WebMonitor.log.<commit_after>// For more information on the 'revealing module' pattern, see
//   http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript
var WebMonitor = (function($, undefined) {
  'use strict';

  var settings = {
    // Show `console.log` messages?
    debug: false,
    // Default job status polling timeout in milliseconds
    pollRate: 300,
    // Defaults for histogram drawing
    histogramDefaults: {
    },
    // See http://fgnass.github.io/spin.js/ for options and customisation
    spinnerDefaults: {
      lines: 12,
      length: 5,
      width: 2,
      radius: 5,
      trail: 50,
      shadow: false
    },
    // See http://eternicode.github.io/bootstrap-datepicker/
    datepickerDefaults: {
      format: 'dd/mm/yyyy',
      // This app doesn't now about the future
      endDate: '+0d',
      todayBtn: 'linked',
      // Always pop under the field
      orientation: 'top auto',
      autoclose: true,
      todayHighlight: true
    }
  };

  // Cross-browser compatible `console.log`. Only fires if settings.debug === true.
  // http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
  // Accepts:
  //   Any number of arguments of any type.
  // Returns:
  //   undefined
  var log = function() {
    log.history = log.history || [];
    log.history.push(arguments);
    if (window.console && settings.debug) {
      console.log(Array.prototype.slice.call(arguments));
    }
  };

  // Draw a histogram in the `container` using `options`.
  // Accepts:
  //   container: A jQuery object in which to draw the histogram
  //     If the jQuery object references multiple DOM nodes, the first is used
  //   data: An array of data points formatted for d3.chart.histogram
  //   options: Object of options passed to the plotting library
  //     Any present options override those in WebMonitor.settings.histogramDefaults
  // Returns:
  //   undefined
  var drawHistogram = function(container, data, options) {
    var opt = $.extend(true, {}, WebMonitor.settings.histogramDefaults, options);
    d3.select(container.get()[0]).append('svg')
      .attr('width', container.width())
      .attr('height', container.height())
      .chart('HistogramZoom')
      .xAxisLabel(opt.xAxis.title.text)
      .yAxisLabel(opt.yAxis.title.text)
      .draw(data);
  };

  // Display a histogram, described by `data`, in `container`.
  // Accepts:
  //   data: An object describing the histogram
  //   container: A jQuery object in which to draw the histogram
  // Returns:
  //   undefined
  var displayHistogram = function(data, container) {
    var name = data['name'],
        title = data['title'],
        binning = data['binning'],
        values = data['values'],
        uncertainties = data['uncertainties'],
        axisTitles = data['axis_titles'];
    var v, binCenter, uLow, uHigh;
    // We need to manipulate the values slightly for d3.chart.histogram
    // See the d3.chart.histogram documentation for the specifics
    var formattedData = [];
    for (var i = 0; i < values.length; i++) {
      var bins = binning[i];
      formattedData.push({
        x: bins[0],
        dx: bins[1],
        y: data['values'][i],
        xErr: uncertainties[i]
      });
    }
    var options = {
      title: {
        text: title
      },
      xAxis: {
        title: {
          text: axisTitles[0]
        }
      },
      yAxis: {
        title: {
          text: axisTitles[1]
        }
      },
    };
    // Remove the spinner
    container.find('.spinner').remove();
    // Draw the histogram in the container
    drawHistogram(container, formattedData, options);
  };

  // Fetches and draws the named `histogram`, residing in `file`, in to the `container`.
  // Accepts:
  //   histogram: String of the histogram's full path key name with in the file
  //   file: String of the file name
  //   container: jQuery element the histogram should be drawn in to. Any existing content will be replaced.
  var loadHistogramFromFileIntoContainer = function(histogram, file, container) {
      var task = createTask('get_key_from_file', {filename: file, key_name: histogram});
      task.done(function(job) {
          displayHistogram(job['result']['data']['key_data'], container);
      });
      task.fail(function(message) {
        var failMsg = '
There was a problem retrieving histogram '
          + '' + histogram + ''
          + ' from file '
          + '' + file + ''
          + '. Please contact the administrator.
'
          + message;
        displayFailure(container, failMsg);
      });
  };

  // Submit a job to the server
  // Accepts:
  //   taskName: Name of the task the job will run
  //   args: Object of arguments passed to the task as named arguments
  //   poll: Whether to poll the job until completion (default: true)
  //     The job is polled in intervals of WebMonitor.settings.pollRate until
  //     the job status is not `queued` or `started`.
  // Returns:
  //   jQuery.Deferred object which fires `resolve` on job completion and fires
  //     `reject` on either submission failure or job polling failure
  var submitJob = function(taskName, args, doPoll) {
    if (doPoll === undefined) {
      doPoll = true;
    }
    var jobRequest =  $.ajax('/jobs', {
      type: 'POST',
      contentType: 'application/json; charset=utf-8',
      dataType: 'json',
      data: JSON.stringify({task_name: taskName, args: args})
    });
    var jobPromise = $.Deferred();
    var poll = function(job) {
      var jobID = job['id'],
          jobStatus = job['status'];
      // Poll the job if it hasn't not completed, else fire `resolve`
      if (jobStatus === 'queued' || jobStatus === 'started') {
        setTimeout(function() {
          log('Polling job ID ' + jobID + ': ' + jobStatus);
          $.getJSON(job['uri'])
            .done(function(data, status) { poll(data['job']); })
            .fail(function(data, status) { jobPromise.reject(data, status); });
        }, settings.pollRate);
      } else {
        log('Job ' + jobID + ' completed: ' + jobStatus);
        jobPromise.resolve(job);
      }
    };
    jobRequest.done(function(data, status) {
      var job = data['job'];
      if (doPoll === true) {
        poll(job);
      }
    });
    // Fire `reject` if the submission fails
    jobRequest.fail(function(data, status) { jobPromise.reject(data, status); });
    return jobPromise;
  };

  // Create a task and submit a job for it to the queue
  //
  // Unlike submitJob, this method handles job failures by creating descriptive
  // HTML error messages.
  // This relies on the JSON response containing a `result` key which is the
  // task's return value, which itself contains a `success` key determining
  // whether the task completed successfully.
  // If `success` if false, the task's `message` key is retrieved.
  // Accepts:
  //   taskName: Name of the task the job will run
  //   args: Object of arguments passed to the task as named arguments
  // Returns:
  //   jQuery.Deferred object which fires `resolve` on job completion and fires
  //     `reject` on either submission failure, job polling failure, or task
  //     failure. On resolution, the JSON response object is passed, whereas
  //     on rejection a descriptive HTML error message is passed.
  var createTask = function(taskName, args) {
    // Create a polling job
    var jobPromise = submitJob(taskName, args, true);
    var taskPromise = $.Deferred();
    jobPromise.done(function(job) {
      // Did the job complete successfully or not?
      if (job['status'] === 'failed') {
        var message = '
The job completed unsuccessfully.
';
        taskPromise.reject(message);
      } else {
        // Did the task the job was running finish successfully or not?
        var result = job['result'];
        if (result['success'] === false) {
          var message = '
The task could not complete successfully. It returned the error message '
            + '' + result['message'] + '.'
            + '
';
          taskPromise.reject(message);
        } else {
          taskPromise.resolve(job);
        }
      }
    });
    jobPromise.fail(function(data, status) {
      var message;
      try {
        message = JSON.parse(data.responseText)['message'];
      } catch(e) {
        message = data.statusText;
      }
      message = '
The server responded with the error code '
        + '' + data.status + ''
        + ' and the message '
        + '' + message + '.'
        + '
';
      taskPromise.reject(message);
    });
    return taskPromise;
  };

  // Display msg inside container, styled as a red error box
  // Accepts:
  //   container: jQuery element to insert msg into
  //   msg: HTML message to display inside container
  var displayFailure = function(container, msg) {
    container.html('
' + msg + '
');
  };

  // Add a `Spinner` object to the `element`, using `settings.spinnerDefaults` as options.
  // Accepts:
  //   element: DOM element
  // Returns:
  //   Spinner object
  var appendSpinner = function(element) {
    return new Spinner(settings.spinnerDefaults).spin(element);
  }

  // Page-specific modules
  var pages = {
    examples: {
      init: function() {
        log('examples.init');
      },
      table: {
        init: function() {
          log('examples.table.init');
        }
      },
      singeLayout: {
        init: function() {
          log('examples.singleLayout.init');
        }
      },
      gridLayout: {
        init: function() {
          log('examples.gridLayout.init');
        }
      },
      tabs: {
        init: function() {
          log('examples.tabs.init');
        }
      },
    }
  };

  // Initialise globally required features, and call the chain of inits required for pageModule.
  // Accepts:
  //   pageModule: String of the form `x.y.z`. Starting from the top (`x`), the `init` function on each module is called, if it exists.
  // Returns:
  //   undefined
  var init = function(pageModule) {
    var components = pageModule.split('/'),
        parentModule = pages,
        modules = [],
        $main = $('.main');

    // Work our way down the module chain, top to bottom, calling `init` on each successive child, if it exists.
    $.each(components, function(index, component) {
      var current = parentModule[component];
      modules.push(current);
      parentModule = current;
      if (current !== undefined && current.init !== undefined) {
        current.init();
      }
    });

    // Find any elements requiring histograms from files and load them
    $main.find('.histogram').each(function(index, el) {
      var $el = $(el),
          file = $el.data('file'),
          histogram = $el.data('histogram');
      if (file && histogram) {
        appendSpinner(el);
        loadHistogramFromFileIntoContainer(histogram, file, $el);
      }
    });

    // Add datepicker to appropriate fields
    $main.find('.input-daterange').datepicker(settings.datepickerDefaults);
  };

  return {
    init: init,
    submitJob: submitJob,
    createTask: createTask,
    log: log,
    settings: settings
  };
})(jQuery);

$(function() {
  WebMonitor.settings.debug = true;
  // Away we go!
  WebMonitor.init(activePage);
});
<|endoftext|>


<commit_before>import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { StateDecorator, Store, State } from '@sambego/storybook-state';
import {
  boolean,
  text
} from '@storybook/addon-knobs';
import { dlsThemeSelector, classicThemeSelector } from '../../../../.storybook/theme-selectors';
import DateInput from './date.component';
import { OriginalTextbox } from '../textbox';
import getCommonTextboxStoryProps from '../textbox/textbox.stories';
import { notes, info, infoValidations } from './documentation';
import getDocGenInfo from '../../../utils/helpers/docgen-info';

DateInput.__docgenInfo = getDocGenInfo(
  require('./docgenInfo.json'),
  /date\.component(?!spec)/
);

OriginalTextbox.__docgenInfo = getDocGenInfo(
  require('../textbox/docgenInfo.json'),
  /textbox\.component(?!spec)/
);

const store = new Store(
  {
    value: ''
  }
);

const setValue = (ev) => {
  action('onChange')(ev);
  store.set({ value: ev.target.value });
};

function makeStory(name, themeSelector) {
  const component = () => {
    const autoFocus = boolean('autoFocus', true);
    const minDate = text('minDate', '');
    const maxDate = text('maxDate', '');

    return (
      <DateInput
        { ...getCommonTextboxStoryProps({ inputWidthEnabled: false }) }
        name='dateinput'
        autoFocus={ autoFocus }
        minDate={ minDate }
        maxDate={ maxDate }
        value={ store.get('value') }
        onChange={ setValue }
      />
    );
  };

  const metadata = {
    themeSelector,
    info: {
      text: info,
      propTables: [OriginalTextbox],
      propTablesExclude: [State],
      excludedPropTypes: ['children', 'leftChildren', 'inputIcon', 'placeholder', 'inputWidth']
    },
    notes: { markdown: notes }
  };

  return [name, component, metadata];
}

function makeValidationsStory(name, themeSelector) {
  const component = () => {
    return (
      <State store={ store }>
        <DateInput
          name='dateinput'
          placeholder={ text('placeholder') }
          validations={ [isNotFirstApr] }
          warnings={ [isNotSecondApr] }
          info={ [isNotThirdApr] }
          onChange={ setValue }
        />
      </State>
    );
  };

  const metadata = {
    themeSelector,
    info: {
      source: false,
      text: infoValidations,
      propTables: [OriginalTextbox],
      propTablesExclude: [State]
    }
  };

  return [name, component, metadata];
}

storiesOf('Experimental/Date Input', module)
  .addDecorator(StateDecorator(store))
  .add(...makeStory('default', dlsThemeSelector))
  .add(...makeStory('classic', classicThemeSelector))
  .add(...makeValidationsStory('validations', dlsThemeSelector))
  .add(...makeValidationsStory('validations classic', classicThemeSelector));

function isNotFirstApr(value) {
  return new Promise((resolve, reject) => {
    if (value !== '01/04/2019') {
      resolve();
    } else {
      reject(new Error('April 1st 2019 cannot be selected!'));
    }
  });
}

function isNotSecondApr(value) {
  return new Promise((resolve, reject) => {
    if (value !== '02/04/2019') {
      resolve();
    } else {
      reject(new Error('Selecting April 2nd 2019 is not recommended'));
    }
  });
}

function isNotThirdApr(value) {
  return new Promise((resolve, reject) => {
    if (value !== '03/04/2019') {
      resolve();
    } else {
      reject(new Error('You have selected April 3rd 2019'));
    }
  });
}
<commit_msg>refactor: updates story to support new event format for onBlur and onChange<commit_after>import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { StateDecorator, Store, State } from '@sambego/storybook-state';
import {
  boolean,
  text
} from '@storybook/addon-knobs';
import { dlsThemeSelector, classicThemeSelector } from '../../../../.storybook/theme-selectors';
import DateInput from './date.component';
import { OriginalTextbox } from '../textbox';
import getCommonTextboxStoryProps from '../textbox/textbox.stories';
import { notes, info, infoValidations } from './documentation';
import getDocGenInfo from '../../../utils/helpers/docgen-info';

DateInput.__docgenInfo = getDocGenInfo(
  require('./docgenInfo.json'),
  /date\.component(?!spec)/
);

OriginalTextbox.__docgenInfo = getDocGenInfo(
  require('../textbox/docgenInfo.json'),
  /textbox\.component(?!spec)/
);

const store = new Store(
  {
    value: ''
  }
);

const setValue = (ev) => {
  action('onChange')(ev);
  store.set({ value: ev.target.value.displayText });
};

function makeStory(name, themeSelector) {
  const component = () => {
    const autoFocus = boolean('autoFocus', true);
    const minDate = text('minDate', '');
    const maxDate = text('maxDate', '');

    return (
      <DateInput
        { ...getCommonTextboxStoryProps({ inputWidthEnabled: false }) }
        name='dateinput'
        autoFocus={ autoFocus }
        minDate={ minDate }
        maxDate={ maxDate }
        value={ store.get('value') }
        onChange={ setValue }
        onBlur={ ev => action('onBlur')(ev) }
      />
    );
  };

  const metadata = {
    themeSelector,
    info: {
      text: info,
      propTables: [OriginalTextbox],
      propTablesExclude: [State],
      excludedPropTypes: ['children', 'leftChildren', 'inputIcon', 'placeholder', 'inputWidth']
    },
    notes: { markdown: notes }
  };

  return [name, component, metadata];
}

function makeValidationsStory(name, themeSelector) {
  const component = () => {
    return (
      <State store={ store }>
        <DateInput
          name='dateinput'
          placeholder={ text('placeholder') }
          validations={ [isNotFirstApr] }
          warnings={ [isNotSecondApr] }
          info={ [isNotThirdApr] }
          onChange={ setValue }
        />
      </State>
    );
  };

  const metadata = {
    themeSelector,
    info: {
      source: false,
      text: infoValidations,
      propTables: [OriginalTextbox],
      propTablesExclude: [State]
    }
  };

  return [name, component, metadata];
}

storiesOf('Experimental/Date Input', module)
  .addDecorator(StateDecorator(store))
  .add(...makeStory('default', dlsThemeSelector))
  .add(...makeStory('classic', classicThemeSelector))
  .add(...makeValidationsStory('validations', dlsThemeSelector))
  .add(...makeValidationsStory('validations classic', classicThemeSelector));

function isNotFirstApr(value) {
  return new Promise((resolve, reject) => {
    if (value !== '01/04/2019') {
      resolve();
    } else {
      reject(new Error('April 1st 2019 cannot be selected!'));
    }
  });
}

function isNotSecondApr(value) {
  return new Promise((resolve, reject) => {
    if (value !== '02/04/2019') {
      resolve();
    } else {
      reject(new Error('Selecting April 2nd 2019 is not recommended'));
    }
  });
}

function isNotThirdApr(value) {
  return new Promise((resolve, reject) => {
    if (value !== '03/04/2019') {
      resolve();
    } else {
      reject(new Error('You have selected April 3rd 2019'));
    }
  });
}
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies
 */
import * as uuid from 'uuid';
import App from '../../../models/app';
import AuthSess from '../../../models/auth-session';

/**
 * @swagger
 * /auth/session/generate:
 *   post:
 *     summary: Generate a session
 *     parameters:
 *       -
 *         name: app_secret
 *         description: App Secret
 *         in: formData
 *         required: true
 *         type: string
 *
 *     responses:
 *       200:
 *         description: OK
 *         schema:
 *           type: object
 *           properties:
 *             token:
 *               type: string
 *               description: Session Token
 *             url:
 *               type: string
 *               description: Authentication form's URL
 *       default:
 *         description: Failed
 *         schema:
 *           $ref: "#/definitions/Error"
 */

/**
 * Generate a session
 *
 * @param {Object} params
 * @return {Promise<object>}
 */
module.exports = (params) =>
	new Promise(async (res, rej) =>
{
	// Get 'app_secret' parameter
	const appSecret = params.app_secret;
	if (appSecret == null) {
		return rej('app_secret is required');
	}

	// Lookup app
	const app = await App.findOne({
		secret: appSecret
	});

	if (app == null) {
		return rej('app not found');
	}

	// Generate token
	const token = uuid.v4();

	// Create session token document
	const doc = await AuthSess.insert({
		created_at: new Date(),
		app_id: app._id,
		token: token
	});

	// Response
	res({
		token: doc.token,
		url: `${config.auth_url}/${doc.token}`
	});
});
<commit_msg>[API] Fix bug<commit_after>'use strict';

/**
 * Module dependencies
 */
import * as uuid from 'uuid';
import App from '../../../models/app';
import AuthSess from '../../../models/auth-session';
import config from '../../../../conf';

/**
 * @swagger
 * /auth/session/generate:
 *   post:
 *     summary: Generate a session
 *     parameters:
 *       -
 *         name: app_secret
 *         description: App Secret
 *         in: formData
 *         required: true
 *         type: string
 *
 *     responses:
 *       200:
 *         description: OK
 *         schema:
 *           type: object
 *           properties:
 *             token:
 *               type: string
 *               description: Session Token
 *             url:
 *               type: string
 *               description: Authentication form's URL
 *       default:
 *         description: Failed
 *         schema:
 *           $ref: "#/definitions/Error"
 */

/**
 * Generate a session
 *
 * @param {Object} params
 * @return {Promise<object>}
 */
module.exports = (params) =>
	new Promise(async (res, rej) =>
{
	// Get 'app_secret' parameter
	const appSecret = params.app_secret;
	if (appSecret == null) {
		return rej('app_secret is required');
	}

	// Lookup app
	const app = await App.findOne({
		secret: appSecret
	});

	if (app == null) {
		return rej('app not found');
	}

	// Generate token
	const token = uuid.v4();

	// Create session token document
	const doc = await AuthSess.insert({
		created_at: new Date(),
		app_id: app._id,
		token: token
	});

	// Response
	res({
		token: doc.token,
		url: `${config.auth_url}/${doc.token}`
	});
});
<|endoftext|>


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

    var Element = require("./models/element");
    var View = require("./models/view");
    var FunctionHelper = require("./helpers/function-helper");

    var _singleton = null;

    var ViewModule = function(App, appData) {
        //Initialize events
        /*
            Array of event listeners. Adheres to the following format:

            [
                {
                    element,
                    event,
                    listener
                }
            ]
        */
        appData.eventListeners = [];

        var handleEventListeners = function(event) {
            var eventListener;

            for (var i = 0, length = appData.eventListeners.length; i < length; i++) {
                eventListener = appData.eventListeners[i];

                if (eventListener.event === "mutation" && event instanceof window.MutationRecord) {
                    if (eventListener.element === event.target ||
                        (event.type === "characterData" && eventListener.element === event.target.parentElement)) {
                        eventListener.listener.apply(undefined, [event]);
                    }
                }
                else if (eventListener.element === event.target && eventListener.event === event.type) {
                    eventListener.listener.apply(undefined, [event]);
                }
            }
        };

        var events = ["blur", "change", "click", "focus", "input", "keypress", "keyup", "mousedown", "mouseup",
        "mouseenter", "mouseleave", "mouseover", "mouseout", "pause", "play", "ratechange", "seeked", "volumechange"];

        for (var i  = 0, iLength = events.length; i < iLength; i++) {
            document.addEventListener(events[i], handleEventListeners);
        }

        //Monitor DOM for changes
        //NOTE: A polyfill (not provided) is required for this to work IE 9 and 10
        //NOTE: IE11 incorrectly reports characterData changes in child nodes as childList mutations
        var mutationObserver = new window[(window.MutationObserver ? "" : "WebKit") + "MutationObserver"](
            function(mutations) {

            mutations.forEach(function(mutation) {
                handleEventListeners(mutation);
            });
        });

        mutationObserver.observe(window.document.querySelector("body"), {
            attributes: true,
            characterData: true,
            childList: true,
            subtree: true
        });

        Element.prototype.addDataBinding = FunctionHelper.override(Element.prototype.addDataBinding,
            function(originalFunction, context, args) {

            originalFunction.apply(context, args);

            var instance = args[0];
            var objectProperty = args[1];
            var options = args[2];
            var elementProperties = (function(elementProperties) {
                if (typeof elementProperties === "undefined") {
                    return (typeof context.getElements()[0].value === "undefined" ? ["innerHTML"] : ["value"]);
                }
                else {
                    return elementProperties instanceof Array ? elementProperties : [elementProperties];
                }
            })(options ? options.elementProperties : undefined);
            var direction = args[2] && typeof options.direction !== "undefined" ?
                options.direction : Element.TWO_WAY_BINDING;

            if (direction === Element.ONE_WAY_BINDING) {
                return;
            }

            var events = ["change", "input"];

            var elements = context.getElements();
            var element, value;
            var backwardTransform = args[2] ? args[2].backwardTransform : null;

            for (var i = 0, iLength = elements.length; i < iLength; i++) {
                element = elements[i];

                //jshint -W083
                if (elementProperties.indexOf("value") !== -1) {
                    for (var j = 0, jLength = events.length; j < jLength; j++) {
                        appData.eventListeners.push({
                            element: element,
                            event: events[j],
                            listener: function() {
                                value = element.value;

                                if (backwardTransform) {
                                    value = backwardTransform(value);
                                }

                                instance.set(objectProperty, value);
                                ViewModule.refresh(instance);
                            }
                        });
                    }
                }
                else {
                    appData.eventListeners.push({
                        element: element,
                        event: "mutation",
                        listener: function(mutation) {
                            if (mutation.type === "attributes") {
                                if (elementProperties.indexOf(mutation.attributeName) !== -1) {
                                    if (mutation.attributeName.indexOf("data-") === 0) {
                                        value = element.dataset[mutation.attributeName.substring(5)];
                                    }
                                    else {
                                        value = element[mutation.attributeName];
                                    }

                                    if (backwardTransform) {
                                        value = backwardTransform(value);
                                    }

                                    instance.set(objectProperty, value);
                                    ViewModule.refresh(instance);
                                }
                            }
                            else if (mutation.type === "characterData" || mutation.type === "childList") {
                                if (elementProperties.indexOf("innerHTML") !== -1) {
                                    value = element.innerHTML;

                                    if (backwardTransform) {
                                        value = backwardTransform(value);
                                    }

                                    instance.set(objectProperty, value);
                                    ViewModule.refresh(instance);
                                }
                            }
                        }
                    });
                }
                //jshint +W083
            }
        });

        Element.prototype.removeDataBinding = FunctionHelper.override(Element.prototype.removeDataBinding,
            function(originalFunction, context, args) {

            originalFunction.apply(context, args);

            var options = args[2];
            var elementProperties = options ? options.elementProperties : undefined;
            var direction = options ? options.direction : undefined;

            if (direction === Element.ONE_WAY_BINDING) {
                return;
            }

            var events = ["change", "input"];

            var elements = context.getElements();
            var element, eventListener;

            for (var i = 0, iLength = elements.length; i < iLength; i++) {
                element = elements[i];

                //jshint -W083
                if ((typeof elementProperties === "undefined" && typeof context.getElements()[0].value !==
                    "undefined") || (typeof elementProperties !== "undefined" && elementProperties.indexOf("value") !==
                    -1)) {
                    for (var j = 0, jLength = events.length; j < jLength; j++) {
                        for (var k = 0, kLength = appData.eventListeners.length; k < kLength; k++) {
                            eventListener = appData.eventListeners[k];

                            if (eventListener.element === element && events.indexOf(eventListener.event) !== -1) {
                                appData.eventListeners.splice(k, 1);
                                k--;
                                kLength--;
                            }
                        }
                    }
                }
                else {
                    for (var l = 0, lLength = appData.eventListeners.length; l < lLength; l++) {
                        eventListener = appData.eventListeners[l];

                        if (eventListener.element === element && events.indexOf(eventListener.event) !== -1) {
                            appData.eventListeners.splice(l, 1);
                            l--;
                            lLength--;
                        }
                    }
                }
                //jshint +W083
            }
        });

        //Public instance members
        var ViewModule = {
            /*
                @function add

                Adds the specified view to the internal records.

                @param {object} view        The desired view
            */
            add: function(view) {
                //Ignore views which already exist in the internal records
                if (appData.views.indexOf(view) !== -1) {
                    return;
                }

                appData.views.push(view);
            },

            /*
                @function remove

                Removes the specified view to the internal records.

                @param {object} view        The desired view
            */
            remove: function(view) {
                var index = appData.views.indexOf(view);

                if (index !== -1) {
                    appData.views.splice(index, 1);
                }
            },

            /*
                @function has

                Checks whether the specified view exists in the internal records.

                @param {object} view        The desired view
            */
            has: function(view) {
                return appData.views.indexOf(view) !== -1;
            },

            /*
                @function create

                Creates a View instance and adds it to the internal records.

                @param [htmlElement[]|htmlElement|string] elements      The desired HTML element(s)
            */
            create: function(elements) {
                var view = new View(elements);

                appData.views.push(view);

                return view;
            },

            /*
                @function refresh

                Refreshes all views which are data bound to the specified model instance. Generally speaking, this is
                automatically called by AppCore.

                @param [{object}] instance      The desired model instance.
            */
            refresh: function(instance) {
                for (var i = 0, length = appData.views.length; i < length; i++) {
                    appData.views[i].refresh(instance);
                }
            },

            Element: (function() {
                return {
                    /*
                        @function create

                        Creates an Element instance and optionally adds it to the specified View.

                        @param [{HTMLElement[]|HTMLElement|string}] elements        The desired HTML element(s)
                        @param [View] view                                          The desired View
                    */
                    create: function(elements, view) {
                        var element = new Element(elements);

                        if (view instanceof View) {
                            view.addElement(element);
                        }

                        return element;
                    },

                    REVERSE_BINDING: Element.REVERSE_BINDING,
                    ONE_WAY_BINDING: Element.ONE_WAY_BINDING,
                    TWO_WAY_BINDING: Element.TWO_WAY_BINDING
                };
            })()
        };

        return ViewModule;
    };

    return (function() {
        if (_singleton === null || typeof _singleton === "undefined") {
            _singleton = ViewModule;
        }

        return _singleton;
    })();
});
<commit_msg>Core.View: added mapping of Core.View.View.<commit_after>define(function(require) {
    "use strict";

    var Element = require("./models/element");
    var View = require("./models/view");
    var FunctionHelper = require("./helpers/function-helper");

    var _singleton = null;

    var ViewModule = function(App, appData) {
        //Initialize events
        /*
            Array of event listeners. Adheres to the following format:

            [
                {
                    element,
                    event,
                    listener
                }
            ]
        */
        appData.eventListeners = [];

        var handleEventListeners = function(event) {
            var eventListener;

            for (var i = 0, length = appData.eventListeners.length; i < length; i++) {
                eventListener = appData.eventListeners[i];

                if (eventListener.event === "mutation" && event instanceof window.MutationRecord) {
                    if (eventListener.element === event.target ||
                        (event.type === "characterData" && eventListener.element === event.target.parentElement)) {
                        eventListener.listener.apply(undefined, [event]);
                    }
                }
                else if (eventListener.element === event.target && eventListener.event === event.type) {
                    eventListener.listener.apply(undefined, [event]);
                }
            }
        };

        var events = ["blur", "change", "click", "focus", "input", "keypress", "keyup", "mousedown", "mouseup",
        "mouseenter", "mouseleave", "mouseover", "mouseout", "pause", "play", "ratechange", "seeked", "volumechange"];

        for (var i  = 0, iLength = events.length; i < iLength; i++) {
            document.addEventListener(events[i], handleEventListeners);
        }

        //Monitor DOM for changes
        //NOTE: A polyfill (not provided) is required for this to work IE 9 and 10
        //NOTE: IE11 incorrectly reports characterData changes in child nodes as childList mutations
        var mutationObserver = new window[(window.MutationObserver ? "" : "WebKit") + "MutationObserver"](
            function(mutations) {

            mutations.forEach(function(mutation) {
                handleEventListeners(mutation);
            });
        });

        mutationObserver.observe(window.document.querySelector("body"), {
            attributes: true,
            characterData: true,
            childList: true,
            subtree: true
        });

        Element.prototype.addDataBinding = FunctionHelper.override(Element.prototype.addDataBinding,
            function(originalFunction, context, args) {

            originalFunction.apply(context, args);

            var instance = args[0];
            var objectProperty = args[1];
            var options = args[2];
            var elementProperties = (function(elementProperties) {
                if (typeof elementProperties === "undefined") {
                    return (typeof context.getElements()[0].value === "undefined" ? ["innerHTML"] : ["value"]);
                }
                else {
                    return elementProperties instanceof Array ? elementProperties : [elementProperties];
                }
            })(options ? options.elementProperties : undefined);
            var direction = args[2] && typeof options.direction !== "undefined" ?
                options.direction : Element.TWO_WAY_BINDING;

            if (direction === Element.ONE_WAY_BINDING) {
                return;
            }

            var events = ["change", "input"];

            var elements = context.getElements();
            var element, value;
            var backwardTransform = args[2] ? args[2].backwardTransform : null;

            for (var i = 0, iLength = elements.length; i < iLength; i++) {
                element = elements[i];

                //jshint -W083
                if (elementProperties.indexOf("value") !== -1) {
                    for (var j = 0, jLength = events.length; j < jLength; j++) {
                        appData.eventListeners.push({
                            element: element,
                            event: events[j],
                            listener: function() {
                                value = element.value;

                                if (backwardTransform) {
                                    value = backwardTransform(value);
                                }

                                instance.set(objectProperty, value);
                                ViewModule.refresh(instance);
                            }
                        });
                    }
                }
                else {
                    appData.eventListeners.push({
                        element: element,
                        event: "mutation",
                        listener: function(mutation) {
                            if (mutation.type === "attributes") {
                                if (elementProperties.indexOf(mutation.attributeName) !== -1) {
                                    if (mutation.attributeName.indexOf("data-") === 0) {
                                        value = element.dataset[mutation.attributeName.substring(5)];
                                    }
                                    else {
                                        value = element[mutation.attributeName];
                                    }

                                    if (backwardTransform) {
                                        value = backwardTransform(value);
                                    }

                                    instance.set(objectProperty, value);
                                    ViewModule.refresh(instance);
                                }
                            }
                            else if (mutation.type === "characterData" || mutation.type === "childList") {
                                if (elementProperties.indexOf("innerHTML") !== -1) {
                                    value = element.innerHTML;

                                    if (backwardTransform) {
                                        value = backwardTransform(value);
                                    }

                                    instance.set(objectProperty, value);
                                    ViewModule.refresh(instance);
                                }
                            }
                        }
                    });
                }
                //jshint +W083
            }
        });

        Element.prototype.removeDataBinding = FunctionHelper.override(Element.prototype.removeDataBinding,
            function(originalFunction, context, args) {

            originalFunction.apply(context, args);

            var options = args[2];
            var elementProperties = options ? options.elementProperties : undefined;
            var direction = options ? options.direction : undefined;

            if (direction === Element.ONE_WAY_BINDING) {
                return;
            }

            var events = ["change", "input"];

            var elements = context.getElements();
            var element, eventListener;

            for (var i = 0, iLength = elements.length; i < iLength; i++) {
                element = elements[i];

                //jshint -W083
                if ((typeof elementProperties === "undefined" && typeof context.getElements()[0].value !==
                    "undefined") || (typeof elementProperties !== "undefined" && elementProperties.indexOf("value") !==
                    -1)) {
                    for (var j = 0, jLength = events.length; j < jLength; j++) {
                        for (var k = 0, kLength = appData.eventListeners.length; k < kLength; k++) {
                            eventListener = appData.eventListeners[k];

                            if (eventListener.element === element && events.indexOf(eventListener.event) !== -1) {
                                appData.eventListeners.splice(k, 1);
                                k--;
                                kLength--;
                            }
                        }
                    }
                }
                else {
                    for (var l = 0, lLength = appData.eventListeners.length; l < lLength; l++) {
                        eventListener = appData.eventListeners[l];

                        if (eventListener.element === element && events.indexOf(eventListener.event) !== -1) {
                            appData.eventListeners.splice(l, 1);
                            l--;
                            lLength--;
                        }
                    }
                }
                //jshint +W083
            }
        });

        //Public instance members
        var ViewModule = {
            /*
                @function add

                Adds the specified view to the internal records.

                @param {object} view        The desired view
            */
            add: function(view) {
                //Ignore views which already exist in the internal records
                if (appData.views.indexOf(view) !== -1) {
                    return;
                }

                appData.views.push(view);
            },

            /*
                @function remove

                Removes the specified view to the internal records.

                @param {object} view        The desired view
            */
            remove: function(view) {
                var index = appData.views.indexOf(view);

                if (index !== -1) {
                    appData.views.splice(index, 1);
                }
            },

            /*
                @function has

                Checks whether the specified view exists in the internal records.

                @param {object} view        The desired view
            */
            has: function(view) {
                return appData.views.indexOf(view) !== -1;
            },

            /*
                @function create

                Creates a View instance and adds it to the internal records.

                @param [htmlElement[]|htmlElement|string] elements      The desired HTML element(s)
            */
            create: function(elements) {
                var view = new View(elements);

                appData.views.push(view);

                return view;
            },

            /*
                @function refresh

                Refreshes all views which are data bound to the specified model instance. Generally speaking, this is
                automatically called by AppCore.

                @param [{object}] instance      The desired model instance.
            */
            refresh: function(instance) {
                for (var i = 0, length = appData.views.length; i < length; i++) {
                    appData.views[i].refresh(instance);
                }
            },

            Element: (function() {
                return {
                    /*
                        @function create

                        Creates an Element instance and optionally adds it to the specified View.

                        @param [{HTMLElement[]|HTMLElement|string}] elements        The desired HTML element(s)
                        @param [View] view                                          The desired View
                    */
                    create: function(elements, view) {
                        var element = new Element(elements);

                        if (view instanceof View) {
                            view.addElement(element);
                        }

                        return element;
                    },

                    REVERSE_BINDING: Element.REVERSE_BINDING,
                    ONE_WAY_BINDING: Element.ONE_WAY_BINDING,
                    TWO_WAY_BINDING: Element.TWO_WAY_BINDING
                };
            })(),

            View: View
        };

        return ViewModule;
    };

    return (function() {
        if (_singleton === null || typeof _singleton === "undefined") {
            _singleton = ViewModule;
        }

        return _singleton;
    })();
});
<|endoftext|>


<commit_before>import { createSelector } from 'reselect';

const getConstants = state => state.constants.constants;

const getEligibilityDetails = state => state.eligibility;

const getRequiredAttributes = (state, props) => {
  const { type, bah, dodBah, country } = props.institution;
  return {
    type: type && type.toLowerCase(),
    bah,
    dodBah,
    country: country && country.toLowerCase(),
  };
};

export function getDerivedAttributes(constant, eligibility, institution) {
  const your = eligibility;
  const its = institution;
  const chapter = Number(your.giBillChapter);
  let monthlyRate;

  const serviceDischarge = your.cumulativeService === 'service discharge';
  const purpleHeart = your.cumulativeService === 'purple heart';

  // VRE and post-9/11 eligibility
  const vre911Eligible = chapter === 31 && your.eligForPostGiBill === 'yes';

  // VRE-without-post-911 eligibility
  const onlyVRE = chapter === 31 && your.eligForPostGiBill === 'no';

  // Determines benefits tier
  const tier =
    vre911Eligible || serviceDischarge || purpleHeart
      ? 1
      : Number(your.cumulativeService);

  const isFlightOrCorrespondence =
    its.type === 'flight' || its.type === 'correspondence';

  const oldGiBill = chapter === 30 || chapter === 1606 || chapter === 35;

  // Determines whether monthly benefit can only be spent on tuition/fees
  const activeDutyThirty =
    your.militaryStatus === 'active duty' && chapter === 30;
  const correspondenceOrFlightUnderOldGiBill =
    (its.type === 'correspondence' || its.type === 'flight') &&
    oldGiBill === true;
  const onlyTuitionFees =
    activeDutyThirty || correspondenceOrFlightUnderOldGiBill;

  // The monthly benefit rate for non-chapter 33 benefits
  const isOJT = its.type === 'ojt';
  const isFlight = its.type === 'flight';
  const n = Number(your.numberOfDependents);
  const OJT = isOJT ? 'OJT' : '';
  switch (chapter) {
    case 30:
      if (your.enlistmentService === '3') {
        monthlyRate = isOJT
          ? constant.MGIB3YRRATE * 0.75
          : constant.MGIB3YRRATE;
      } else if (your.enlistmentService === '2') {
        monthlyRate = isOJT
          ? constant.MGIB2YRRATE * 0.75
          : constant.MGIB2YRRATE;
      }
      break;
    case 1606:
      monthlyRate = constant.SRRATE;
      if (isOJT) {
        monthlyRate *= 0.75;
      }
      break;
    case 35:
      if (isOJT) {
        monthlyRate = constant.DEARATEOJT;
      } else if (isFlight) {
        monthlyRate = 0;
      } else {
        monthlyRate = constant.DEARATEFULLTIME;
      }
      break;
    case 31:
      if (n <= 2) {
        monthlyRate = constant[`VRE${n}DEPRATE${OJT}`];
      } else {
        monthlyRate =
          constant[`VRE2DEPRATE${OJT}`] +
          (n - 2) * constant[`VREINCRATE${OJT}`];
      }
      break;
    default:
      monthlyRate = null;
  }

  const bah = its.dodBah && its.dodBah < its.bah ? its.dodBah : its.bah;

  const averageBah =
    constant.AVGDODBAH && constant.AVGDODBAH < constant.AVGVABAH
      ? constant.AVGDODBAH
      : constant.AVGVABAH;

  return {
    serviceDischarge,
    vre911Eligible,
    tier,
    onlyVRE,
    oldGiBill,
    onlyTuitionFees,
    monthlyRate,
    isFlightOrCorrespondence,
    bah,
    averageBah,
    chapter,
  };
}

function calculateTuition(constant, eligibility, institution, derived) {
  if (derived.oldGiBill) {
    return { qualifier: 'per year', value: 0, ratedQualifier: '/ year' };
  }
  if (institution.type === 'ojt') {
    return { qualifier: null, value: 'N/A' };
  }
  if (derived.chapter === 31) {
    if (derived.isFlightOrCorrespondence) {
      return {
        qualifier: 'per year',
        value: 0,
        ratedQualifier: ' / year',
      };
    }
    return { qualifier: null, value: 'Full Cost' };
  }
  if (institution.type === 'flight') {
    return {
      qualifier: 'per year',
      ratedQualifier: ' / year',
      value: Math.round(constant.FLTTFCAP * derived.tier),
    };
  }
  if (institution.type === 'correspondence') {
    return {
      qualifier: 'per year',
      ratedQualifier: ' / year',
      value: Math.round(constant.CORRESPONDTFCAP * derived.tier),
    };
  }
  if (institution.type === 'public') {
    return {
      qualifier: '% of instate tuition',
      ratedQualifier: '% in-state',
      value: Math.round(100 * derived.tier),
    };
  }
  return {
    qualifier: 'per year',
    ratedQualifier: ' / year',
    value: Math.round(constant.TFCAP * derived.tier),
  };
}

function calculateHousing(constant, eligibility, institution, derived) {
  if (derived.chapter === 31 && derived.isFlightOrCorrespondence) {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: 0,
    };
  }
  if (derived.oldGiBill || derived.onlyVRE) {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: Math.round(derived.monthlyRate),
    };
  }
  if (eligibility.militaryStatus === 'active duty') {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: 0,
    };
  }
  if (
    eligibility.militaryStatus === 'spouse' &&
    eligibility.spouseActiveDuty === 'yes'
  ) {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: 0,
    };
  }
  if (derived.isFlightOrCorrespondence) {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: 0,
    };
  }
  if (eligibility.onlineClasses === 'yes') {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: Math.round((derived.tier * derived.averageBah) / 2),
    };
  }
  if (institution.country !== 'usa') {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: Math.round(derived.tier * derived.averageBah),
    };
  }
  return {
    qualifier: 'per month',
    ratedQualifier: ' / month',
    value: Math.round(derived.tier * derived.bah),
  };
}

function calculateBooks(constant, eligibility, institution, derived) {
  if (derived.oldGiBill || derived.isFlightOrCorrespondence) {
    return {
      qualifier: 'per year',
      ratedQualifier: ' / year',
      value: 0,
    };
  }
  if (derived.chapter === 31) {
    return { qualifier: null, ratedQualifier: null, value: 'Full Cost' };
  }
  return {
    qualifier: 'per year',
    ratedQualifier: ' / year',
    value: derived.tier * constant.BSCAP,
  };
}

export const estimatedBenefits = createSelector(
  [getConstants, getEligibilityDetails, getRequiredAttributes],
  (constant, eligibility, attribute) => {
    if (constant === undefined) return {};

    const derived = getDerivedAttributes(constant, eligibility, attribute);
    const tuition = calculateTuition(constant, eligibility, attribute, derived);
    const housing = calculateHousing(constant, eligibility, attribute, derived);
    const books = calculateBooks(constant, eligibility, attribute, derived);

    return {
      tuition,
      housing,
      books,
    };
  },
);
<commit_msg>Update housing rate on card for spouse/child chapter 35. (#21284)<commit_after>import { createSelector } from 'reselect';
import environment from 'platform/utilities/environment';

const getConstants = state => state.constants.constants;

const getEligibilityDetails = state => state.eligibility;

const getRequiredAttributes = (state, props) => {
  const { type, bah, dodBah, country } = props.institution;
  return {
    type: type && type.toLowerCase(),
    bah,
    dodBah,
    country: country && country.toLowerCase(),
  };
};

export function getDerivedAttributes(constant, eligibility, institution) {
  const your = eligibility;
  const its = institution;
  const chapter = Number(your.giBillChapter);
  let monthlyRate;

  const serviceDischarge = your.cumulativeService === 'service discharge';
  const purpleHeart = your.cumulativeService === 'purple heart';

  // VRE and post-9/11 eligibility
  const vre911Eligible = chapter === 31 && your.eligForPostGiBill === 'yes';

  // VRE-without-post-911 eligibility
  const onlyVRE = chapter === 31 && your.eligForPostGiBill === 'no';

  // Determines benefits tier
  const tier =
    vre911Eligible || serviceDischarge || purpleHeart
      ? 1
      : Number(your.cumulativeService);

  const isFlightOrCorrespondence =
    its.type === 'flight' || its.type === 'correspondence';

  const oldGiBill = chapter === 30 || chapter === 1606 || chapter === 35;

  // Determines whether monthly benefit can only be spent on tuition/fees
  const activeDutyThirty =
    your.militaryStatus === 'active duty' && chapter === 30;
  const correspondenceOrFlightUnderOldGiBill =
    (its.type === 'correspondence' || its.type === 'flight') &&
    oldGiBill === true;
  const onlyTuitionFees =
    activeDutyThirty || correspondenceOrFlightUnderOldGiBill;

  // The monthly benefit rate for non-chapter 33 benefits
  const isOJT = its.type === 'ojt';
  const isFlight = its.type === 'flight';
  const n = Number(your.numberOfDependents);
  const OJT = isOJT ? 'OJT' : '';
  switch (chapter) {
    case 30:
      if (your.enlistmentService === '3') {
        monthlyRate = isOJT
          ? constant.MGIB3YRRATE * 0.75
          : constant.MGIB3YRRATE;
      } else if (your.enlistmentService === '2') {
        monthlyRate = isOJT
          ? constant.MGIB2YRRATE * 0.75
          : constant.MGIB2YRRATE;
      }
      break;
    case 1606:
      monthlyRate = constant.SRRATE;
      if (isOJT) {
        monthlyRate *= 0.75;
      }
      break;
    case 35:
      if (isOJT) {
        monthlyRate = constant.DEARATEOJT;
      } else if (isFlight) {
        monthlyRate = 0;
      } else {
        monthlyRate = constant.DEARATEFULLTIME;
      }

      if (
        (your.militaryStatus === 'child' || your.militaryStatus === 'spouse') &&
        its.country === 'philippines' &&
        !environment.isProduction()
      ) {
        monthlyRate /= 2;
      }
      break;
    case 31:
      if (n <= 2) {
        monthlyRate = constant[`VRE${n}DEPRATE${OJT}`];
      } else {
        monthlyRate =
          constant[`VRE2DEPRATE${OJT}`] +
          (n - 2) * constant[`VREINCRATE${OJT}`];
      }
      break;
    default:
      monthlyRate = null;
  }

  const bah = its.dodBah && its.dodBah < its.bah ? its.dodBah : its.bah;

  const averageBah =
    constant.AVGDODBAH && constant.AVGDODBAH < constant.AVGVABAH
      ? constant.AVGDODBAH
      : constant.AVGVABAH;

  return {
    serviceDischarge,
    vre911Eligible,
    tier,
    onlyVRE,
    oldGiBill,
    onlyTuitionFees,
    monthlyRate,
    isFlightOrCorrespondence,
    bah,
    averageBah,
    chapter,
  };
}

function calculateTuition(constant, eligibility, institution, derived) {
  if (derived.oldGiBill) {
    return { qualifier: 'per year', value: 0, ratedQualifier: '/ year' };
  }
  if (institution.type === 'ojt') {
    return { qualifier: null, value: 'N/A' };
  }
  if (derived.chapter === 31) {
    if (derived.isFlightOrCorrespondence) {
      return {
        qualifier: 'per year',
        value: 0,
        ratedQualifier: ' / year',
      };
    }
    return { qualifier: null, value: 'Full Cost' };
  }
  if (institution.type === 'flight') {
    return {
      qualifier: 'per year',
      ratedQualifier: ' / year',
      value: Math.round(constant.FLTTFCAP * derived.tier),
    };
  }
  if (institution.type === 'correspondence') {
    return {
      qualifier: 'per year',
      ratedQualifier: ' / year',
      value: Math.round(constant.CORRESPONDTFCAP * derived.tier),
    };
  }
  if (institution.type === 'public') {
    return {
      qualifier: '% of instate tuition',
      ratedQualifier: '% in-state',
      value: Math.round(100 * derived.tier),
    };
  }
  return {
    qualifier: 'per year',
    ratedQualifier: ' / year',
    value: Math.round(constant.TFCAP * derived.tier),
  };
}

function calculateHousing(constant, eligibility, institution, derived) {
  if (derived.chapter === 31 && derived.isFlightOrCorrespondence) {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: 0,
    };
  }
  if (derived.oldGiBill || derived.onlyVRE) {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: Math.round(derived.monthlyRate),
    };
  }
  if (eligibility.militaryStatus === 'active duty') {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: 0,
    };
  }
  if (
    eligibility.militaryStatus === 'spouse' &&
    eligibility.spouseActiveDuty === 'yes'
  ) {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: 0,
    };
  }
  if (derived.isFlightOrCorrespondence) {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: 0,
    };
  }
  if (eligibility.onlineClasses === 'yes') {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: Math.round((derived.tier * derived.averageBah) / 2),
    };
  }
  if (institution.country !== 'usa') {
    return {
      qualifier: 'per month',
      ratedQualifier: ' / month',
      value: Math.round(derived.tier * derived.averageBah),
    };
  }
  return {
    qualifier: 'per month',
    ratedQualifier: ' / month',
    value: Math.round(derived.tier * derived.bah),
  };
}

function calculateBooks(constant, eligibility, institution, derived) {
  if (derived.oldGiBill || derived.isFlightOrCorrespondence) {
    return {
      qualifier: 'per year',
      ratedQualifier: ' / year',
      value: 0,
    };
  }
  if (derived.chapter === 31) {
    return { qualifier: null, ratedQualifier: null, value: 'Full Cost' };
  }
  return {
    qualifier: 'per year',
    ratedQualifier: ' / year',
    value: derived.tier * constant.BSCAP,
  };
}

export const estimatedBenefits = createSelector(
  [getConstants, getEligibilityDetails, getRequiredAttributes],
  (constant, eligibility, attribute) => {
    if (constant === undefined) return {};

    const derived = getDerivedAttributes(constant, eligibility, attribute);
    const tuition = calculateTuition(constant, eligibility, attribute, derived);
    const housing = calculateHousing(constant, eligibility, attribute, derived);
    const books = calculateBooks(constant, eligibility, attribute, derived);

    return {
      tuition,
      housing,
      books,
    };
  },
);
<|endoftext|>