<commit_before>"use strict";
var oneApiRoute = {
	"^\/[a-zA-Z0-9_\.\-]+$": {
		"type": "object",
		"properties": {
			"method": {
				"type": "string",
				"required": false,
				"enum": ["GET", "POST", "PUT", "DELETE", "DEL"]
			},
			"mw": {
				"type": "string",
				"required": false,
				"pattern": "^/[^/]+(/[^/]+)*$"
			},
			"imfv": {
				"required": false,
				"type": "object",
				"properties": {
					"commonFields": {
						"type": "array",
						"required": false,
						"items": {
							"type": "string"
						},
						"uniqueItems": true
					},
					"custom": {
						"oneOf": [
							{
								"type": "string",
								"required": false,
								"pattern": "^/[^/]+(/[^/]+)*$"
							},
							{
								"type": "object",
								"required": false,
								"properties": {
									"required": {"type": "boolean", "required": true},
									"source": {
										"type": "array",
										"minItems": 1,
										"items": {"type": "string"},
										"required": true
									},
									"validation": {
										"oneOf":[
											{
												"type": "object",
												"required": true,
												"additionalProperties": true
											},
											{
												"type": "string",
												"required": true
											}
										]
									}
								}
							}
						]
					}
				}
			},
			"_apiInfo": {
				"required": true,
				"type": "object",
				"properties": {
					"l": {"type": "string", "required": true},
					"group": {"type": "string", "required": true},
					"groupMain": {"type": "boolean"}
				}
			},
			"commonFields": {"type": "array", "minItems": 1, "items": {"type": "string"}},
			"additionalProperties": {
				"type": "object",
				"properties": {
					"required": {"type": "boolean", "required": true},
					"source": {
						"type": "array",
						"minItems": 1,
						"items": {"type": "string"},
						"required": true
					},
					"validation": {
						"oneOf":[
							{
								"type": "object",
								"required": true,
								"additionalProperties": true
							},
							{
								"type": "string",
								"required": true
							}
						]
					}
				}
			}
		}
	}
};

var apiRoute = {
	"oneOf":[
		{
			"type": "object",
			"required": true,
			"properties": {
				"commonFields": {
					"oneOf": [
						{
							"type": "string",
							"required": true,
							"pattern": "^/[^/]+(/[^/]+)*$"
						},
						{
							"type": "object",
							"additionalProperties": {
								"type": "object",
								"properties": {
									"required": {"type": "boolean", "required": true},
									"source": {
										"type": "array",
										"minItems": 1,
										"items": {"type": "string"},
										"required": true
									},
									"validation": {
										"oneOf":[
											{
												"type": "object",
												"required": true,
												"additionalProperties": true
											},
											{
												"type": "string",
												"required": true
											}
										]
									}
								}
							}
						}
					]
				},
				"patternProperties": {
					"oneOf": [
						oneApiRoute,
						{
							"type": "object",
							"required": true,
							"patternProperties": oneApiRoute
						}
					]
				}
			}
		},
		{
			"type": "string",
			"required": false
		}
	]
};

var config = {
	"oneOf": [
		{
			"type": "object",
			"required": true,
			"properties": {
				"type": {
					"type": "string",
					"enum": ["service"]
				},
				"dbs": {
					"type": "array",
					"required": false,
					"items": {
						"type": "object",
						"properties": {
							"prefix": {"type": "string"},
							"name": {"type": "string", "required": true},
							"multitenant": {"type": "boolean"}
						}
					},
					"minItems": 1,
					"uniqueItems": true
				},
				"serviceVersion": {"type": "string", "required": false},
				"serviceName": {"type": "string", "minLength": "3", "required": true, "pattern": /^[a-z0-9\-]+$/},
				"serviceGroup": {"type": "string", "minLength": "3", "required": false},
				"servicePort": {"type": "integer", "min": 4100, "required": true},
				"prerequisites": {"type": "object", "required": true},
				"requestTimeout": {"type": "integer", "min": 10},
				"requestTimeoutRenewal": {"type": "integer", "max": 10},
				"extKeyRequired": {"type": "boolean"},
				"session": {"type": "boolean"},
                "oauth": {"type": "boolean"},
                "urac": {"type": "boolean"},
                "urac_Profile": {"type": "boolean"},
                "urac_ACL": {"type": "boolean"},
                "provision_ACL": {"type": "boolean"},

				"swagger": {"type": "boolean"},
				"multitenant": {"type": "boolean"},
				"roaming": {"type": "boolean"},
				"awarenessEnv": {"type": "boolean"},
				"errors": {
					"oneOf":[
						{
							"type": "object",
							"required": false,
							"patternProperties": {
								"^[0-9]+$": {"type": "string", "required": true, "minLength": 5}
							}
						},
						{
							"type": "string",
							"required": false
						}
					]
				},
				"schema": apiRoute
			}
		},
		{
			"type": "object",
			"required": true,
			"properties": {
				"type": {
					"type": "string",
					"enum": ["daemon"]
				},
				"dbs": {
					"type": "array",
					"required": false,
					"items": {
						"type": "object",
						"properties": {
							"prefix": {"type": "string"},
							"name": {"type": "string", "required": true},
							"multitenant": {"type": "boolean"}
						}
					},
					"minItems": 1,
					"uniqueItems": true
				},
				"serviceVersion": {"type": "string", "required": false},
				"serviceName": {"type": "string", "minLength": "3", "required": true, "pattern": /^[a-z0-9\-]+$/},
				"serviceGroup": {"type": "string", "minLength": "3", "required": false},
				"servicePort": {"type": "integer", "min": 4100, "required": true},
				"prerequisites": {"type": "object", "required": true},
				"swagger": {"type": "boolean"},
				"errors": {
					"oneOf":[
						{
							"type": "object",
							"required": false,
							"patternProperties": {
								"^[0-9]+$": {"type": "string", "required": true, "minLength": 5}
							}
						},
						{
							"type": "string",
							"required": false
						}
					]
				},
				"schema": {
					"oneOf":[
						{
							"type": "object",
							"required": true,
							"properties": {
								"patternProperties": {
									"^\/[a-zA-Z0-9_\.\-]+$": {
										"type": "object",
										"properties": {
											"l": {"type": "string", "required": true},
											"mw": {
												"type": "string",
												"required": false,
												"pattern": "^/[^/]+(/[^/]+)*$"
											}
										}
									}
								}
							}
						},
						{
							"type": "string",
							"required": false
						}
					]
				}
			}
		}
	]
};

var versionNbr = "^(\\*|[0-9]+(\\.(\\*|[0-9]+))+|[0-9]+(\\.[0-9]+)+(\\-[a-z]+(\\.[0-9]+(\\.)*)*))$";
var pckg = {
	"type": "object",
	"required": true,
	"properties": {
		"name": {"type": "string", "required": true},
		"description": {"type": "string", "required": true},
		"version": {
			"type": "string",
			"required": true,
			"pattern": versionNbr
		},
		"author": {
			"type": "object",
			"required": true,
			"properties": {
				"name": {"type": "string", "required": true},
				"email": {"type": "string", "required": true, "format": "email"},
				"additionalProperties": true
			}
		},
		"repository": {
			"type": "object",
			"required": true,
			"properties": {
				"type": {"type": "string", "required": true},
				"url": {"type": "string", "required": true},
				"additionalProperties": true
			}
		},
		"license": {"type": "string", "required": true},
		"engines": {
			"type": "object",
			"required": true,
			"properties": {
				"node": {"type": "string", "required": true},
				"additionalProperties": true
			}
		},
		"scripts": {
			"type": "object",
			"required": false,
			"properties": {
				"test": {"type": "string", "required": true},
				"additionalProperties": true
			}
		},
		"devDependencies": {
			"type": "object",
			"required": false,
			"additionalProperties": {
				"type": "string",
				"required": true,
				"pattern": versionNbr
			}
		},
		"dependencies": {
			"type": "object",
			"required": true,
			"additionalProperties": {
				"type": "string",
				"required": true,
				"pattern": versionNbr
			}
		}

	}
};

var apiMethodSchema = {
	"type": "object",
	"additionalProperties": false,
	"patternProperties": {
		"^[_a-z\/][_a-zA-Z0-9\/:]*$": { //pattern to match an api route
			"type": "object",
			"required": true,
			"properties": {
				"_apiInfo": {
					"required": true,
					"type": "object",
					"additionalProperties": false,
					"properties": {
						"l": {"type": "string", "required": true},
						"group": {"type": "string", "required": true},
						"groupMain": {"type": "boolean"}
					}
				},
				"imfv": {
					"type": "object",
					"additionalProperties": false,
					"properties": {
						"commonFields": {
							"type": "array",
							"uniqueItems": true,
							"items": {"type": "string", "required": true}
						},
						"custom": {
							"type": "object",
							"additionalProperties": { "type": "object" }
						}
					}
				},
				"_authorization": {
					"type": "string",
					"required": false
				},
				"mw": {
					"type": "string",
					"required": false
				}
			},
			"additionalProperties": false
		}
	}
};

var contract = {
	"type": "object",
	"additionalProperties": false,
	"properties": {
		"commonFields": {
			"type": "object",
			"additionalProperties": { "type": "object" }
		},
		"get": apiMethodSchema,
		"put": apiMethodSchema,
		"post": apiMethodSchema,
		"del": apiMethodSchema,
		"delete": apiMethodSchema
	}
};

module.exports = {
	"config": config,
	"service": config.oneOf[0],
	"daemon": config.oneOf[1],
	"package": pckg,
	"contract": contract
};
<commit_msg>serviceVersion on activating a repo can be number or string<commit_after>"use strict";
var oneApiRoute = {
	"^\/[a-zA-Z0-9_\.\-]+$": {
		"type": "object",
		"properties": {
			"method": {
				"type": "string",
				"required": false,
				"enum": ["GET", "POST", "PUT", "DELETE", "DEL"]
			},
			"mw": {
				"type": "string",
				"required": false,
				"pattern": "^/[^/]+(/[^/]+)*$"
			},
			"imfv": {
				"required": false,
				"type": "object",
				"properties": {
					"commonFields": {
						"type": "array",
						"required": false,
						"items": {
							"type": "string"
						},
						"uniqueItems": true
					},
					"custom": {
						"oneOf": [
							{
								"type": "string",
								"required": false,
								"pattern": "^/[^/]+(/[^/]+)*$"
							},
							{
								"type": "object",
								"required": false,
								"properties": {
									"required": {"type": "boolean", "required": true},
									"source": {
										"type": "array",
										"minItems": 1,
										"items": {"type": "string"},
										"required": true
									},
									"validation": {
										"oneOf":[
											{
												"type": "object",
												"required": true,
												"additionalProperties": true
											},
											{
												"type": "string",
												"required": true
											}
										]
									}
								}
							}
						]
					}
				}
			},
			"_apiInfo": {
				"required": true,
				"type": "object",
				"properties": {
					"l": {"type": "string", "required": true},
					"group": {"type": "string", "required": true},
					"groupMain": {"type": "boolean"}
				}
			},
			"commonFields": {"type": "array", "minItems": 1, "items": {"type": "string"}},
			"additionalProperties": {
				"type": "object",
				"properties": {
					"required": {"type": "boolean", "required": true},
					"source": {
						"type": "array",
						"minItems": 1,
						"items": {"type": "string"},
						"required": true
					},
					"validation": {
						"oneOf":[
							{
								"type": "object",
								"required": true,
								"additionalProperties": true
							},
							{
								"type": "string",
								"required": true
							}
						]
					}
				}
			}
		}
	}
};

var apiRoute = {
	"oneOf":[
		{
			"type": "object",
			"required": true,
			"properties": {
				"commonFields": {
					"oneOf": [
						{
							"type": "string",
							"required": true,
							"pattern": "^/[^/]+(/[^/]+)*$"
						},
						{
							"type": "object",
							"additionalProperties": {
								"type": "object",
								"properties": {
									"required": {"type": "boolean", "required": true},
									"source": {
										"type": "array",
										"minItems": 1,
										"items": {"type": "string"},
										"required": true
									},
									"validation": {
										"oneOf":[
											{
												"type": "object",
												"required": true,
												"additionalProperties": true
											},
											{
												"type": "string",
												"required": true
											}
										]
									}
								}
							}
						}
					]
				},
				"patternProperties": {
					"oneOf": [
						oneApiRoute,
						{
							"type": "object",
							"required": true,
							"patternProperties": oneApiRoute
						}
					]
				}
			}
		},
		{
			"type": "string",
			"required": false
		}
	]
};

var config = {
	"oneOf": [
		{
			"type": "object",
			"required": true,
			"properties": {
				"type": {
					"type": "string",
					"enum": ["service"]
				},
				"dbs": {
					"type": "array",
					"required": false,
					"items": {
						"type": "object",
						"properties": {
							"prefix": {"type": "string"},
							"name": {"type": "string", "required": true},
							"multitenant": {"type": "boolean"}
						}
					},
					"minItems": 1,
					"uniqueItems": true
				},
				"serviceVersion": {
                    "oneOf":[
                        {
                            "type": "number",
                            "required": false
                        },
                        {
                            "type": "string",
                            "required": false
                        }
                    ]
				},
				"serviceName": {"type": "string", "minLength": "3", "required": true, "pattern": /^[a-z0-9\-]+$/},
				"serviceGroup": {"type": "string", "minLength": "3", "required": false},
				"servicePort": {"type": "integer", "min": 4100, "required": true},
				"prerequisites": {"type": "object", "required": true},
				"requestTimeout": {"type": "integer", "min": 10},
				"requestTimeoutRenewal": {"type": "integer", "max": 10},
				"extKeyRequired": {"type": "boolean"},
				"session": {"type": "boolean"},
                "oauth": {"type": "boolean"},
                "urac": {"type": "boolean"},
                "urac_Profile": {"type": "boolean"},
                "urac_ACL": {"type": "boolean"},
                "provision_ACL": {"type": "boolean"},

				"swagger": {"type": "boolean"},
				"multitenant": {"type": "boolean"},
				"roaming": {"type": "boolean"},
				"awarenessEnv": {"type": "boolean"},
				"errors": {
					"oneOf":[
						{
							"type": "object",
							"required": false,
							"patternProperties": {
								"^[0-9]+$": {"type": "string", "required": true, "minLength": 5}
							}
						},
						{
							"type": "string",
							"required": false
						}
					]
				},
				"schema": apiRoute
			}
		},
		{
			"type": "object",
			"required": true,
			"properties": {
				"type": {
					"type": "string",
					"enum": ["daemon"]
				},
				"dbs": {
					"type": "array",
					"required": false,
					"items": {
						"type": "object",
						"properties": {
							"prefix": {"type": "string"},
							"name": {"type": "string", "required": true},
							"multitenant": {"type": "boolean"}
						}
					},
					"minItems": 1,
					"uniqueItems": true
				},
				"serviceVersion": {
                    "oneOf":[
                        {
                            "type": "number",
                            "required": false
                        },
                        {
                            "type": "string",
                            "required": false
                        }
                    ]
				},
				"serviceName": {"type": "string", "minLength": "3", "required": true, "pattern": /^[a-z0-9\-]+$/},
				"serviceGroup": {"type": "string", "minLength": "3", "required": false},
				"servicePort": {"type": "integer", "min": 4100, "required": true},
				"prerequisites": {"type": "object", "required": true},
				"swagger": {"type": "boolean"},
				"errors": {
					"oneOf":[
						{
							"type": "object",
							"required": false,
							"patternProperties": {
								"^[0-9]+$": {"type": "string", "required": true, "minLength": 5}
							}
						},
						{
							"type": "string",
							"required": false
						}
					]
				},
				"schema": {
					"oneOf":[
						{
							"type": "object",
							"required": true,
							"properties": {
								"patternProperties": {
									"^\/[a-zA-Z0-9_\.\-]+$": {
										"type": "object",
										"properties": {
											"l": {"type": "string", "required": true},
											"mw": {
												"type": "string",
												"required": false,
												"pattern": "^/[^/]+(/[^/]+)*$"
											}
										}
									}
								}
							}
						},
						{
							"type": "string",
							"required": false
						}
					]
				}
			}
		}
	]
};

var versionNbr = "^(\\*|[0-9]+(\\.(\\*|[0-9]+))+|[0-9]+(\\.[0-9]+)+(\\-[a-z]+(\\.[0-9]+(\\.)*)*))$";
var pckg = {
	"type": "object",
	"required": true,
	"properties": {
		"name": {"type": "string", "required": true},
		"description": {"type": "string", "required": true},
		"version": {
			"type": "string",
			"required": true,
			"pattern": versionNbr
		},
		"author": {
			"type": "object",
			"required": true,
			"properties": {
				"name": {"type": "string", "required": true},
				"email": {"type": "string", "required": true, "format": "email"},
				"additionalProperties": true
			}
		},
		"repository": {
			"type": "object",
			"required": true,
			"properties": {
				"type": {"type": "string", "required": true},
				"url": {"type": "string", "required": true},
				"additionalProperties": true
			}
		},
		"license": {"type": "string", "required": true},
		"engines": {
			"type": "object",
			"required": true,
			"properties": {
				"node": {"type": "string", "required": true},
				"additionalProperties": true
			}
		},
		"scripts": {
			"type": "object",
			"required": false,
			"properties": {
				"test": {"type": "string", "required": true},
				"additionalProperties": true
			}
		},
		"devDependencies": {
			"type": "object",
			"required": false,
			"additionalProperties": {
				"type": "string",
				"required": true,
				"pattern": versionNbr
			}
		},
		"dependencies": {
			"type": "object",
			"required": true,
			"additionalProperties": {
				"type": "string",
				"required": true,
				"pattern": versionNbr
			}
		}

	}
};

var apiMethodSchema = {
	"type": "object",
	"additionalProperties": false,
	"patternProperties": {
		"^[_a-z\/][_a-zA-Z0-9\/:]*$": { //pattern to match an api route
			"type": "object",
			"required": true,
			"properties": {
				"_apiInfo": {
					"required": true,
					"type": "object",
					"additionalProperties": false,
					"properties": {
						"l": {"type": "string", "required": true},
						"group": {"type": "string", "required": true},
						"groupMain": {"type": "boolean"}
					}
				},
				"imfv": {
					"type": "object",
					"additionalProperties": false,
					"properties": {
						"commonFields": {
							"type": "array",
							"uniqueItems": true,
							"items": {"type": "string", "required": true}
						},
						"custom": {
							"type": "object",
							"additionalProperties": { "type": "object" }
						}
					}
				},
				"_authorization": {
					"type": "string",
					"required": false
				},
				"mw": {
					"type": "string",
					"required": false
				}
			},
			"additionalProperties": false
		}
	}
};

var contract = {
	"type": "object",
	"additionalProperties": false,
	"properties": {
		"commonFields": {
			"type": "object",
			"additionalProperties": { "type": "object" }
		},
		"get": apiMethodSchema,
		"put": apiMethodSchema,
		"post": apiMethodSchema,
		"del": apiMethodSchema,
		"delete": apiMethodSchema
	}
};

module.exports = {
	"config": config,
	"service": config.oneOf[0],
	"daemon": config.oneOf[1],
	"package": pckg,
	"contract": contract
};
<|endoftext|>


<commit_before>
XMOT.namespace("XMOT.interaction.widgets");

/**
 *  This gizmo adds 3 small rectangles to the target object with which the
 *  rotation of the target can be controlled, constrained to single axes the
 *  rectangle present.
 *
 * @extends XMOT.interaction.widgets.OverlayWidget
 */
XMOT.interaction.widgets.RotateGizmo = new XMOT.Class(
    XMOT.interaction.widgets.OverlayWidget, {

    GeometryType: XMOT.interaction.geometry.RotateGizmo,

    /**
     *  @this {XMOT.interaction.widgets.RotateGizmo}
     *  @override
     *  @protected
     */
    onCreateBehavior: function()
    {
        this.behavior["xaxis"] = this._createRotater("x");
        this.behavior["yaxis"] = this._createRotater("y");
        this.behavior["zaxis"] = this._createRotater("z");
    },

    /**
     *  @this {XMOT.interaction.widgets.RotateGizmo}
     *  @private
     *
     *  @param {string} axis. "x", "y" or "z"
     */
    _createRotater: function(axis)
    {
        var geoId = axis + "axis";

        var eventDispatcher = new XMOT.util.EventDispatcher("mousedown", function(evt) {
            return (evt.button === XMOT.MOUSEBUTTON_LEFT);
        });

        var constraint = this._createRotationConstraint();

        var graphRootXfmable = XMOT.ClientMotionFactory.createTransformable(
            this.geometry.getRoot(), constraint
        );

        var pickGrps = [this.geometry.getGeo(geoId)];

        var rot = new XMOT.interaction.behaviors.Rotater(
            this.globalID(geoId), pickGrps, graphRootXfmable, undefined, eventDispatcher);
        rot.axisRestriction(axis);

        return rot;
    },

    /** Creates a rotation constraint, where the real target's rotation
     *  is updated with the given
     *
     *  @this {XMOT.interaction.widgets.RotateGizmo}
     *  @private
     *
     *  @return {XMOT.Constraint}
     */
    _createRotationConstraint: function() {

        var target = this.mirror().target();

        return {
            constrainRotation: function(newRotation, opts){
                if(!opts.transformable)
                    throw new Error("Constraint: no transformable given.");

                target.setOrientation(newRotation);

                return true;
            },
            constrainScaling: function(newScale, opts){
                return true;
            },

            constrainTranslation: function(newTranslation, opts) {
                return true;
            }
        };
    }
});
<commit_msg>interaction-rotategizmo: applied concept of reflecting constraint<commit_after>
XMOT.namespace("XMOT.interaction.widgets");

/**
 *  This gizmo adds 3 small rectangles to the target object with which the
 *  rotation of the target can be controlled, constrained to single axes the
 *  rectangle present.
 *
 * @extends XMOT.interaction.widgets.OverlayWidget
 */
XMOT.interaction.widgets.RotateGizmo = new XMOT.Class(
    XMOT.interaction.widgets.OverlayWidget, {

    GeometryType: XMOT.interaction.geometry.RotateGizmo,

    /**
     *  @this {XMOT.interaction.widgets.RotateGizmo}
     *  @override
     *  @protected
     */
    onCreateBehavior: function()
    {
        this.behavior["xaxis"] = this._createRotater("x");
        this.behavior["yaxis"] = this._createRotater("y");
        this.behavior["zaxis"] = this._createRotater("z");
    },

    /**
     *  @this {XMOT.interaction.widgets.RotateGizmo}
     *  @private
     *
     *  @param {string} axis. "x", "y" or "z"
     */
    _createRotater: function(axis)
    {
        var geoId = axis + "axis";

        var eventDispatcher = new XMOT.util.EventDispatcher("mousedown", function(evt) {
            return (evt.button === XMOT.MOUSEBUTTON_LEFT);
        });

        var constraint = this.createReflectingConstraint();
        var behaviorTarget = this.createBehaviorTarget(constraint);

        var pickGrps = [this.geometry.getGeo(geoId)];

        var rot = new XMOT.interaction.behaviors.Rotater(
            this.globalID(geoId), pickGrps, behaviorTarget, undefined, eventDispatcher);
        rot.axisRestriction(axis);

        return rot;
    }
});
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import ReactTooltip from 'react-tooltip';
import { connect } from 'react-redux';

import Icon from 'common/Icon';
import isLatestPatch from 'game/isLatestPatch';
import DiscordButton from 'interface/common/thirdpartybuttons/Discord';
import GitHubButton from 'interface/common/thirdpartybuttons/GitHub';
import makeAnalyzerUrl from 'interface/common/makeAnalyzerUrl';
import { ignoreSpecNotSupportedWarning } from 'interface/actions/specNotSupported';
import { getSpecsIgnoredNotSupportedWarning } from 'interface/selectors/skipSpecNotSupported';

import Background from './images/weirdnelf.png';

class SupportChecker extends React.PureComponent {
  static propTypes = {
    children: PropTypes.node.isRequired,
    config: PropTypes.shape({
      patchCompatibility: PropTypes.string.isRequired,
      spec: PropTypes.shape({
        id: PropTypes.number.isRequired,
      }).isRequired,
    }).isRequired,
    report: PropTypes.object.isRequired,
    fight: PropTypes.shape({
      id: PropTypes.number.isRequired,
    }).isRequired,
    player: PropTypes.shape({
      name: PropTypes.string.isRequired,
    }).isRequired,
    ignoreSpecNotSupportedWarning: PropTypes.func.isRequired,
    ignored: PropTypes.array.isRequired,
  };

  constructor() {
    super();
    this.handleClickContinue = this.handleClickContinue.bind(this);
  }
  componentDidMount() {
    ReactTooltip.rebuild();
  }
  componentDidUpdate() {
    ReactTooltip.hide();
  }

  handleClickContinue() {
    // I chose on purpose not to store this in a cookie since I don't want this to be forgotten. It should not be a big deal if this happens every time the page is loaded, so long as it isn't shown every fight.
    this.props.ignoreSpecNotSupportedWarning(this.props.config.spec.id);
  }

  get continue() {
    return this.props.ignored.includes(this.props.config.spec.id);
  }

  render() {
    const { children, config, report, fight, player } = this.props;

    const spec = config.spec;

    if (!this.continue && !isLatestPatch(config.patchCompatibility)) {
      return (

              <Link to={makeAnalyzerUrl(report, fight.id)} data-tip="Back to player selection">

              </Link>

            {player.name} - {spec.specName} {spec.className}

Sorry, this spec is currently not supported

                  This spec hasn't been updated for the latest patch so we're afraid it might be outdated and misleading. We recommend reading the  Wowhead and Icy Veins guides to gain more knowledge about your spec and use this to analyze yourself. You can try asking for help in a class Discord, but they're likely too busy memeing to do thorough analysis for you.

                  We have no ETA for support for {spec.specName} {spec.className}. We need volunteer contributors to maintain specs, and seeing as {spec.specName} {spec.className} is out of date, it's likely nobody is currently maintaining it. If you are interested or know someone who might be interested helping people help themselves, check out GitHub or Discord for more information.

                    <GitHubButton />{' '}
                    <DiscordButton />

                  <Link
                    to={makeAnalyzerUrl(report, fight.id, player.id)}
                    onClick={this.handleClickContinue}
                    style={{ fontSize: '1.1em' }}
                    data-tip="Khadgar approves your bravery"
                  >
                    <Icon icon="quest_khadgar" /> Continue anyway
                  </Link>

      );
    }

    return children;
  }
}

const mapStateToProps = state => ({
  ignored: getSpecsIgnoredNotSupportedWarning(state),
});
export default connect(mapStateToProps, {
  ignoreSpecNotSupportedWarning,
})(SupportChecker);
<commit_msg>Be nice<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import ReactTooltip from 'react-tooltip';
import { connect } from 'react-redux';

import Icon from 'common/Icon';
import isLatestPatch from 'game/isLatestPatch';
import DiscordButton from 'interface/common/thirdpartybuttons/Discord';
import GitHubButton from 'interface/common/thirdpartybuttons/GitHub';
import makeAnalyzerUrl from 'interface/common/makeAnalyzerUrl';
import { ignoreSpecNotSupportedWarning } from 'interface/actions/specNotSupported';
import { getSpecsIgnoredNotSupportedWarning } from 'interface/selectors/skipSpecNotSupported';

import Background from './images/weirdnelf.png';

class SupportChecker extends React.PureComponent {
  static propTypes = {
    children: PropTypes.node.isRequired,
    config: PropTypes.shape({
      patchCompatibility: PropTypes.string.isRequired,
      spec: PropTypes.shape({
        id: PropTypes.number.isRequired,
      }).isRequired,
    }).isRequired,
    report: PropTypes.object.isRequired,
    fight: PropTypes.shape({
      id: PropTypes.number.isRequired,
    }).isRequired,
    player: PropTypes.shape({
      name: PropTypes.string.isRequired,
    }).isRequired,
    ignoreSpecNotSupportedWarning: PropTypes.func.isRequired,
    ignored: PropTypes.array.isRequired,
  };

  constructor() {
    super();
    this.handleClickContinue = this.handleClickContinue.bind(this);
  }
  componentDidMount() {
    ReactTooltip.rebuild();
  }
  componentDidUpdate() {
    ReactTooltip.hide();
  }

  handleClickContinue() {
    // I chose on purpose not to store this in a cookie since I don't want this to be forgotten. It should not be a big deal if this happens every time the page is loaded, so long as it isn't shown every fight.
    this.props.ignoreSpecNotSupportedWarning(this.props.config.spec.id);
  }

  get continue() {
    return this.props.ignored.includes(this.props.config.spec.id);
  }

  render() {
    const { children, config, report, fight, player } = this.props;

    const spec = config.spec;

    if (!this.continue && !isLatestPatch(config.patchCompatibility)) {
      return (

              <Link to={makeAnalyzerUrl(report, fight.id)} data-tip="Back to player selection">

              </Link>

            {player.name} - {spec.specName} {spec.className}

Sorry, this spec is currently not supported

                  This spec hasn't been updated for the latest patch so we're afraid it might be outdated and misleading. We recommend reading the  Wowhead and Icy Veins guides to gain more knowledge about your spec and use this to analyze yourself. You can try asking for help in a class Discord.

                  We have no ETA for support for {spec.specName} {spec.className}. We need volunteer contributors to maintain specs, and seeing as {spec.specName} {spec.className} is out of date, it's likely nobody is currently maintaining it. If you are interested or know someone who might be interested helping people help themselves, check out GitHub or Discord for more information.

                    <GitHubButton />{' '}
                    <DiscordButton />

                  <Link
                    to={makeAnalyzerUrl(report, fight.id, player.id)}
                    onClick={this.handleClickContinue}
                    style={{ fontSize: '1.1em' }}
                    data-tip="Khadgar approves your bravery"
                  >
                    <Icon icon="quest_khadgar" /> Continue anyway
                  </Link>

      );
    }

    return children;
  }
}

const mapStateToProps = state => ({
  ignored: getSpecsIgnoredNotSupportedWarning(state),
});
export default connect(mapStateToProps, {
  ignoreSpecNotSupportedWarning,
})(SupportChecker);
<|endoftext|>


<commit_before><commit_msg>cleanup unused<commit_after><|endoftext|>


<commit_before>/**
 * @module parse/patterns
 */
import { resourceId, resourceKey } from '../utils/object';
import { readFiles, readFileTree } from '../utils/parse';
import { titleCase } from '../utils/shared';
import path from 'path';

import DrizzleError from '../utils/error';

const isPattern = obj => obj.hasOwnProperty('path');
const collectionPath = itms => path.dirname(itms[Object.keys(itms).pop()].path);
const collectionKey = itms => collectionPath(itms).split(path.sep).pop();

function checkNamespaceCollision (key, obj, id, options = {}) {
  if (Array.isArray(key)) {
    return key.map(oneKey =>
      checkNamespaceCollision(oneKey, obj, id, options)
    );
  }
  if (obj && obj.hasOwnProperty(key)) {
    DrizzleError.error(new DrizzleError(`'${id}' has local '${key}'
property set. This is a Drizzle reserved property and will be
overwritten. See docs.`, DrizzleError.LEVELS.WARN), options.debug);
  }
}

/**
 * Should this pattern be hidden per collection or pattern metadata?
 * @param {Object} collection   Collection obj
 * @param {Object} pattern      Pattern obj
 * @param {String} patternKey
 * @return {Boolean}
 */
function isHidden (collection, pattern, patternKey) {
  return ((collection.hidden && collection.hidden.indexOf(patternKey) !== -1) ||
    (pattern.data && pattern.data.hidden));
}

/**
 * Is the obj a collection?
 * @param {Object} obj
 * @return {Boolean}
 */
function isCollection (obj) {
  if (isPattern(obj)) { return false; }
  return Object.keys(obj).some(childKey => isPattern(obj[childKey]));
}

/**
 * Construct a glob to look for collection metadata.
 * @param {Object} items  All the patterns
 * @return {String} glob
 */
function collectionGlob (items) {
  return path.join(collectionPath(items), 'collection.+(yml|yaml|json)');
}

/**
 * Do any of the patterns in this collection have ordering information in their
 * front matter?
 *
 * @param itms      Patterns in the collection
 * @return {Boolean}
 */
const hasPatternOrdering = itms => {
  return Object.keys(itms).some(itm => {
    return (itms[itm].data && itms[itm].data.hasOwnProperty('order'));
  });
};

/**
 * Flesh out an individual pattern object.
 *
 * @param {Object} patternObj
 * @param {Object} options
 * @return {Object} built-out pattern
 */
function buildPattern (patternObj, options) {
  const patternFile = { path: patternObj.path };
  // const patternId = resourceId(patternFile,
  //   options.src.patterns.basedir, 'patterns');
  // checkNamespaceCollision('id', patternObj.data,
  //   `Pattern ${patternId}`, options);
  return Object.assign(patternObj, {
    name: (patternObj.data && patternObj.data.name) ||
      titleCase(resourceKey(patternFile))
  });
}

/**
 * Flesh out all of the patterns that are within `collectionObj`. This is
 * before any of these patterns get assigned to `items` or `patterns` on
 * `collectionObj.collection`.
 *
 * @param {Object} collectionObj  The containing object with pattern children
 *                                that will ultimately be managed under
 *                                collectionObj.collection (items and patterns)
 * @param {Object} options
 * @return {Object} patterns      Built-out pattern objects
 */
function buildPatterns (collectionObj, options) {
  const patterns = {};
  for (const childKey in collectionObj) {
    if (isPattern(collectionObj[childKey])) {
      patterns[childKey] = buildPattern(collectionObj[childKey], options);
      delete collectionObj[childKey];
    }
  }
  return patterns;
}

/**
 * Transform the `collection`'s `items` (all patterns, unordered) into
 * an {Array} of ordered, visible patterns that should be rendered as part
 * of this collection. Check both individual pattern files and collection
 * metadata for ordering information, as well as information about hidden
 * patterns.
 *
 * @param {Object} collection
 * @return {Array} patterns            Ordered, visible patterns
 */
function buildOrderedPatterns (collection) {
  let sortedKeys;
  if (hasPatternOrdering(collection.items)) {
    sortedKeys = Object.keys(collection.items).sort((keyA, keyB) => {
      const orderA = collection.items[keyA].data.order || 10000;
      const orderB = collection.items[keyB].data.order || 10000;
      return orderA - orderB;
    });
  } else {
    sortedKeys = collection.order || [];
  }
  const patterns = [];
  sortedKeys = sortedKeys.concat(
    Object.keys(collection.items).filter(itemKey => {
      // Make sure all keys are accounted for
      return (sortedKeys.indexOf(itemKey) < 0);
    })
  );
  sortedKeys.forEach(sortedKey => {
    if (!isHidden(collection, collection.items[sortedKey], sortedKey)) {
      patterns.push(collection.items[sortedKey]);
    }
  });
  return patterns;
}

/**
 * Build an individual collection object. Give it some metadata based on
 * defaults and any metadata file found in its path. Build the Array of
 * patterns that should appear on this pattern collection's page.
 *
 * @param {Object} collectionObj  The containing object that holds the patterns
 *                                that are part of this collection.
 * @param {Object} options
 * @return {Promise} resolving to {Object} representing the containing object
 *                                for this collection (as distinct from
 *                                collectionObj.collection, which is what this
 *                                function tacks on).
 */
function buildCollection (collectionObj, options) {
  const items = buildPatterns (collectionObj, options);
  const pseudoFile = { path: collectionPath(items) };
  return readFiles(collectionGlob(items), options).then(collData => {
    const collectionMeta = (collData.length) ? collData[0].contents : {};
    collectionObj.collection = Object.assign ({
      name: titleCase(collectionKey(items)),
      id: resourceId(pseudoFile, options.src.patterns.basedir,
        options.keys.collections)
    }, collectionMeta);
    checkNamespaceCollision(['items', 'patterns'], collectionObj.collection,
      `Collection ${collectionObj.collection.name}`, options);
    collectionObj.collection.items = items;
    collectionObj.collection.patterns = buildOrderedPatterns(
      collectionObj.collection);
    return collectionObj;
  });
}

/**
 * Traverse and build collections data and their contained patterns based on
 * parsed pattern data.
 *
 * @param {Object} patternObj  Patterns at the current level of traverse.
 * @param {Object} options
 * @param {Array} collectionPromises Array of `{Promise}`s representing
 *                             reading collection metadata
 */
function buildCollections (patternObj, options, collectionPromises = []) {
  if (isPattern(patternObj)) { return collectionPromises; }
  if (isCollection(patternObj)) {
    collectionPromises.push(buildCollection (patternObj, options));
  }
  for (const patternKey in patternObj) {
    if (patternKey !== 'collection') {
      buildCollections (patternObj[patternKey], options, collectionPromises);
    }
  }
  return collectionPromises;
}

/**
 * Parse pattern files and then flesh out individual pattern objects and
 * build collection data.
 *
 * @param {Object} options
 * @return {Promise} resolving to pattern/collection data
 */
function parsePatterns (options) {
  return readFileTree(options.src.patterns, options.keys.patterns, options)
  .then(patternObj => {
    return Promise.all(buildCollections(patternObj, options))
      .then(() => patternObj,
            error => DrizzleError.error(error, options.debug));
  });
}

export default parsePatterns;
<commit_msg>Remove commented code<commit_after>/**
 * @module parse/patterns
 */
import { resourceId, resourceKey } from '../utils/object';
import { readFiles, readFileTree } from '../utils/parse';
import { titleCase } from '../utils/shared';
import path from 'path';

import DrizzleError from '../utils/error';

const isPattern = obj => obj.hasOwnProperty('path');
const collectionPath = itms => path.dirname(itms[Object.keys(itms).pop()].path);
const collectionKey = itms => collectionPath(itms).split(path.sep).pop();

function checkNamespaceCollision (key, obj, id, options = {}) {
  if (Array.isArray(key)) {
    return key.map(oneKey =>
      checkNamespaceCollision(oneKey, obj, id, options)
    );
  }
  if (obj && obj.hasOwnProperty(key)) {
    DrizzleError.error(new DrizzleError(`'${id}' has local '${key}'
property set. This is a Drizzle reserved property and will be
overwritten. See docs.`, DrizzleError.LEVELS.WARN), options.debug);
  }
}

/**
 * Should this pattern be hidden per collection or pattern metadata?
 * @param {Object} collection   Collection obj
 * @param {Object} pattern      Pattern obj
 * @param {String} patternKey
 * @return {Boolean}
 */
function isHidden (collection, pattern, patternKey) {
  return ((collection.hidden && collection.hidden.indexOf(patternKey) !== -1) ||
    (pattern.data && pattern.data.hidden));
}

/**
 * Is the obj a collection?
 * @param {Object} obj
 * @return {Boolean}
 */
function isCollection (obj) {
  if (isPattern(obj)) { return false; }
  return Object.keys(obj).some(childKey => isPattern(obj[childKey]));
}

/**
 * Construct a glob to look for collection metadata.
 * @param {Object} items  All the patterns
 * @return {String} glob
 */
function collectionGlob (items) {
  return path.join(collectionPath(items), 'collection.+(yml|yaml|json)');
}

/**
 * Do any of the patterns in this collection have ordering information in their
 * front matter?
 *
 * @param itms      Patterns in the collection
 * @return {Boolean}
 */
const hasPatternOrdering = itms => {
  return Object.keys(itms).some(itm => {
    return (itms[itm].data && itms[itm].data.hasOwnProperty('order'));
  });
};

/**
 * Flesh out an individual pattern object.
 *
 * @param {Object} patternObj
 * @param {Object} options
 * @return {Object} built-out pattern
 */
function buildPattern (patternObj, options) {
  const patternFile = { path: patternObj.path };
  return Object.assign(patternObj, {
    name: (patternObj.data && patternObj.data.name) ||
      titleCase(resourceKey(patternFile))
  });
}

/**
 * Flesh out all of the patterns that are within `collectionObj`. This is
 * before any of these patterns get assigned to `items` or `patterns` on
 * `collectionObj.collection`.
 *
 * @param {Object} collectionObj  The containing object with pattern children
 *                                that will ultimately be managed under
 *                                collectionObj.collection (items and patterns)
 * @param {Object} options
 * @return {Object} patterns      Built-out pattern objects
 */
function buildPatterns (collectionObj, options) {
  const patterns = {};
  for (const childKey in collectionObj) {
    if (isPattern(collectionObj[childKey])) {
      patterns[childKey] = buildPattern(collectionObj[childKey], options);
      delete collectionObj[childKey];
    }
  }
  return patterns;
}

/**
 * Transform the `collection`'s `items` (all patterns, unordered) into
 * an {Array} of ordered, visible patterns that should be rendered as part
 * of this collection. Check both individual pattern files and collection
 * metadata for ordering information, as well as information about hidden
 * patterns.
 *
 * @param {Object} collection
 * @return {Array} patterns            Ordered, visible patterns
 */
function buildOrderedPatterns (collection) {
  let sortedKeys;
  if (hasPatternOrdering(collection.items)) {
    sortedKeys = Object.keys(collection.items).sort((keyA, keyB) => {
      const orderA = collection.items[keyA].data.order || 10000;
      const orderB = collection.items[keyB].data.order || 10000;
      return orderA - orderB;
    });
  } else {
    sortedKeys = collection.order || [];
  }
  const patterns = [];
  sortedKeys = sortedKeys.concat(
    Object.keys(collection.items).filter(itemKey => {
      // Make sure all keys are accounted for
      return (sortedKeys.indexOf(itemKey) < 0);
    })
  );
  sortedKeys.forEach(sortedKey => {
    if (!isHidden(collection, collection.items[sortedKey], sortedKey)) {
      patterns.push(collection.items[sortedKey]);
    }
  });
  return patterns;
}

/**
 * Build an individual collection object. Give it some metadata based on
 * defaults and any metadata file found in its path. Build the Array of
 * patterns that should appear on this pattern collection's page.
 *
 * @param {Object} collectionObj  The containing object that holds the patterns
 *                                that are part of this collection.
 * @param {Object} options
 * @return {Promise} resolving to {Object} representing the containing object
 *                                for this collection (as distinct from
 *                                collectionObj.collection, which is what this
 *                                function tacks on).
 */
function buildCollection (collectionObj, options) {
  const items = buildPatterns (collectionObj, options);
  const pseudoFile = { path: collectionPath(items) };
  return readFiles(collectionGlob(items), options).then(collData => {
    const collectionMeta = (collData.length) ? collData[0].contents : {};
    collectionObj.collection = Object.assign ({
      name: titleCase(collectionKey(items)),
      id: resourceId(pseudoFile, options.src.patterns.basedir,
        options.keys.collections)
    }, collectionMeta);
    checkNamespaceCollision(['items', 'patterns'], collectionObj.collection,
      `Collection ${collectionObj.collection.name}`, options);
    collectionObj.collection.items = items;
    collectionObj.collection.patterns = buildOrderedPatterns(
      collectionObj.collection);
    return collectionObj;
  });
}

/**
 * Traverse and build collections data and their contained patterns based on
 * parsed pattern data.
 *
 * @param {Object} patternObj  Patterns at the current level of traverse.
 * @param {Object} options
 * @param {Array} collectionPromises Array of `{Promise}`s representing
 *                             reading collection metadata
 */
function buildCollections (patternObj, options, collectionPromises = []) {
  if (isPattern(patternObj)) { return collectionPromises; }
  if (isCollection(patternObj)) {
    collectionPromises.push(buildCollection (patternObj, options));
  }
  for (const patternKey in patternObj) {
    if (patternKey !== 'collection') {
      buildCollections (patternObj[patternKey], options, collectionPromises);
    }
  }
  return collectionPromises;
}

/**
 * Parse pattern files and then flesh out individual pattern objects and
 * build collection data.
 *
 * @param {Object} options
 * @return {Promise} resolving to pattern/collection data
 */
function parsePatterns (options) {
  return readFileTree(options.src.patterns, options.keys.patterns, options)
  .then(patternObj => {
    return Promise.all(buildCollections(patternObj, options))
      .then(() => patternObj,
            error => DrizzleError.error(error, options.debug));
  });
}

export default parsePatterns;
<|endoftext|>


<commit_before>RealityCheck = (function ($) {
    "use strict";

    var reality_check_url = page.url.url_for('user/reality_check');
    var reality_freq_url  = page.url.url_for('user/reality_check_frequency');
    var logout_url        = page.url.url_for('logout');

    RealityCheck.prototype.setInterval = function (intv) {
        this.interval = intv * 60 * 1000; // convert minutes to millisec
        this.storage.set('reality_check.interval', this.interval);
    };

    RealityCheck.prototype.getInterval = function () {
        return this.getIntervalMs() / (60 * 1000); // convert to minutes

    };

    RealityCheck.prototype.getIntervalMs = function () {
        if (this.interval > 0) return this.interval;

        this.interval = parseFloat(this.storage.get('reality_check.interval'));

        // use default if garbage
        if (isNaN(this.interval) || this.interval<=0)
            this.interval = this.default_interval;

        return this.interval;
    };

    function RealityCheck(cookieName, persistentStore) {
        var val, that = this;

        val = ($.cookie(cookieName)||'').split(',');
        val[0] = parseFloat(val[0]);
        if (isNaN(val[0]) || val[0]<=0) return;  // no or invalid cookie
        this.default_interval = val[0] * 60 * 1000;

        this.storage = persistentStore;

        // A storage event handler is used to notify about interval changes.
        // That way all windows see the same interval.
        $(window).on('storage', function (jq_event) {
            if (jq_event.originalEvent.key === 'reality_check.interval') {
                that.interval = parseFloat(jq_event.originalEvent.newValue);

                // garbage here can only happen if the user tries to tamper
                if (isNaN(that.interval) || that.interval<=0)
                    that.interval = that.default_interval;

                console.log('interval storage handler new value = '+that.interval);

                that.setAlarm();
            }

            if (jq_event.originalEvent.key === 'reality_check.basetime') {
                var val = parseInt(jq_event.originalEvent.newValue);

                // garbage here can only happen if the user tries to tamper
                if (isNaN(val) || val<=0) return;
                that.basetime = val;

                console.log('basetime storage handler new value = '+that.basetime);

                that.setAlarm();
            }
        });

        // The cookie is formatted as DEFAULT_INTERVAL , SERVER_TIME_WHEN_IT_WAS_ISSUED
        // We save the server time in local storage. If the stored time differs from
        // the cookie time we are in a new session. Hence, we have to reset all stored
        // data and to ask the user to check the reality-check frequency.

        if (val[1] && val[1] != persistentStore.get('reality_check.srvtime')) {
            persistentStore.set('reality_check.srvtime', val[1]);
            persistentStore.set('reality_check.basetime', this.basetime = new Date().getTime());
            persistentStore.set('reality_check.ack', 1);
            this.askForFrequency();
        } else {
            this.basetime = parseInt(persistentStore.get('reality_check.basetime'));
            this.setAlarm();
        }
    }

    RealityCheck.prototype.setAlarm = function () {
        var that = this;
        var intv = this.getIntervalMs();
        var alrm = intv - (new Date().getTime() - this.basetime) % intv;

        console.log('interval = '+this.interval+', next alarm in '+alrm+' ms');
        console.log('alrm at '+(new Date((new Date()).getTime()+alrm)).toUTCString());

        if (this.tmout) window.clearTimeout(this.tmout);

        this.tmout = window.setTimeout(function () {
            // console.log('fire at '+(new Date()).toUTCString());
            that.fire();
        }, alrm);
    };

    RealityCheck.prototype._fire = function (url, next) {
        var that = this;

        $.ajax({
            url: url,
            dataType: 'text',
            success: function (data) {
                next.call(that, data);
            },
            error: function (xhr) {
                if (xhr.status === 404) return; // no MF loginid
                window.setTimeout(function () {
                    that.fire();
                }, 5000);
            },
        });
    };

    RealityCheck.prototype.fire = function () {
        this._fire(reality_check_url, this.display);
    };

    RealityCheck.prototype.display = function (data) {
        var that = this, outer, middle, storage_handler;

        outer = $('#reality-check');
        if (outer) outer.remove();

        outer = $("

").appendTo('body');
        middle = $('
').appendTo(outer);
        $('
' + data + '
').appendTo(middle);
        $('#reality-check [interval=1]').val(this.getInterval());

        storage_handler = function (jq_event) {
            var ack;

            if (jq_event.originalEvent.key !== 'reality_check.ack') return;
            ack = parseInt(jq_event.originalEvent.newValue || 1);
            if (ack > that.lastAck) {
                console.log('Display storage handler');

                $(window).off('storage', storage_handler);
                that.setAlarm();
                $('#reality-check').remove();
            }
        };

        // in case the client works with multiple windows, check if he has acknowleged
        // it in another window.
        $(window).on('storage', storage_handler);

        this.lastAck = parseInt(this.storage.get('reality_check.ack') || 1);
        $('#reality-check [bcont=1]').on('click', function () {
            var intv = parseFloat($('#reality-check [interval=1]').val());
            if (intv <= 0) {
                $('#reality-check p.msg').show('fast');
                return;
            }
            that.setInterval(intv);
            that.storage.set('reality_check.ack', that.lastAck+1);
            $(window).off('storage', storage_handler);
            that.setAlarm();
            $('#reality-check').remove();
        });

        $('#reality-check .blogout').on('click', function () {
            window.location.href = logout_url;
        });
    };

    // On session start we need to ask for the reality-check interval.
    // This is an ajax call because it depends on the user's language.

    RealityCheck.prototype.askForFrequency = function () {
        this._fire(reality_freq_url, this.displayFrequencyChoice);
    };

    RealityCheck.prototype.displayFrequencyChoice = function (data) {
        var that = this, outer, middle, storage_handler, click_handler;

        outer = $('#reality-check');
        if (outer) outer.remove();

        outer = $("

").appendTo('body');
        middle = $('
').appendTo(outer);
        $('
' + data + '
').appendTo(middle);
        $('#reality-check [interval=1]').val(this.getInterval());

        storage_handler = function (jq_event) {
            var ack;

            if (jq_event.originalEvent.key !== 'reality_check.ack') return;

            ack = parseInt(jq_event.originalEvent.newValue || 1);
            if (ack > that.lastAck) {
                console.log('FreqSet storage handler');

                $(window).off('storage', storage_handler);
                $('#reality-check').remove();
            }
        };

        // in case the client works with multiple windows, check if he has acknowleged
        // it in another window.
        $(window).on('storage', storage_handler);

        this.lastAck = parseInt(this.storage.get('reality_check.ack') || 1);
        click_handler = function () {
            var intv = parseFloat($('#reality-check [interval=1]').val());
            if (intv <= 0) {
                $('#reality-check p.msg').show('fast');
                return;
            }

            console.log('set interval handler: intv = '+intv);

            that.setInterval(intv);
            that.storage.set('reality_check.ack', that.lastAck+1);
            $(window).off('storage', storage_handler);
            $('#reality-check').remove();
            that.setAlarm();
        };
        $('#reality-check [bcont=1]').on('click', click_handler);
        $('#reality-check [interval=1]').on('change', click_handler);
    };

    return RealityCheck;
}(jQuery));

$(document).ready(function () {
    console.log('About to create reality-check object');

    if (window.reality_check_object) return;
    window.reality_check_object = new RealityCheck('reality_check', LocalStore);
});
<commit_msg>ask for reality check interval<commit_after>RealityCheck = (function ($) {
    "use strict";

    var reality_check_url = page.url.url_for('user/reality_check');
    var reality_freq_url  = page.url.url_for('user/reality_check_frequency');
    var logout_url        = page.url.url_for('logout');

    RealityCheck.prototype.setInterval = function (intv) {
        this.interval = intv * 60 * 1000; // convert minutes to millisec
        this.storage.set('reality_check.interval', this.interval);
    };

    RealityCheck.prototype.getInterval = function () {
        return this.getIntervalMs() / (60 * 1000); // convert to minutes

    };

    RealityCheck.prototype.getIntervalMs = function () {
        if (this.interval > 0) return this.interval;

        this.interval = parseFloat(this.storage.get('reality_check.interval'));

        // use default if garbage
        if (isNaN(this.interval) || this.interval<=0)
            this.interval = this.default_interval;

        return this.interval;
    };

    function RealityCheck(cookieName, persistentStore) {
        var val, that = this;

        val = ($.cookie(cookieName)||'').split(',');
        val[0] = parseFloat(val[0]);
        if (isNaN(val[0]) || val[0]<=0) return;  // no or invalid cookie
        this.default_interval = val[0] * 60 * 1000;

        this.storage = persistentStore;

        // A storage event handler is used to notify about interval changes.
        // That way all windows see the same interval.
        $(window).on('storage', function (jq_event) {
            if (jq_event.originalEvent.key === 'reality_check.interval') {
                that.interval = parseFloat(jq_event.originalEvent.newValue);

                // garbage here can only happen if the user tries to tamper
                if (isNaN(that.interval) || that.interval<=0)
                    that.interval = that.default_interval;

                console.log('interval storage handler new value = '+that.interval);

                that.setAlarm();
            }

            if (jq_event.originalEvent.key === 'reality_check.basetime') {
                var val = parseInt(jq_event.originalEvent.newValue);

                // garbage here can only happen if the user tries to tamper
                if (isNaN(val) || val<=0) return;
                that.basetime = val;

                console.log('basetime storage handler new value = '+that.basetime);

                that.setAlarm();
            }
        });

        // The cookie is formatted as DEFAULT_INTERVAL , SERVER_TIME_WHEN_IT_WAS_ISSUED
        // We save the server time in local storage. If the stored time differs from
        // the cookie time we are in a new session. Hence, we have to reset all stored
        // data and to ask the user to check the reality-check frequency.

        if (val[1] && val[1] != persistentStore.get('reality_check.srvtime')) {
            persistentStore.set('reality_check.srvtime', val[1]);
            persistentStore.set('reality_check.basetime', this.basetime = new Date().getTime());
            persistentStore.set('reality_check.ack', 1);
            this.askForFrequency();
        } else if (persistentStore.get('reality_check.askingForInterval')) {
            this.basetime = parseInt(persistentStore.get('reality_check.basetime'));
            this.askForFrequency();
        } else {
            this.basetime = parseInt(persistentStore.get('reality_check.basetime'));
            this.setAlarm();
        }
    }

    RealityCheck.prototype.setAlarm = function () {
        var that = this;
        var intv = this.getIntervalMs();
        var alrm = intv - (new Date().getTime() - this.basetime) % intv;

        console.log('interval = '+this.interval+', next alarm in '+alrm+' ms');
        console.log('alrm at '+(new Date((new Date()).getTime()+alrm)).toUTCString());

        if (this.tmout) window.clearTimeout(this.tmout);

        this.tmout = window.setTimeout(function () {
            // console.log('fire at '+(new Date()).toUTCString());
            that.fire();
        }, alrm);
    };

    RealityCheck.prototype._fire = function (url, next) {
        var that = this;

        $.ajax({
            url: url,
            dataType: 'text',
            success: function (data) {
                next.call(that, data);
            },
            error: function (xhr) {
                if (xhr.status === 404) return; // no MF loginid
                window.setTimeout(function () {
                    that.fire();
                }, 5000);
            },
        });
    };

    RealityCheck.prototype.fire = function () {
        this._fire(reality_check_url, this.display);
    };

    RealityCheck.prototype.display = function (data) {
        var that = this, outer, middle, storage_handler;

        outer = $('#reality-check');
        if (outer) outer.remove();

        outer = $("

").appendTo('body');
        middle = $('
').appendTo(outer);
        $('
' + data + '
').appendTo(middle);
        $('#reality-check [interval=1]').val(this.getInterval());

        storage_handler = function (jq_event) {
            var ack;

            if (jq_event.originalEvent.key !== 'reality_check.ack') return;
            ack = parseInt(jq_event.originalEvent.newValue || 1);
            if (ack > that.lastAck) {
                console.log('Display storage handler');

                $(window).off('storage', storage_handler);
                that.setAlarm();
                $('#reality-check').remove();
            }
        };

        // in case the client works with multiple windows, check if he has acknowleged
        // it in another window.
        $(window).on('storage', storage_handler);

        this.lastAck = parseInt(this.storage.get('reality_check.ack') || 1);
        $('#reality-check [bcont=1]').on('click', function () {
            var intv = parseFloat($('#reality-check [interval=1]').val());
            if (intv <= 0) {
                $('#reality-check p.msg').show('fast');
                return;
            }
            that.setInterval(intv);
            that.storage.set('reality_check.ack', that.lastAck+1);
            $(window).off('storage', storage_handler);
            that.setAlarm();
            $('#reality-check').remove();
        });

        $('#reality-check .blogout').on('click', function () {
            window.location.href = logout_url;
        });
    };

    // On session start we need to ask for the reality-check interval.
    // This is an ajax call because it depends on the user's language.

    RealityCheck.prototype.askForFrequency = function () {
        this._fire(reality_freq_url, this.displayFrequencyChoice);
    };

    RealityCheck.prototype.displayFrequencyChoice = function (data) {
        var that = this, outer, middle, storage_handler, click_handler;

        outer = $('#reality-check');
        if (outer) outer.remove();

        outer = $("

").appendTo('body');
        middle = $('
').appendTo(outer);
        $('
' + data + '
').appendTo(middle);
        $('#reality-check [interval=1]').val(this.getInterval());

        this.storage.set('reality_check.askingForInterval', 1);
        storage_handler = function (jq_event) {
            var ack;

            if (jq_event.originalEvent.key !== 'reality_check.ack') return;

            ack = parseInt(jq_event.originalEvent.newValue || 1);
            if (ack > that.lastAck) {
                console.log('FreqSet storage handler');

                $(window).off('storage', storage_handler);
                $('#reality-check').remove();
            }
        };

        // in case the client works with multiple windows, check if he has acknowleged
        // it in another window.
        $(window).on('storage', storage_handler);

        this.lastAck = parseInt(this.storage.get('reality_check.ack') || 1);
        click_handler = function () {
            var intv = parseFloat($('#reality-check [interval=1]').val());
            if (intv <= 0) {
                $('#reality-check p.msg').show('fast');
                return;
            }

            console.log('set interval handler: intv = '+intv);
            that.storage.removeItem('reality_check.askingForInterval');

            that.setInterval(intv);
            that.storage.set('reality_check.ack', that.lastAck+1);
            $(window).off('storage', storage_handler);
            $('#reality-check').remove();
            that.setAlarm();
        };
        $('#reality-check [bcont=1]').on('click', click_handler);
        $('#reality-check [interval=1]').on('change', click_handler);
    };

    return RealityCheck;
}(jQuery));

$(document).ready(function () {
    console.log('About to create reality-check object');

    if (window.reality_check_object) return;
    window.reality_check_object = new RealityCheck('reality_check', LocalStore);
});
<|endoftext|>


<commit_before>var TickDisplay = function() {
    return {
        reset: function() {
            var $self = this;
            $self.contract_barrier = null;
            $self.applicable_ticks = [];
            $self.chart.destroy();
        },
        initialize: function(data) {
            var $self = this;

            // setting up globals
            $self.number_of_ticks = parseInt(data.number_of_ticks);
            $self.symbol = data.symbol;
            $self.display_symbol = data.display_symbol;
            $self.contract_start_ms = parseInt(data.contract_start * 1000);
            $self.contract_type = data.contract_type;
            $self.set_barrier = true;
            $self.display_decimal = 0;

            if (typeof data.decimal !== 'undefined') {
                $self.number_of_decimal = parseInt(data.decimal) + 1; //calculated barrier is rounded to one more decimal place
            }

            if (data.show_contract_result) {
                $self.show_contract_result = true;
                $self.contract_sentiment = data.contract_sentiment;
                $self.price = parseFloat(data.price);
                $self.payout = parseFloat(data.payout);
            }

            var minimize = data.show_contract_result;
            $self.set_x_indicators();

            $self.initialize_chart({
                plot_from: data.previous_tick_epoch * 1000,
                plot_to: new Date((parseInt(data.contract_start) + parseInt(($self.number_of_ticks+2)*2)) * 1000).getTime(),
                minimize: minimize,
            });
        },
        set_x_indicators: function() {
            var $self = this;

            if ($self.contract_type.match('ASIAN')) {
                var last_tick_index = $self.number_of_ticks - 1;

                $self.x_indicators = {
                    '_0': { label: 'Tick 1', id: 'start_tick'},
                };
                $self.x_indicators['_' + last_tick_index] = {
                    label: 'Tick ' + $self.number_of_ticks,
                    id: 'last_tick',
                };
                $self.x_indicators['_' + $self.number_of_ticks] = {
                    label: 'Exit Tick',
                    id: 'exit_tick',
                };
            } else if ($self.contract_type.match('FLASH')) {
                $self.x_indicators = {
                    '_1': { label: 'Tick 1', id: 'start_tick'},
                };
                $self.x_indicators['_' + $self.number_of_ticks] = {
                    label: 'Exit Tick',
                    id: 'exit_tick',
                };
            } else if ($self.contract_type.match('DIGIT')) {
                $self.x_indicators = {
                    '_0': { label: 'Tick 1', id: 'start_tick'},
                };
                $self.x_indicator['_' + $self.number_of_ticks - 1] = {
                    label:  'Tick ' + $self.number_of_ticks,
                    id: 'last_tick',
                };
            } else {
                $self.x_indicators = {};
            }

        },
        initialize_chart: function(config) {
            var $self = this;

            $self.chart = new Highcharts.Chart({
                chart: {
                    type: 'line',
                    renderTo: 'tick_chart',
                    width: config.minimize ? 394 : null,
                    height: config.minimize ? 125 : null,
                    backgroundColor: null,
                    events: { load: $self.plot(config.plot_from, config.plot_to) },
                },
                tooltip: {
                    formatter: function () {
                        var that = this;
                        var new_decimal = that.y.toString().split('.')[1].length;
                        var decimal_places = Math.max( $self.display_decimal, new_decimal);
                        $self.display_decimal = decimal_places;
                        var new_y = that.y.toFixed(decimal_places);
                        var mom = moment.utc(that.x*1000).format("dddd, MMM D, HH:mm:ss");
                        return mom + "
" + $self.display_symbol + " " + new_y;
                    },
                },
                xAxis: {
                    type: 'datetime',
                    min: parseInt(config['plot_from']),
                    max: parseInt(config['plot_to']),
                    labels: { enabled: false, }
                },
                yAxis: {
                    title: '',
                },
                series: [{
                    data: [],
                }],
                title: '',
                exporting: {enabled: false, enableImages: false},
                legend: {enabled: false},
            });
        },
        plot: function(plot_from, plot_to) {
            var $self = this;

            var plot_from_moment = moment(plot_from).utc();
            var plot_to_moment = moment(plot_to).utc();
            var contract_start_moment = moment($self.contract_start_ms).utc();
            var ticks_needed = $self.number_of_ticks + 1;
            $self.applicable_ticks = [];

            var symbol = $self.symbol;
            var stream_url = window.location.protocol + '//' + page.settings.get('streaming_server');
            stream_url += "/stream/ticks/" + symbol + "/" + plot_from_moment.unix() + "/" + plot_to_moment.unix();
            $self.ev = new EventSource(stream_url, { withCredentials: true });

            $self.ev.onmessage = function(msg) {
                if ($self.applicable_ticks.length >= ticks_needed) {
                    $self.ev.close();
                    $self.evaluate_contract_outcome();
                    return;
                }

                var data = JSON.parse(msg.data);
                if (!(data[0] instanceof Array)) {
                    data = [ data ];
                }
                for (var i = 0; i < data.length; i++) {
                    if (data[i][0] === 'tick') {
                        var tick = {
                            epoch: parseInt(data[i][1]),
                            quote: parseFloat(data[i][2])
                        };
                        $self.chart.series[0].addPoint([tick.epoch*1000, tick.quote], true, false);

                        if (tick.epoch > contract_start_moment.unix()) {
                            $self.applicable_ticks.push(tick);

                            var tick_index = $self.applicable_ticks.length - 1;
                            var indicator_key = '_' + tick_index;

                            if (typeof $self.x_indicators[indicator_key] !== 'undefined') {
                                $self.x_indicators[indicator_key]['index'] = tick_index;
                                $self.add($self.x_indicators[indicator_key]);
                            }

                            $self.add_barrier();
                        }
                    }
                }
            };
            $self.ev.onerror = function(e) {$self.ev.close(); };
        },
        add_barrier: function() {
            var $self = this;

            if (!$self.set_barrier) {
                return;
            }

            var barrier_type = $self.contract_type.match('ASIAN') ? 'asian' : 'static';

            if (barrier_type === 'static') {
                var barrier_tick = $self.applicable_ticks[0];
                $self.chart.yAxis[0].addPlotLine({
                    id: 'tick-barrier',
                    value: barrier_tick.quote,
                    label: {text: 'Barrier ('+barrier_tick.quote+')', align: 'center'},
                    color: 'green',
                    width: 2,
                });
                $self.contract_barrier = barrier_tick.quote;
                $self.set_barrier = false;
            }

            if (barrier_type === 'asian') {
                var total = 0;
                for (var i=0; i < $self.applicable_ticks.length; i++) {
                    total += parseFloat($self.applicable_ticks[i].quote);
                }
                var calc_barrier =  total/$self.applicable_ticks.length;
                calc_barrier = calc_barrier.toFixed($self.number_of_decimal); // round calculated barrier

                $self.chart.yAxis[0].removePlotLine('tick-barrier');
                $self.chart.yAxis[0].addPlotLine({
                    id: 'tick-barrier',
                    value: calc_barrier,
                    color: 'green',
                    label: {
                        text: 'Average ('+calc_barrier+')',
                        align: 'center'
                    },
                    width: 2,
                });
                $self.contract_barrier = calc_barrier;
            }
        },
        add: function(indicator) {
            var $self = this;

            $self.chart.xAxis[0].addPlotLine({
               value: $self.applicable_ticks[indicator.index].epoch * 1000,
               id: indicator.id,
               label: {text: indicator.label},
               color: '#e98024',
               width: 2,
            });
        },
        evaluate_contract_outcome: function() {
            var $self = this;

            if (!$self.contract_barrier) {
                return; // can't do anything without barrier
            }

            var exit_tick_index = $self.applicable_ticks.length - 1;
            var exit_spot = $self.applicable_ticks[exit_tick_index].quote;

            if ($self.contract_sentiment === 'up') {
                if (exit_spot > $self.contract_barrier) {
                    $self.win();
                } else {
                    $self.lose();
                }
            } else if ($self.contract_sentiment === 'down') {
                if (exit_spot < $self.contract_barrier) {
                    $self.win();
                } else {
                    $self.lose();
                }
            }

        },
        win: function() {
            var $self = this;

            var profit = $self.payout - $self.price;
            $self.update_ui($self.payout, profit, 'This contract won');
        },
        lose: function() {
            var $self = this;
            $self.update_ui(0, -$self.price, 'This contract lost');
        },
        update_ui: function(final_price, pnl, contract_status) {
            var $self = this;

            $('#bet-confirm-header').text(text.localize(contract_status));
            $('#contract-outcome-buyprice').text($self.to_monetary_format($self.price));
            $('#contract-outcome-payout').text($self.to_monetary_format(final_price));

            if (pnl > 0) {
                $('#contract-outcome-label').text(text.localize('Profit'));
                $('#contract-outcome-profit').addClass('profit').text($self.to_monetary_format(pnl));
            } else {
                $('#contract-outcome-label').removeClass('standout').text(text.localize('Loss'));
                $('#contract-outcome-profit').addClass('loss').text($self.to_monetary_format(pnl));
            }
            $('#contract-confirmation-details').hide();
            $('#contract-outcome-details').show();
        },
        to_monetary_format: function(number) {
            return number.toFixed(2);
        }
    };
}();
<commit_msg>Exit spot to Exit tick<commit_after>var TickDisplay = function() {
    return {
        reset: function() {
            var $self = this;
            $self.contract_barrier = null;
            $self.applicable_ticks = [];
            $self.chart.destroy();
        },
        initialize: function(data) {
            var $self = this;

            // setting up globals
            $self.number_of_ticks = parseInt(data.number_of_ticks);
            $self.symbol = data.symbol;
            $self.display_symbol = data.display_symbol;
            $self.contract_start_ms = parseInt(data.contract_start * 1000);
            $self.contract_type = data.contract_type;
            $self.set_barrier = true;
            $self.display_decimal = 0;

            if (typeof data.decimal !== 'undefined') {
                $self.number_of_decimal = parseInt(data.decimal) + 1; //calculated barrier is rounded to one more decimal place
            }

            if (data.show_contract_result) {
                $self.show_contract_result = true;
                $self.contract_sentiment = data.contract_sentiment;
                $self.price = parseFloat(data.price);
                $self.payout = parseFloat(data.payout);
            }

            var minimize = data.show_contract_result;
            $self.set_x_indicators();

            $self.initialize_chart({
                plot_from: data.previous_tick_epoch * 1000,
                plot_to: new Date((parseInt(data.contract_start) + parseInt(($self.number_of_ticks+2)*2)) * 1000).getTime(),
                minimize: minimize,
            });
        },
        set_x_indicators: function() {
            var $self = this;

            if ($self.contract_type.match('ASIAN')) {
                var last_tick_index = $self.number_of_ticks - 1;

                $self.x_indicators = {
                    '_0': { label: 'Tick 1', id: 'start_tick'},
                };
                $self.x_indicators['_' + last_tick_index] = {
                    label: 'Tick ' + $self.number_of_ticks,
                    id: 'last_tick',
                };
                $self.x_indicators['_' + $self.number_of_ticks] = {
                    label: 'Exit Spot',
                    id: 'exit_tick',
                };
            } else if ($self.contract_type.match('FLASH')) {
                $self.x_indicators = {
                    '_1': { label: 'Tick 1', id: 'start_tick'},
                };
                $self.x_indicators['_' + $self.number_of_ticks] = {
                    label: 'Exit Spot',
                    id: 'exit_tick',
                };
            } else if ($self.contract_type.match('DIGIT')) {
                $self.x_indicators = {
                    '_0': { label: 'Tick 1', id: 'start_tick'},
                };
                $self.x_indicator['_' + $self.number_of_ticks - 1] = {
                    label:  'Tick ' + $self.number_of_ticks,
                    id: 'last_tick',
                };
            } else {
                $self.x_indicators = {};
            }

        },
        initialize_chart: function(config) {
            var $self = this;

            $self.chart = new Highcharts.Chart({
                chart: {
                    type: 'line',
                    renderTo: 'tick_chart',
                    width: config.minimize ? 394 : null,
                    height: config.minimize ? 125 : null,
                    backgroundColor: null,
                    events: { load: $self.plot(config.plot_from, config.plot_to) },
                },
                tooltip: {
                    formatter: function () {
                        var that = this;
                        var new_decimal = that.y.toString().split('.')[1].length;
                        var decimal_places = Math.max( $self.display_decimal, new_decimal);
                        $self.display_decimal = decimal_places;
                        var new_y = that.y.toFixed(decimal_places);
                        var mom = moment.utc(that.x*1000).format("dddd, MMM D, HH:mm:ss");
                        return mom + "
" + $self.display_symbol + " " + new_y;
                    },
                },
                xAxis: {
                    type: 'datetime',
                    min: parseInt(config['plot_from']),
                    max: parseInt(config['plot_to']),
                    labels: { enabled: false, }
                },
                yAxis: {
                    title: '',
                },
                series: [{
                    data: [],
                }],
                title: '',
                exporting: {enabled: false, enableImages: false},
                legend: {enabled: false},
            });
        },
        plot: function(plot_from, plot_to) {
            var $self = this;

            var plot_from_moment = moment(plot_from).utc();
            var plot_to_moment = moment(plot_to).utc();
            var contract_start_moment = moment($self.contract_start_ms).utc();
            var ticks_needed = $self.number_of_ticks + 1;
            $self.applicable_ticks = [];

            var symbol = $self.symbol;
            var stream_url = window.location.protocol + '//' + page.settings.get('streaming_server');
            stream_url += "/stream/ticks/" + symbol + "/" + plot_from_moment.unix() + "/" + plot_to_moment.unix();
            $self.ev = new EventSource(stream_url, { withCredentials: true });

            $self.ev.onmessage = function(msg) {
                if ($self.applicable_ticks.length >= ticks_needed) {
                    $self.ev.close();
                    $self.evaluate_contract_outcome();
                    return;
                }

                var data = JSON.parse(msg.data);
                if (!(data[0] instanceof Array)) {
                    data = [ data ];
                }
                for (var i = 0; i < data.length; i++) {
                    if (data[i][0] === 'tick') {
                        var tick = {
                            epoch: parseInt(data[i][1]),
                            quote: parseFloat(data[i][2])
                        };
                        $self.chart.series[0].addPoint([tick.epoch*1000, tick.quote], true, false);

                        if (tick.epoch > contract_start_moment.unix()) {
                            $self.applicable_ticks.push(tick);

                            var tick_index = $self.applicable_ticks.length - 1;
                            var indicator_key = '_' + tick_index;

                            if (typeof $self.x_indicators[indicator_key] !== 'undefined') {
                                $self.x_indicators[indicator_key]['index'] = tick_index;
                                $self.add($self.x_indicators[indicator_key]);
                            }

                            $self.add_barrier();
                        }
                    }
                }
            };
            $self.ev.onerror = function(e) {$self.ev.close(); };
        },
        add_barrier: function() {
            var $self = this;

            if (!$self.set_barrier) {
                return;
            }

            var barrier_type = $self.contract_type.match('ASIAN') ? 'asian' : 'static';

            if (barrier_type === 'static') {
                var barrier_tick = $self.applicable_ticks[0];
                $self.chart.yAxis[0].addPlotLine({
                    id: 'tick-barrier',
                    value: barrier_tick.quote,
                    label: {text: 'Barrier ('+barrier_tick.quote+')', align: 'center'},
                    color: 'green',
                    width: 2,
                });
                $self.contract_barrier = barrier_tick.quote;
                $self.set_barrier = false;
            }

            if (barrier_type === 'asian') {
                var total = 0;
                for (var i=0; i < $self.applicable_ticks.length; i++) {
                    total += parseFloat($self.applicable_ticks[i].quote);
                }
                var calc_barrier =  total/$self.applicable_ticks.length;
                calc_barrier = calc_barrier.toFixed($self.number_of_decimal); // round calculated barrier

                $self.chart.yAxis[0].removePlotLine('tick-barrier');
                $self.chart.yAxis[0].addPlotLine({
                    id: 'tick-barrier',
                    value: calc_barrier,
                    color: 'green',
                    label: {
                        text: 'Average ('+calc_barrier+')',
                        align: 'center'
                    },
                    width: 2,
                });
                $self.contract_barrier = calc_barrier;
            }
        },
        add: function(indicator) {
            var $self = this;

            $self.chart.xAxis[0].addPlotLine({
               value: $self.applicable_ticks[indicator.index].epoch * 1000,
               id: indicator.id,
               label: {text: indicator.label},
               color: '#e98024',
               width: 2,
            });
        },
        evaluate_contract_outcome: function() {
            var $self = this;

            if (!$self.contract_barrier) {
                return; // can't do anything without barrier
            }

            var exit_tick_index = $self.applicable_ticks.length - 1;
            var exit_spot = $self.applicable_ticks[exit_tick_index].quote;

            if ($self.contract_sentiment === 'up') {
                if (exit_spot > $self.contract_barrier) {
                    $self.win();
                } else {
                    $self.lose();
                }
            } else if ($self.contract_sentiment === 'down') {
                if (exit_spot < $self.contract_barrier) {
                    $self.win();
                } else {
                    $self.lose();
                }
            }

        },
        win: function() {
            var $self = this;

            var profit = $self.payout - $self.price;
            $self.update_ui($self.payout, profit, 'This contract won');
        },
        lose: function() {
            var $self = this;
            $self.update_ui(0, -$self.price, 'This contract lost');
        },
        update_ui: function(final_price, pnl, contract_status) {
            var $self = this;

            $('#bet-confirm-header').text(text.localize(contract_status));
            $('#contract-outcome-buyprice').text($self.to_monetary_format($self.price));
            $('#contract-outcome-payout').text($self.to_monetary_format(final_price));

            if (pnl > 0) {
                $('#contract-outcome-label').text(text.localize('Profit'));
                $('#contract-outcome-profit').addClass('profit').text($self.to_monetary_format(pnl));
            } else {
                $('#contract-outcome-label').removeClass('standout').text(text.localize('Loss'));
                $('#contract-outcome-profit').addClass('loss').text($self.to_monetary_format(pnl));
            }
            $('#contract-confirmation-details').hide();
            $('#contract-outcome-details').show();
        },
        to_monetary_format: function(number) {
            return number.toFixed(2);
        }
    };
}();
<|endoftext|>