<commit_before>import WebGLSystem from '../WebGLSystem';
import { Rectangle, Matrix } from '../../../../math';
import VertexArrayObject from './VertexArrayObject';
import GLBuffer from './GLBuffer';
import setVertexAttribArrays from './setVertexAttribArrays';

const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };

/**
 * @class
 * @extends PIXI.WebGLSystem
 * @memberof PIXI
 */

export default class GeometrySystem extends WebGLSystem
{
    /**
     * @param {PIXI.WebGLRenderer} renderer - The renderer this System works for.
     */
    constructor(renderer)
    {
        super(renderer);

        this._activeGeometry = null;
        this._activeVao = null;

    }

    /**
     * Sets up the renderer context and necessary buffers.
     *
     * @private
     */
    contextChange()
    {
        this.gl = this.renderer.gl;
        this.CONTEXT_UID = this.renderer.CONTEXT_UID;
    }

    /**
     * Binds geometry so that is can be drawn. Creating a Vao if required
     * @private
     * @param {PIXI.mesh.Geometry} geometry instance of geometry to bind
     */
    bind(geometry, shader)
    {
        shader = shader || this.renderer.shader.shader;

        const gl = this.gl;

        // not sure the best way to address this..
        // currently different shaders require different VAOs for the same geometry
        // Still mulling over the best way to solve this one..
        // will likely need to modify the shader attribute locations at run time!
        let vaos = geometry.glVertexArrayObjects[this.CONTEXT_UID];

        if(!vaos)
        {
            vaos = geometry.glVertexArrayObjects[this.CONTEXT_UID] = {};
        }

        const vao = vaos[shader.program.id] || this.initGeometryVao(geometry, shader.program);

        this._activeGeometry = geometry;

        if(this._activeVao !== vao)
        {
            this._activeVao = vao;
            gl.bindVertexArray(vao);
        }

        // TODO - optimise later!
        // don't need to loop through if nothing changed!
        // maybe look to add an 'autoupdate' to geometry?
        this.updateBuffers();

    }

    updateBuffers()
    {
        const geometry = this._activeGeometry;
        const gl = this.gl;

        for (let i = 0; i < geometry.buffers.length; i++)
        {
            const buffer = geometry.buffers[i];

            const glBuffer = buffer._glBuffers[this.CONTEXT_UID];

            if (buffer._updateID !== glBuffer._updateID)
            {
                glBuffer._updateID = buffer._updateID;

                // can cache this on buffer! maybe added a getter / setter?
                const type = buffer.index ? gl.ELEMENT_ARRAY_BUFFER : gl.ARRAY_BUFFER;
                const drawType = buffer.static ? gl.STATIC_DRAW : gl.DYNAMIC_DRAW;

                gl.bindBuffer(type, glBuffer.buffer);

                if(glBuffer.byteLength >= buffer.data.byteLength)
                {
                    // offset is always zero for now!
                    gl.bufferSubData(type, 0, buffer.data);
                }
                else
                {
                    gl.bufferData(type, buffer.data, drawType);
                }

            }
        }
    }

    checkCompatability(geometry, program)
    {
        // geometry must have at least all the attributes that the shader requires.
        const geometryAttributes = geometry.attributes;
        const shaderAttributes = program.attributeData;

        for (const j in shaderAttributes)
        {
            if(!geometryAttributes[j])
            {
                throw new Error('shader and geometry incompatible, geometry missing the "' + j + '" attribute');
            }
        }
    }

    /**
     * Creates a Vao with the same structure as the geometry and stores it on the geometry.
     * @private
     * @param {PIXI.mesh.Geometry} geometry instance of geometry to to generate Vao for
     * @return {PIXI.VertexArrayObject} Returns a fresh vao.
     */
    initGeometryVao(geometry, program)
    {
        this.checkCompatability(geometry, program);

        const gl = this.gl;
        const CONTEXT_UID = this.CONTEXT_UID;
        const buffers = geometry.buffers;
        const attributes = geometry.attributes;

        // first update - and create the buffers!
        for (let i = 0; i < buffers.length; i++)
        {
            const buffer = buffers[i];

            if (!buffer._glBuffers[CONTEXT_UID])
            {
                buffer._glBuffers[CONTEXT_UID] = new GLBufferData(gl.createBuffer());
            }
        }

        const tempStride = {};
        const tempStart = {};

        for (const j in buffers)
        {
            tempStride[j] = 0;
            tempStart[j] = 0;
        }

        for (const j in attributes)
        {
            if(!attributes[j].size && program.attributeData[j])
            {
                attributes[j].size = program.attributeData[j].size;
            }

            tempStride[attributes[j].buffer] += attributes[j].size * byteSizeMap[attributes[j].type];
        }

        for (const j in attributes)
        {
            const attribute = attributes[j];
            const attribSize = attribute.size;

            // must be careful that the geometry has attributes not used by this shader..

            if (attribute.stride === undefined)
            {
                if (tempStride[attribute.buffer] === attribSize * byteSizeMap[attribute.type])
                {
                    attribute.stride = 0;
                }
                else
                {
                    attribute.stride = tempStride[attribute.buffer];
                }
            }

            if (attribute.start === undefined)
            {
                attribute.start = tempStart[attribute.buffer];

                tempStart[attribute.buffer] += attribSize * byteSizeMap[attribute.type];
            }
        }

        const vao = gl.createVertexArray();

        gl.bindVertexArray(vao);

        if (geometry.indexBuffer)
        {
            // first update the index buffer if we have one..
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, geometry.indexBuffer._glBuffers[CONTEXT_UID].buffer);
        }

        let lastBuffer = null;

        // add a new one!
        for (const j in attributes)
        {
            const attribute = attributes[j];
            const buffer = buffers[attribute.buffer];
            const glBuffer = buffer._glBuffers[CONTEXT_UID];

            if(program.attributeData[j])
            {
                if(lastBuffer !== glBuffer)
                {
                    gl.bindBuffer(gl.ARRAY_BUFFER, glBuffer.buffer);

                    lastBuffer = glBuffer;
                }

                const location = program.attributeData[j].location;

                gl.enableVertexAttribArray(location);

                gl.vertexAttribPointer(location,
                                       attribute.size,
                                       attribute.type || gl.FLOAT,
                                       attribute.normalized,
                                       attribute.stride,
                                       attribute.start);

                if(attribute.instance)
                {
                    gl.vertexAttribDivisor(location, 1);
                }
            }
        }

        // TODO - maybe make this a data object?
        // lets wait to see if we need to first!
        geometry.glVertexArrayObjects[CONTEXT_UID][program.id] = vao;

        gl.bindVertexArray(null);

        return vao;
    }

    draw(type, size, start, instanceCount)
    {
        const gl = this.gl;
        const geometry = this._activeGeometry;

        //TODO.. this should not change so maybe cache the function?

        if(geometry.indexBuffer)
        {
            if(geometry.instanced)
            {
                gl.drawElementsInstanced(type, size || geometry.indexBuffer.data.length, gl.UNSIGNED_SHORT, (start || 0) * 2, instanceCount || 1);
            }
            else
            {
                gl.drawElements(type, size || geometry.indexBuffer.data.length, gl.UNSIGNED_SHORT, (start || 0) * 2 );
            }
        }
        else
        {
            if(geometry.instanced)
            {
                // TODO need a better way to calculate size..
                gl.drawArrayInstanced(type, start, size || geometry.getSize(), instanceCount || 1);
            }
            else
            {
                gl.drawArrays(type, start, size || geometry.getSize());
            }
        }

        return this;
    }

    /**
     * Creates a new VAO from this renderer's context and state.
     *
     * @return {VertexArrayObject} The new VAO.
     */
    createVao()
    {
        return new VertexArrayObject(this.gl, this.renderer.state.attribState);
    }

    /**
     * Changes the current Vao to the one given in parameter
     *
     * @param {PIXI.VertexArrayObject} vao - the new Vao
     * @return {PIXI.WebGLRenderer} Returns itself.
     */
    bindVao(vao)
    {
    }
}

class GLBufferData
{
    constructor(buffer)
    {
        this.buffer = buffer;
        this.updateID = -1;
        this.byteLength = -1;
    }
}
<commit_msg>Added webgl 1 and no VAO fallbacks<commit_after>import WebGLSystem from '../WebGLSystem';
import { Rectangle, Matrix } from '../../../../math';
import VertexArrayObject from './VertexArrayObject';
import GLBuffer from './GLBuffer';
import setVertexAttribArrays from './setVertexAttribArrays';

const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };

/**
 * @class
 * @extends PIXI.WebGLSystem
 * @memberof PIXI
 */

export default class GeometrySystem extends WebGLSystem
{
    /**
     * @param {PIXI.WebGLRenderer} renderer - The renderer this System works for.
     */
    constructor(renderer)
    {
        super(renderer);

        this._activeGeometry = null;
        this._activeVao = null;

        this.hasVao = true;
    }

    /**
     * Sets up the renderer context and necessary buffers.
     *
     * @private
     */
    contextChange()
    {
        const gl = this.gl = this.renderer.gl;
        this.CONTEXT_UID = this.renderer.CONTEXT_UID;

        if(!gl.createVertexArray)
        {
            // webgl 1!
            const nativeVaoExtension = gl.getExtension('OES_vertex_array_object') ||
                                  gl.getExtension('MOZ_OES_vertex_array_object') ||
                                  gl.getExtension('WEBKIT_OES_vertex_array_object');

            if(nativeVaoExtension)
            {
                gl.createVertexArray = nativeVaoExtension.createVertexArrayOES;
                gl.bindVertexArray = nativeVaoExtension.bindVertexArrayOES;
                gl.deleteVertexArray = nativeVaoExtension.deleteVertexArrayOES;
            }
            else
            {
                this.hasVao = false;
                gl.createVertexArray = ()=>{return {}}
                gl.bindVertexArray = ()=>{}
                gl.deleteVertexArray = ()=>{}
            }
        }
    }

    /**
     * Binds geometry so that is can be drawn. Creating a Vao if required
     * @private
     * @param {PIXI.mesh.Geometry} geometry instance of geometry to bind
     */
    bind(geometry, shader)
    {
        shader = shader || this.renderer.shader.shader;

        const gl = this.gl;

        // not sure the best way to address this..
        // currently different shaders require different VAOs for the same geometry
        // Still mulling over the best way to solve this one..
        // will likely need to modify the shader attribute locations at run time!
        let vaos = geometry.glVertexArrayObjects[this.CONTEXT_UID];

        if(!vaos)
        {
            vaos = geometry.glVertexArrayObjects[this.CONTEXT_UID] = {};
        }

        const vao = vaos[shader.program.id] || this.initGeometryVao(geometry, shader.program);

        this._activeGeometry = geometry;

        if(this._activeVao !== vao)
        {
            this._activeVao = vao;

            if(this.hasVao)
            {
                gl.bindVertexArray(vao);
            }
            else
            {
                this.activateVao(geometry, shader.program);
            }
        }

        // TODO - optimise later!
        // don't need to loop through if nothing changed!
        // maybe look to add an 'autoupdate' to geometry?
        this.updateBuffers();

    }

    updateBuffers()
    {
        const geometry = this._activeGeometry;
        const gl = this.gl;

        for (let i = 0; i < geometry.buffers.length; i++)
        {
            const buffer = geometry.buffers[i];

            const glBuffer = buffer._glBuffers[this.CONTEXT_UID];

            if (buffer._updateID !== glBuffer._updateID)
            {
                glBuffer._updateID = buffer._updateID;

                // TODO can cache this on buffer! maybe added a getter / setter?
                const type = buffer.index ? gl.ELEMENT_ARRAY_BUFFER : gl.ARRAY_BUFFER;
                const drawType = buffer.static ? gl.STATIC_DRAW : gl.DYNAMIC_DRAW;

                gl.bindBuffer(type, glBuffer.buffer);

                if(glBuffer.byteLength >= buffer.data.byteLength)
                {
                    // offset is always zero for now!
                    gl.bufferSubData(type, 0, buffer.data);
                }
                else
                {
                    gl.bufferData(type, buffer.data, drawType);
                }

            }
        }
    }

    checkCompatability(geometry, program)
    {
        // geometry must have at least all the attributes that the shader requires.
        const geometryAttributes = geometry.attributes;
        const shaderAttributes = program.attributeData;

        for (const j in shaderAttributes)
        {
            if(!geometryAttributes[j])
            {
                throw new Error('shader and geometry incompatible, geometry missing the "' + j + '" attribute');
            }
        }
    }

    /**
     * Creates a Vao with the same structure as the geometry and stores it on the geometry.
     * @private
     * @param {PIXI.mesh.Geometry} geometry instance of geometry to to generate Vao for
     * @return {PIXI.VertexArrayObject} Returns a fresh vao.
     */
    initGeometryVao(geometry, program)
    {
        this.checkCompatability(geometry, program);

        const gl = this.gl;
        const CONTEXT_UID = this.CONTEXT_UID;
        const buffers = geometry.buffers;
        const attributes = geometry.attributes;

        // first update - and create the buffers!
        for (let i = 0; i < buffers.length; i++)
        {
            const buffer = buffers[i];

            if (!buffer._glBuffers[CONTEXT_UID])
            {
                buffer._glBuffers[CONTEXT_UID] = new GLBufferData(gl.createBuffer());
            }
        }

        const tempStride = {};
        const tempStart = {};

        for (const j in buffers)
        {
            tempStride[j] = 0;
            tempStart[j] = 0;
        }

        for (const j in attributes)
        {
            if(!attributes[j].size && program.attributeData[j])
            {
                attributes[j].size = program.attributeData[j].size;
            }

            tempStride[attributes[j].buffer] += attributes[j].size * byteSizeMap[attributes[j].type];
        }

        for (const j in attributes)
        {
            const attribute = attributes[j];
            const attribSize = attribute.size;

            // must be careful that the geometry has attributes not used by this shader..

            if (attribute.stride === undefined)
            {
                if (tempStride[attribute.buffer] === attribSize * byteSizeMap[attribute.type])
                {
                    attribute.stride = 0;
                }
                else
                {
                    attribute.stride = tempStride[attribute.buffer];
                }
            }

            if (attribute.start === undefined)
            {
                attribute.start = tempStart[attribute.buffer];

                tempStart[attribute.buffer] += attribSize * byteSizeMap[attribute.type];
            }
        }

        // TODO - maybe make this a data object?
        // lets wait to see if we need to first!
        const vao = gl.createVertexArray();

        gl.bindVertexArray(vao);

        this.activateVao(geometry, program);

        gl.bindVertexArray(null);

        geometry.glVertexArrayObjects[CONTEXT_UID][program.id] = vao;

    }

    activateVao(geometry, program)
    {
        const gl = this.gl;
        const CONTEXT_UID = this.CONTEXT_UID;
        const buffers = geometry.buffers;
        const attributes = geometry.attributes;

        if (geometry.indexBuffer)
        {
            // first update the index buffer if we have one..
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, geometry.indexBuffer._glBuffers[CONTEXT_UID].buffer);
        }

        let lastBuffer = null;

        // add a new one!
        for (const j in attributes)
        {
            const attribute = attributes[j];
            const buffer = buffers[attribute.buffer];
            const glBuffer = buffer._glBuffers[CONTEXT_UID];

            if(program.attributeData[j])
            {
                if(lastBuffer !== glBuffer)
                {
                    gl.bindBuffer(gl.ARRAY_BUFFER, glBuffer.buffer);

                    lastBuffer = glBuffer;
                }

                const location = program.attributeData[j].location;

                gl.enableVertexAttribArray(location);

                gl.vertexAttribPointer(location,
                                       attribute.size,
                                       attribute.type || gl.FLOAT,
                                       attribute.normalized,
                                       attribute.stride,
                                       attribute.start);

                if(attribute.instance)
                {
                    gl.vertexAttribDivisor(location, 1);
                }
            }
        }
    }

    draw(type, size, start, instanceCount)
    {
        const gl = this.gl;
        const geometry = this._activeGeometry;

        //TODO.. this should not change so maybe cache the function?

        if(geometry.indexBuffer)
        {
            if(geometry.instanced)
            {
                gl.drawElementsInstanced(type, size || geometry.indexBuffer.data.length, gl.UNSIGNED_SHORT, (start || 0) * 2, instanceCount || 1);
            }
            else
            {
                gl.drawElements(type, size || geometry.indexBuffer.data.length, gl.UNSIGNED_SHORT, (start || 0) * 2 );
            }
        }
        else
        {
            if(geometry.instanced)
            {
                // TODO need a better way to calculate size..
                gl.drawArrayInstanced(type, start, size || geometry.getSize(), instanceCount || 1);
            }
            else
            {
                gl.drawArrays(type, start, size || geometry.getSize());
            }
        }

        return this;
    }

    /**
     * Creates a new VAO from this renderer's context and state.
     *
     * @return {VertexArrayObject} The new VAO.
     */
    createVao()
    {
        return new VertexArrayObject(this.gl, this.renderer.state.attribState);
    }

    /**
     * Changes the current Vao to the one given in parameter
     *
     * @param {PIXI.VertexArrayObject} vao - the new Vao
     * @return {PIXI.WebGLRenderer} Returns itself.
     */
    bindVao(vao)
    {
    }
}

class GLBufferData
{
    constructor(buffer)
    {
        this.buffer = buffer;
        this.updateID = -1;
        this.byteLength = -1;
    }
}
<|endoftext|>


<commit_before>/**
 * Created by quasarchimaere on 20.11.2018.
 */
import won from "../won-es6.js";
import angular from "angular";
import ngAnimate from "angular-animate";
import dropdownModule from "./covering-dropdown.js";
import { attach, delay, getIn, get } from "../utils.js";
import { actionCreators } from "../actions/actions.js";
import { connect2Redux, parseRestErrorMessage } from "../won-utils.js";

import * as srefUtils from "../sref-utils.js";

import "style/_slidein.scss";

function genSlideInConf() {
  let template = `

            <svg class="si__icon" style="--local-primary:white;">
                <use xlink:href="#ico16_indicator_warning" href="#ico16_indicator_warning"></use>
            </svg>

                Lost connection – make sure your internet-connection
                is working, then click “reconnect”.

            <button
                ng-show="self.connectionHasBeenLost && !self.reconnecting"
                ng-click="self.reconnect__start()"
                class="si__button">
                    Reconnect
            </button>

            <svg class="hspinner" ng-show="self.reconnecting">
                <use xlink:href="#ico_loading_anim" href="#ico_loading_anim"></use>
            </svg>

            <svg class="si__icon" style="--local-primary:white;">
                <use xlink:href="#ico16_indicator_warning" href="#ico16_indicator_warning"></use>
            </svg>

                E-Mail has not been verified yet, check your Inbox.

                Verifying the E-Mail address

                {{ self.parseRestErrorMessage(self.emailVerificationError) }}

                E-Mail Address verified

                E-Mail Address verified (Please Login Now)

            <svg class="hspinner" ng-if="self.processingVerifyEmailAddress || self.processingResendVerificationEmail">
                <use xlink:href="#ico_loading_anim" href="#ico_loading_anim"></use>
            </svg>
            <button
              class="si__button"
              ng-if="!self.processingVerifyEmailAddress && !self.processingResendVerificationMail && ((self.loggedIn && !self.emailVerified && !self.emailVerificationError) || (self.verificationToken && self.emailVerificationError))"
              ng-click="self.account__resendVerificationEmail(self.email)">
                Resend Email
            </button>
            <svg class="si__close"
                style="--local-primary:white;"
                ng-click="self.router__stateGoCurrent({token: undefined})"
                ng-if="!self.processingVerifyEmailAddress && self.verificationToken && !self.emailVerificationError">
                <use xlink:href="#ico36_close" href="#ico36_close"></use>
            </svg>
            <svg class="si__close"
                style="--local-primary:white;"
                ng-click="self.account__verifyEmailAddressSuccess()"
                ng-if="!self.processingVerifyEmailAddress && self.isAlreadyVerifiedError()">
                <use xlink:href="#ico36_close" href="#ico36_close"></use>
            </svg>

            <svg class="si__icon" style="--local-primary:white;">
                <use xlink:href="#ico16_indicator_warning" href="#ico16_indicator_warning"></use>
            </svg>

                You have not accepted the

                   Terms Of Service
                  yet.

            <button
              class="si__button"
              ng-if="!self.processingAcceptTermsOfService"
              ng-click="self.account__acceptTermsOfService()">
                Accept
            </button>
            <svg class="hspinner" ng-if="self.processingAcceptTermsOfService">
                <use xlink:href="#ico_loading_anim" href="#ico_loading_anim"></use>
            </svg>

            <svg class="si__icon" style="--local-primary:white;">
                <use xlink:href="#ico16_indicator_warning" href="#ico16_indicator_info"></use>
            </svg>

                This is the demonstrator of an ongoing research project. Please keep in mind:

 Your posts are public.

 Your user account is not publicly linked to your posts.

 The connections of your posts are public.

 The messages you exchange with others are private, but stored in clear text on our servers.

                   See Privacy Policy.

                We use cookies to track your session using a self-hosted analytics tool.

                   Suppress tracking.

            <button
                ng-click="self.account__acceptDisclaimer()"
                class="si__smallbutton">
                    Ok, I'll keep that in mind
            </button>

    `;

  const serviceDependencies = [
    "$ngRedux",
    "$scope",
    "$state" /*injections as strings here*/,
  ];

  class Controller {
    constructor(/* arguments <- serviceDependencies */) {
      attach(this, serviceDependencies, arguments);
      Object.assign(this, srefUtils); // bind srefUtils to scope
      this.parseRestErrorMessage = parseRestErrorMessage;

      const selectFromState = state => {
        const verificationToken = getIn(state, [
          "router",
          "currentParams",
          "token",
        ]);

        return {
          verificationToken,
          acceptedDisclaimer: getIn(state, ["account", "acceptedDisclaimer"]),
          emailVerified: getIn(state, ["account", "emailVerified"]),
          emailVerificationError: getIn(state, [
            "account",
            "emailVerificationError",
          ]),
          processingVerifyEmailAddress: getIn(state, [
            "process",
            "processingVerifyEmailAddress",
          ]),
          processingAcceptTermsOfService: getIn(state, [
            "process",
            "processingAcceptTermsOfService",
          ]),
          processingResendVerificationEmail: getIn(state, [
            "process",
            "processingResendVerificationEmail",
          ]),
          acceptedTermsOfService: getIn(state, [
            "account",
            "acceptedTermsOfService",
          ]),
          loggedIn: getIn(state, ["account", "loggedIn"]),
          email: getIn(state, ["account", "email"]),
          connectionHasBeenLost: getIn(state, ["messages", "lostConnection"]), // name chosen to avoid name-clash with the action-creator
          reconnecting: getIn(state, ["messages", "reconnecting"]),
        };
      };

      connect2Redux(selectFromState, actionCreators, [], this);

      this.$scope.$watch("self.verificationToken", verificationToken =>
        this.verifyEmailAddress(verificationToken)
      );
    }

    isAlreadyVerifiedError() {
      return (
        get(this.emailVerificationError, "code") ==
        won.RESPONSECODE.TOKEN_RESEND_FAILED_ALREADY_VERIFIED
      );
    }

    verifyEmailAddress(verificationToken) {
      delay(0).then(() => {
        if (
          verificationToken &&
          !this.processingVerifyEmailAddress &&
          !(this.emailVerified || this.emailVerificationError)
        ) {
          this.account__verifyEmailAddress(verificationToken);
        }
      });
    }
  }
  Controller.$inject = serviceDependencies;

  return {
    restrict: "E",
    scope: {}, //isolate scope to allow usage within other controllers/components
    controller: Controller,
    controllerAs: "self",
    bindToController: true, //scope-bindings -> ctrl
    template: template,
  };
}

export default angular
  .module("won.owner.components.slideIn", [dropdownModule, ngAnimate])
  .directive("wonSlideIn", genSlideInConf).name;
<commit_msg>Moves the isAlreadyVerifiedError from a function to state<commit_after>/**
 * Created by quasarchimaere on 20.11.2018.
 */
import won from "../won-es6.js";
import angular from "angular";
import ngAnimate from "angular-animate";
import dropdownModule from "./covering-dropdown.js";
import { attach, delay, getIn } from "../utils.js";
import { actionCreators } from "../actions/actions.js";
import { connect2Redux, parseRestErrorMessage } from "../won-utils.js";

import * as srefUtils from "../sref-utils.js";

import "style/_slidein.scss";

function genSlideInConf() {
  let template = `

            <svg class="si__icon" style="--local-primary:white;">
                <use xlink:href="#ico16_indicator_warning" href="#ico16_indicator_warning"></use>
            </svg>

                Lost connection – make sure your internet-connection
                is working, then click “reconnect”.

            <button
                ng-show="self.connectionHasBeenLost && !self.reconnecting"
                ng-click="self.reconnect__start()"
                class="si__button">
                    Reconnect
            </button>

            <svg class="hspinner" ng-show="self.reconnecting">
                <use xlink:href="#ico_loading_anim" href="#ico_loading_anim"></use>
            </svg>

            <svg class="si__icon" style="--local-primary:white;">
                <use xlink:href="#ico16_indicator_warning" href="#ico16_indicator_warning"></use>
            </svg>

                E-Mail has not been verified yet, check your Inbox.

                Verifying the E-Mail address

                {{ self.parseRestErrorMessage(self.emailVerificationError) }}

                E-Mail Address verified

                E-Mail Address verified (Please Login Now)

            <svg class="hspinner" ng-if="self.processingVerifyEmailAddress || self.processingResendVerificationEmail">
                <use xlink:href="#ico_loading_anim" href="#ico_loading_anim"></use>
            </svg>
            <button
              class="si__button"
              ng-if="!self.processingVerifyEmailAddress && !self.processingResendVerificationMail && ((self.loggedIn && !self.emailVerified && !self.emailVerificationError) || (self.verificationToken && self.emailVerificationError))"
              ng-click="self.account__resendVerificationEmail(self.email)">
                Resend Email
            </button>
            <svg class="si__close"
                style="--local-primary:white;"
                ng-click="self.router__stateGoCurrent({token: undefined})"
                ng-if="!self.processingVerifyEmailAddress && self.verificationToken && !self.emailVerificationError">
                <use xlink:href="#ico36_close" href="#ico36_close"></use>
            </svg>
            <svg class="si__close"
                style="--local-primary:white;"
                ng-click="self.account__verifyEmailAddressSuccess()"
                ng-if="!self.processingVerifyEmailAddress && self.isAlreadyVerifiedError">
                <use xlink:href="#ico36_close" href="#ico36_close"></use>
            </svg>

            <svg class="si__icon" style="--local-primary:white;">
                <use xlink:href="#ico16_indicator_warning" href="#ico16_indicator_warning"></use>
            </svg>

                You have not accepted the

                   Terms Of Service
                  yet.

            <button
              class="si__button"
              ng-if="!self.processingAcceptTermsOfService"
              ng-click="self.account__acceptTermsOfService()">
                Accept
            </button>
            <svg class="hspinner" ng-if="self.processingAcceptTermsOfService">
                <use xlink:href="#ico_loading_anim" href="#ico_loading_anim"></use>
            </svg>

            <svg class="si__icon" style="--local-primary:white;">
                <use xlink:href="#ico16_indicator_warning" href="#ico16_indicator_info"></use>
            </svg>

                This is the demonstrator of an ongoing research project. Please keep in mind:

 Your posts are public.

 Your user account is not publicly linked to your posts.

 The connections of your posts are public.

 The messages you exchange with others are private, but stored in clear text on our servers.

                   See Privacy Policy.

                We use cookies to track your session using a self-hosted analytics tool.

                   Suppress tracking.

            <button
                ng-click="self.account__acceptDisclaimer()"
                class="si__smallbutton">
                    Ok, I'll keep that in mind
            </button>

    `;

  const serviceDependencies = [
    "$ngRedux",
    "$scope",
    "$state" /*injections as strings here*/,
  ];

  class Controller {
    constructor(/* arguments <- serviceDependencies */) {
      attach(this, serviceDependencies, arguments);
      Object.assign(this, srefUtils); // bind srefUtils to scope
      this.parseRestErrorMessage = parseRestErrorMessage;

      const selectFromState = state => {
        const verificationToken = getIn(state, [
          "router",
          "currentParams",
          "token",
        ]);

        return {
          verificationToken,
          acceptedDisclaimer: getIn(state, ["account", "acceptedDisclaimer"]),
          emailVerified: getIn(state, ["account", "emailVerified"]),
          emailVerificationError: getIn(state, [
            "account",
            "emailVerificationError",
          ]),
          processingVerifyEmailAddress: getIn(state, [
            "process",
            "processingVerifyEmailAddress",
          ]),
          processingAcceptTermsOfService: getIn(state, [
            "process",
            "processingAcceptTermsOfService",
          ]),
          processingResendVerificationEmail: getIn(state, [
            "process",
            "processingResendVerificationEmail",
          ]),
          acceptedTermsOfService: getIn(state, [
            "account",
            "acceptedTermsOfService",
          ]),
          loggedIn: getIn(state, ["account", "loggedIn"]),
          email: getIn(state, ["account", "email"]),
          connectionHasBeenLost: getIn(state, ["messages", "lostConnection"]), // name chosen to avoid name-clash with the action-creator
          reconnecting: getIn(state, ["messages", "reconnecting"]),
          isAlreadyVerifiedError:
            getIn(state, ["account", "emailVerificationError", "code"]) ==
            won.RESPONSECODE.TOKEN_RESEND_FAILED_ALREADY_VERIFIED,
        };
      };

      connect2Redux(selectFromState, actionCreators, [], this);

      this.$scope.$watch("self.verificationToken", verificationToken =>
        this.verifyEmailAddress(verificationToken)
      );
    }

    verifyEmailAddress(verificationToken) {
      delay(0).then(() => {
        if (
          verificationToken &&
          !this.processingVerifyEmailAddress &&
          !(this.emailVerified || this.emailVerificationError)
        ) {
          this.account__verifyEmailAddress(verificationToken);
        }
      });
    }
  }
  Controller.$inject = serviceDependencies;

  return {
    restrict: "E",
    scope: {}, //isolate scope to allow usage within other controllers/components
    controller: Controller,
    controllerAs: "self",
    bindToController: true, //scope-bindings -> ctrl
    template: template,
  };
}

export default angular
  .module("won.owner.components.slideIn", [dropdownModule, ngAnimate])
  .directive("wonSlideIn", genSlideInConf).name;
<|endoftext|>


<commit_before>var booleanFromEnv = require('./config/booleanFromEnv')
var flattenBrowser = require('zuul/lib/flatten_browser')
var request = require('sync-request')
var assign = require('lodash').assign

// copied from https://github.com/defunctzombie/zuul/blob/18e1a674f54b7d131b5e5ff82b2a6a75a49ec0c4/lib/scout_browser.js#L42-L56
function format (obj) {
  var browsers = {}
  obj.forEach(function (info) {
    var name = info.api_name

    var browser = browsers[name] = browsers[name] || []
    browser.push({
      name: name,
      version: info.short_version,
      platform: info.os
    })
  })

  return browsers
}

function queryBrowsers (query, optionalKeys) {
  var res = request('GET', 'https://saucelabs.com/rest/v1/info/browsers/webdriver')
  var allBrowsers = JSON.parse(res.getBody('utf8'))
  var chosenBrowsers = flattenBrowser(query, format(allBrowsers))
  chosenBrowsers.map(function (browser) {
    browser.browserName = browser.name
    delete browser.name
    assign(browser, optionalKeys)
  })
  return chosenBrowsers
}

require('babel/register')({
  experimental: true,
  blacklist: [
    'regenerator'
  ]
})

var config = {
  //
  // ==================
  // Specify Test Files
  // ==================
  // Define which test specs should run. The pattern is relative to the location of this
  // file.
  //
  specs: [
    './test/**/*.js'
  ],
  // Patterns to exclude.
  exclude: [
    // 'path/to/excluded/files'
  ],
  //
  // ============
  // Capabilities
  // ============
  // Define your capabilities here. WebdriverIO can run multiple capabilties at the same
  // time. Depending on the number of capabilities WebdriverIO launches several test
  // sessions. Within your capabilities you can overwrite the spec and exclude option in
  // order to group specific specs to a specific capability.
  //
  // If you have trouble getting all important capabilities together check out Sauce Labs
  // platform configurator. A great tool to configure your capabilities.
  // https://docs.saucelabs.com/reference/platforms-configurator
  //
  capabilities: [{
    browserName: 'chrome'
    // platform: 'MAC',
    // chromeOptions: {
      // binary: require('expand-home-dir')('~') + '/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary'
    // }
  }
  // {
  //   browserName: 'phantomjs'
  // }
  ],
  //
  // ===================
  // Test Configurations
  // ===================
  // Define all options that are relevant for the WebdriverIO instance here
  //
  // Level of logging verbosity.
  logLevel: 'silent',
  //
  // Enables colors for log output
  coloredLogs: true,
  //
  // Saves a screenshot to a given path if a command fails.
  screenshotPath: './errorShots/',

  //
  // Default timeout for all waitForXXX commands.
  waitforTimeout: 1000,
  //
  // Initialise the browser instance with a WebdriverIO plugin. The object should have the
  // plugin name as key and the desired plugin options as property. Make sure you have
  // the plugin installed before running any tests. The following plugins are currently
  // available:
  // WebdriverCSS: https://github.com/webdriverio/webdrivercss
  // WebdriverRTC: https://github.com/webdriverio/webdriverrtc
  // Browserevent: https://github.com/webdriverio/browserevent
  // plugins: {
  //     webdrivercss: {
  //         screenshotRoot: 'my-shots',
  //         failedComparisonsRoot: 'diffs',
  //         misMatchTolerance: 0.05,
  //         screenWidth: [320,480,640,1024]
  //     },
  //     webdriverrtc: {},
  //     browserevent: {}
  // },
  //
  // Framework you want to run your specs with.
  // The following are supported: mocha, jasmine and cucumber
  // see also: http://webdriver.io/guide/testrunner/frameworks.html
  //
  // Make sure you have the node package for the specific framework installed before running
  // any tests. If not please install the following package:
  // Mocha: `$ npm install mocha`
  // Jasmine: `$ npm install jasmine`
  // Cucumber: `$ npm install cucumber`
  framework: 'mocha',
  //
  // Test reporter for stdout.
  // The following are supported: dot (default), spec and xunit
  // see also: http://webdriver.io/guide/testrunner/reporters.html
  reporter: 'spec',

  //
  // Options to be passed to Mocha.
  // See the full list at http://mochajs.org/
  mochaOpts: {
    ui: 'bdd'
    // 'check-leaks': true,
    // bail: true
  },

  // Shorten url command calls by setting a base url. If your url parameter starts with '/'
  // the base url gets prepended.
  baseUrl: 'http://localhost:5050'
}

if (booleanFromEnv('WDIO_SAUCELABS', false)) {
  //
  // =================
  // Service Providers
  // =================
  // WebdriverIO supports Sauce Labs, Browserstack and Testing Bot (other cloud providers
  // should work too though). These services define specific user and key (or access key)
  // values you need to put in here in order to connect to these services.
  //
  config.user = process.env.SAUCE_USERNAME
  config.key = process.env.SAUCE_ACCESS_KEY

  //
  // If you are using Sauce Labs WebdriverIO takes care about updating the job information
  // once the test is done. This option is set to `true` per default.
  //
  config.updateJob = true
  // delete config.reporter

  config.capabilities = queryBrowsers([
    // {name: 'internet explorer', version: '10..latest'},
    // {name: 'firefox', version: '38..latest'},
    {name: 'chrome', version: 'latest'},
    // {name: 'safari', version: '8..latest'},
    // {name: 'iphone', version: '8.4..latest'}
  ], {
    'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,
    'idle-timeout': 900,
    name: 'lucibus/caido',
    build: process.env.TRAVIS_BUILD_NUMBER
  })
}

exports.config = config
<commit_msg>caido: fix lint<commit_after>var booleanFromEnv = require('./config/booleanFromEnv')
var flattenBrowser = require('zuul/lib/flatten_browser')
var request = require('sync-request')
var assign = require('lodash').assign

// copied from https://github.com/defunctzombie/zuul/blob/18e1a674f54b7d131b5e5ff82b2a6a75a49ec0c4/lib/scout_browser.js#L42-L56
function format (obj) {
  var browsers = {}
  obj.forEach(function (info) {
    var name = info.api_name

    var browser = browsers[name] = browsers[name] || []
    browser.push({
      name: name,
      version: info.short_version,
      platform: info.os
    })
  })

  return browsers
}

function queryBrowsers (query, optionalKeys) {
  var res = request('GET', 'https://saucelabs.com/rest/v1/info/browsers/webdriver')
  var allBrowsers = JSON.parse(res.getBody('utf8'))
  var chosenBrowsers = flattenBrowser(query, format(allBrowsers))
  chosenBrowsers.map(function (browser) {
    browser.browserName = browser.name
    delete browser.name
    assign(browser, optionalKeys)
  })
  return chosenBrowsers
}

require('babel/register')({
  experimental: true,
  blacklist: [
    'regenerator'
  ]
})

var config = {
  //
  // ==================
  // Specify Test Files
  // ==================
  // Define which test specs should run. The pattern is relative to the location of this
  // file.
  //
  specs: [
    './test/**/*.js'
  ],
  // Patterns to exclude.
  exclude: [
    // 'path/to/excluded/files'
  ],
  //
  // ============
  // Capabilities
  // ============
  // Define your capabilities here. WebdriverIO can run multiple capabilties at the same
  // time. Depending on the number of capabilities WebdriverIO launches several test
  // sessions. Within your capabilities you can overwrite the spec and exclude option in
  // order to group specific specs to a specific capability.
  //
  // If you have trouble getting all important capabilities together check out Sauce Labs
  // platform configurator. A great tool to configure your capabilities.
  // https://docs.saucelabs.com/reference/platforms-configurator
  //
  capabilities: [{
    browserName: 'chrome'
    // platform: 'MAC',
    // chromeOptions: {
      // binary: require('expand-home-dir')('~') + '/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary'
    // }
  }
  // {
  //   browserName: 'phantomjs'
  // }
  ],
  //
  // ===================
  // Test Configurations
  // ===================
  // Define all options that are relevant for the WebdriverIO instance here
  //
  // Level of logging verbosity.
  logLevel: 'silent',
  //
  // Enables colors for log output
  coloredLogs: true,
  //
  // Saves a screenshot to a given path if a command fails.
  screenshotPath: './errorShots/',

  //
  // Default timeout for all waitForXXX commands.
  waitforTimeout: 1000,
  //
  // Initialise the browser instance with a WebdriverIO plugin. The object should have the
  // plugin name as key and the desired plugin options as property. Make sure you have
  // the plugin installed before running any tests. The following plugins are currently
  // available:
  // WebdriverCSS: https://github.com/webdriverio/webdrivercss
  // WebdriverRTC: https://github.com/webdriverio/webdriverrtc
  // Browserevent: https://github.com/webdriverio/browserevent
  // plugins: {
  //     webdrivercss: {
  //         screenshotRoot: 'my-shots',
  //         failedComparisonsRoot: 'diffs',
  //         misMatchTolerance: 0.05,
  //         screenWidth: [320,480,640,1024]
  //     },
  //     webdriverrtc: {},
  //     browserevent: {}
  // },
  //
  // Framework you want to run your specs with.
  // The following are supported: mocha, jasmine and cucumber
  // see also: http://webdriver.io/guide/testrunner/frameworks.html
  //
  // Make sure you have the node package for the specific framework installed before running
  // any tests. If not please install the following package:
  // Mocha: `$ npm install mocha`
  // Jasmine: `$ npm install jasmine`
  // Cucumber: `$ npm install cucumber`
  framework: 'mocha',
  //
  // Test reporter for stdout.
  // The following are supported: dot (default), spec and xunit
  // see also: http://webdriver.io/guide/testrunner/reporters.html
  reporter: 'spec',

  //
  // Options to be passed to Mocha.
  // See the full list at http://mochajs.org/
  mochaOpts: {
    ui: 'bdd'
    // 'check-leaks': true,
    // bail: true
  },

  // Shorten url command calls by setting a base url. If your url parameter starts with '/'
  // the base url gets prepended.
  baseUrl: 'http://localhost:5050'
}

if (booleanFromEnv('WDIO_SAUCELABS', false)) {
  //
  // =================
  // Service Providers
  // =================
  // WebdriverIO supports Sauce Labs, Browserstack and Testing Bot (other cloud providers
  // should work too though). These services define specific user and key (or access key)
  // values you need to put in here in order to connect to these services.
  //
  config.user = process.env.SAUCE_USERNAME
  config.key = process.env.SAUCE_ACCESS_KEY

  //
  // If you are using Sauce Labs WebdriverIO takes care about updating the job information
  // once the test is done. This option is set to `true` per default.
  //
  config.updateJob = true
  // delete config.reporter

  config.capabilities = queryBrowsers([
    // {name: 'internet explorer', version: '10..latest'},
    // {name: 'firefox', version: '38..latest'},
    {name: 'chrome', version: 'latest'}
    // {name: 'safari', version: '8..latest'},
    // {name: 'iphone', version: '8.4..latest'}
  ], {
    'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,
    'idle-timeout': 900,
    name: 'lucibus/caido',
    build: process.env.TRAVIS_BUILD_NUMBER
  })
}

exports.config = config
<|endoftext|>


<commit_before>import React from 'react'
import {connect} from 'react-redux'
import classnames from 'classnames'
import {loadPlayer} from './services/playerOverview/actions'
import {CLASSINDEX_TO_NAME, JUMP_CLASSES} from 'root/constants/TFClasses'

import TimeAgo from 'react-timeago'
import DocumentTitle from 'react-document-title'
import {Row, Col, Tabs, Tab, Table} from 'react-bootstrap'
import SteamAvatar from 'root/components/SteamAvatar'
import Throbber from 'root/components/Throbber'
import PlayerOverviewStats from './components/PlayerOverviewStats'

import './styles.styl'

function getFormattedDate(date) {
  var year = date.getFullYear()
  var month = (1 + date.getMonth()).toString()
  month = month.length > 1 ? month : '0' + month
  var day = date.getDate().toString()
  day = day.length > 1 ? day : '0' + day
  return month + '/' + day + '/' + year
}

export class PlayerOverview extends React.Component {
  componentDidMount() {
    this.props.loadPlayer(this.props.params.id)
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.params.id !== this.props.params.id) {
      this.props.loadPlayer(nextProps.params.id)
    }
  }

  renderClassRankStats(playerClass) {
    const cri = this.props.data.class_rank_info[playerClass]
    return (

           {`${Math.floor(cri.points)} Points`}

           {`Rank ${cri.rank} (5th in United States)`}

    )
  }

  renderChatRank() {
    const {data} = this.props
    const cri = data.class_rank_info
    const soldier = cri[3]
    const demoman = cri[4]
    let title
    let tfClass
    let rank
    if (soldier.rank < demoman.rank) {
      title = soldier.title
      tfClass = 'soldier'
      rank = soldier.rank
    }
    else {
      title = demoman.title
      tfClass = 'demoman'
      rank = demoman.rank
    }
    return (

        <span className={`tf-icon sm ${tfClass}`}/>

          {title}

          (Rank {rank})

    )
  }

  render() {
    if (!this.props.data || this.props.fetching) {
      return
<Throbber />

    }
    const data = this.props.data
    const pi = data.player_info
    const firstSeenDate = new Date(pi.first_seen * 1000)
    return (
      <DocumentTitle title={`Tempus - ${pi.name}`}>

                  <SteamAvatar steamID={pi.steamid} size="mediumlarge" />

                  Online <TimeAgo date={pi.last_seen * 1000} />

                  Joined {getFormattedDate(firstSeenDate)}

                    {pi.name}

                {this.renderChatRank()}

              <Row>
                {JUMP_CLASSES.map(pc => {
                  const playerClassName = CLASSINDEX_TO_NAME[pc]
                  const icon =
                  return (
                    <PlayerOverviewStats leaderboardURL={`/ranks/${playerClassName.toLowerCase()}`}
                                         leaderboardTitle={playerClassName}
                                         icon={icon}
                                         rankInfo={data.class_rank_info[pc]}
                                         countryRankInfo={data.country_class_rank_info[pc]}
                                         playerInfo={data.player_info}
                                         prStats={data.pr_stats}
                                         wrStats={data.wr_stats}
                                         topStats={data.top_stats}
                                         zoneCount={data.zone_count} />
                  )
                })}
                <PlayerOverviewStats leaderboardURL="/ranks/overall"
                                     leaderboardTitle={'Overall'}
                                     icon={}
                                     rankInfo={data.rank_info}
                                     countryRankInfo={data.country_rank_info}
                                     playerInfo={data.player_info}
                                     prStats={data.pr_stats}
                                     wrStats={data.wr_stats}
                                     topStats={data.top_stats}
                                     zoneCount={data.zone_count} />
              </Row>

              <Tabs className="player-overview-tabs">
                <Tab title="Soldier" eventKey="1">

                      World Records (placeholder)

                      Incomplete Maps (placeholder)

                </Tab>
                <Tab title="Demoman" eventKey="2">
                </Tab>
              </Tabs>

      </DocumentTitle>
    )
  }
}

function mapStateToProps(state) {
  const {playerOverview} = state
  const {fetching, error, data} = playerOverview
  return {fetching, error, data: data ? data.toJS() : data}
}

export default connect(
  mapStateToProps,
  {loadPlayer}
)(PlayerOverview)
<commit_msg>Fix another broken throbber.<commit_after>import React from 'react'
import {connect} from 'react-redux'
import classnames from 'classnames'
import {loadPlayer} from './services/playerOverview/actions'
import {CLASSINDEX_TO_NAME, JUMP_CLASSES} from 'root/constants/TFClasses'

import TimeAgo from 'react-timeago'
import DocumentTitle from 'react-document-title'
import {Row, Col, Tabs, Tab, Table} from 'react-bootstrap'
import SteamAvatar from 'root/components/SteamAvatar'
import Throbber from 'root/components/Throbber'
import PlayerOverviewStats from './components/PlayerOverviewStats'

import './styles.styl'

function getFormattedDate(date) {
  var year = date.getFullYear()
  var month = (1 + date.getMonth()).toString()
  month = month.length > 1 ? month : '0' + month
  var day = date.getDate().toString()
  day = day.length > 1 ? day : '0' + day
  return month + '/' + day + '/' + year
}

export class PlayerOverview extends React.Component {
  componentDidMount() {
    this.props.loadPlayer(this.props.params.id)
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.params.id !== this.props.params.id) {
      this.props.loadPlayer(nextProps.params.id)
    }
  }

  renderClassRankStats(playerClass) {
    const cri = this.props.data.class_rank_info[playerClass]
    return (

           {`${Math.floor(cri.points)} Points`}

           {`Rank ${cri.rank} (5th in United States)`}

    )
  }

  renderChatRank() {
    const {data} = this.props
    const cri = data.class_rank_info
    const soldier = cri[3]
    const demoman = cri[4]
    let title
    let tfClass
    let rank
    if (soldier.rank < demoman.rank) {
      title = soldier.title
      tfClass = 'soldier'
      rank = soldier.rank
    }
    else {
      title = demoman.title
      tfClass = 'demoman'
      rank = demoman.rank
    }
    return (

        <span className={`tf-icon sm ${tfClass}`}/>

          {title}

          (Rank {rank})

    )
  }

  render() {
    if (!this.props.data || this.props.fetching) {
      return
<Throbber />

    }
    const data = this.props.data
    const pi = data.player_info
    const firstSeenDate = new Date(pi.first_seen * 1000)
    return (
      <DocumentTitle title={`Tempus - ${pi.name}`}>

                  <SteamAvatar steamID={pi.steamid} size="mediumlarge" />

                  Online <TimeAgo date={pi.last_seen * 1000} />

                  Joined {getFormattedDate(firstSeenDate)}

                    {pi.name}

                {this.renderChatRank()}

              <Row>
                {JUMP_CLASSES.map(pc => {
                  const playerClassName = CLASSINDEX_TO_NAME[pc]
                  const icon =
                  return (
                    <PlayerOverviewStats leaderboardURL={`/ranks/${playerClassName.toLowerCase()}`}
                                         leaderboardTitle={playerClassName}
                                         icon={icon}
                                         rankInfo={data.class_rank_info[pc]}
                                         countryRankInfo={data.country_class_rank_info[pc]}
                                         playerInfo={data.player_info}
                                         prStats={data.pr_stats}
                                         wrStats={data.wr_stats}
                                         topStats={data.top_stats}
                                         zoneCount={data.zone_count} />
                  )
                })}
                <PlayerOverviewStats leaderboardURL="/ranks/overall"
                                     leaderboardTitle={'Overall'}
                                     icon={}
                                     rankInfo={data.rank_info}
                                     countryRankInfo={data.country_rank_info}
                                     playerInfo={data.player_info}
                                     prStats={data.pr_stats}
                                     wrStats={data.wr_stats}
                                     topStats={data.top_stats}
                                     zoneCount={data.zone_count} />
              </Row>

              <Tabs className="player-overview-tabs">
                <Tab title="Soldier" eventKey="1">

                      World Records (placeholder)

                      Incomplete Maps (placeholder)

                </Tab>
                <Tab title="Demoman" eventKey="2">
                </Tab>
              </Tabs>

      </DocumentTitle>
    )
  }
}

function mapStateToProps(state) {
  const {playerOverview} = state
  const {fetching, error, data} = playerOverview
  return {fetching, error, data: data ? data.toJS() : data}
}

export default connect(
  mapStateToProps,
  {loadPlayer}
)(PlayerOverview)
<|endoftext|>


<commit_before>import React from 'react';
import Section from 'shared/components/section/section';
import LinkButton from 'shared/components/linkButton/linkButton';
import Sabio from '../../../images/codeSchoolLogos/sabio.png';
import CFellows from '../../../images/codeSchoolLogos/cf-logo-horizontal-2-color-black.png';
import Nodejs from '../../../images/nodejs.png';
import styles from './benefit.css';

const Benefit = () => (

        <LinkButton
          role="button"
          text="Donate"
          theme="blue-large"
          link="https://opencollective.com/operationcode#support"
          isExternal
        />

        <LinkButton
          role="button"
          text="Purchase Tickets"
          theme="red-large"
          link="https://buytickets.at/opcode/122463"
          isExternal
        />

       The 2017 Operation Code Benefit Dinner & Auction will celebrate the tens of hundreds of life-changing educational and mentorship opportunities provided throughout the country and across the globe since 2014 while aspiring to deliver more next year.

      Every day a new active military service member, citizen-soldier, veteran, spouse or military family member joins Operation Code for software mentorship, career guidance and assistance, for the lifelong friendships, tech conference and code school scholarships, and to be part of something bigger than themselves— an open source community comprised of passionate volunteer software developers and technology entrepreneurs all dedicated to helping the men and women who’ve served in uniform and their families get the technical skills necessary for the 21st century new skills economy. In too many cases, they face financial barriers and hardships to get started.

       At Operation Code, we believe every service member, citizen-soldier, veteran and family member deserves exceptional technology training and mentorship. We believe that all who’ve worn the uniform and their families should fill the nation’s technical talent shortage.

       That’s what drives each and every one of us: our global network of volunteer software developers, who donate tens of thousands of hours towards mentoring those who’ve served and their families, and our supporters who back us through employee-employer matching, in-kind contributions, and generous sponsorship.

       On Friday, November 10, 2017, we will come together at the Sentinel Hotel’s Governor Ballroom to pause, reflect, toast and celebrate how far we’ve come. We will honor those who’ve served in uniform and how much they’ve learned through the communities generosity. With your support, we will continue to fund our education programs and seed our first scholarship endowment so we can go further, faster tomorrow.

To learn more about sponsorship, {' '}

          click here
        .

          Read the full press release{' '}

        here
        .

Who:

        250+ guests joining forces to help America’s finest and their families get into tech

What:

          Hosted bar, wine, hors d’oeuvres, auction, dinner, and program

When:

        Friday, November 10, 2017

        5:30 PM Hosted Bar, Hors d’oeuvres, Silent Auction

        7:00 PM Dinner, Program and Live Auction

Where:

        The Sentinel Hotel

        Governor Ballroom

        614 SW 11th Ave

        Portland, OR 97205

Why:

        Fund Operation Code’s education programs and create a scholarship endowment

Dress:

        Business Casual

Event Chairs:

        Chris Dawson & David Molina

Hors D’Oeuvres:

          (Served with Silent Auction)

             Stuffed Baby Mushrooms

          with Bacon, Cream Cheese & Jalapeno

             Grilled Prosciutto, Quince Paste, and Manchego Cheese on Baguette

             Smoked Salmon Mousse Tartlets

          House Smoked Salmon with Cream Cheese, Chives & Lemon Zest

             Pierre Robert Cheese & Cherry Conserve Crostini

Salad:
 Italian Kale and Romaine Salad

          with Radicchio, Fennel, Feta Cheese, Dried Cranberries and Candied Walnuts with a Green Goddess Dressing

Dinner:
 Mushroom Duxelle Stuffed Chicken

          Panko-Crusted Boneless Chicken Breast Stuffed with Mushroom Duxelle, Served with Creamy Farro Risotto & Rosemary Sage Cream Sauce

          Vegetarian Option: Wild Mushrooms, Broccolini, Asparagus, and Fontina Cheese Served in an Acorn Squash with Butternut Squash Puree

          Dinner Served with Artisan Rolls & Butter, House Brewed Coffee & Tea

          This year’s major sponsors include{' '}

            Dan Shaw
          ,
           {' '}

           Sabio
          , and {' '}

           Beneficial State Bank
          .

          For Additional Information

          Please contact David Molina at:

          david@operationcode.org

          (971) 279-2586 (work)

          <LinkButton
            text="Donate"
            theme="blue-large"
            link="https://opencollective.com/operationcode#support"
            isExternal
          />

          <LinkButton
            text="Purchase Tickets"
            theme="red-large"
            link="https://buytickets.at/opcode/122463"
            isExternal
          />

);

export default Benefit;
<commit_msg>Fix naming references<commit_after>import React from 'react';
import Section from 'shared/components/section/section';
import LinkButton from 'shared/components/linkButton/linkButton';
import Sabio from '../../../images/codeSchoolLogos/sabio.png';
import CodeFellows from '../../../images/codeSchoolLogos/cf-logo-horizontal-2-color-black.png';
import Nodejs from '../../../images/nodejs.png';
import styles from './benefit.css';

const Benefit = () => (

        <LinkButton
          role="button"
          text="Donate"
          theme="blue-large"
          link="https://opencollective.com/operationcode#support"
          isExternal
        />

        <LinkButton
          role="button"
          text="Purchase Tickets"
          theme="red-large"
          link="https://buytickets.at/opcode/122463"
          isExternal
        />

       The 2017 Operation Code Benefit Dinner & Auction will celebrate the tens of hundreds of life-changing educational and mentorship opportunities provided throughout the country and across the globe since 2014 while aspiring to deliver more next year.

      Every day a new active military service member, citizen-soldier, veteran, spouse or military family member joins Operation Code for software mentorship, career guidance and assistance, for the lifelong friendships, tech conference and code school scholarships, and to be part of something bigger than themselves— an open source community comprised of passionate volunteer software developers and technology entrepreneurs all dedicated to helping the men and women who’ve served in uniform and their families get the technical skills necessary for the 21st century new skills economy. In too many cases, they face financial barriers and hardships to get started.

       At Operation Code, we believe every service member, citizen-soldier, veteran and family member deserves exceptional technology training and mentorship. We believe that all who’ve worn the uniform and their families should fill the nation’s technical talent shortage.

       That’s what drives each and every one of us: our global network of volunteer software developers, who donate tens of thousands of hours towards mentoring those who’ve served and their families, and our supporters who back us through employee-employer matching, in-kind contributions, and generous sponsorship.

       On Friday, November 10, 2017, we will come together at the Sentinel Hotel’s Governor Ballroom to pause, reflect, toast and celebrate how far we’ve come. We will honor those who’ve served in uniform and how much they’ve learned through the communities generosity. With your support, we will continue to fund our education programs and seed our first scholarship endowment so we can go further, faster tomorrow.

To learn more about sponsorship, {' '}

          click here
        .

          Read the full press release{' '}

        here
        .

Who:

        250+ guests joining forces to help America’s finest and their families get into tech

What:

          Hosted bar, wine, hors d’oeuvres, auction, dinner, and program

When:

        Friday, November 10, 2017

        5:30 PM Hosted Bar, Hors d’oeuvres, Silent Auction

        7:00 PM Dinner, Program and Live Auction

Where:

        The Sentinel Hotel

        Governor Ballroom

        614 SW 11th Ave

        Portland, OR 97205

Why:

        Fund Operation Code’s education programs and create a scholarship endowment

Dress:

        Business Casual

Event Chairs:

        Chris Dawson & David Molina

Hors D’Oeuvres:

          (Served with Silent Auction)

             Stuffed Baby Mushrooms

          with Bacon, Cream Cheese & Jalapeno

             Grilled Prosciutto, Quince Paste, and Manchego Cheese on Baguette

             Smoked Salmon Mousse Tartlets

          House Smoked Salmon with Cream Cheese, Chives & Lemon Zest

             Pierre Robert Cheese & Cherry Conserve Crostini

Salad:
 Italian Kale and Romaine Salad

          with Radicchio, Fennel, Feta Cheese, Dried Cranberries and Candied Walnuts with a Green Goddess Dressing

Dinner:
 Mushroom Duxelle Stuffed Chicken

          Panko-Crusted Boneless Chicken Breast Stuffed with Mushroom Duxelle, Served with Creamy Farro Risotto & Rosemary Sage Cream Sauce

          Vegetarian Option: Wild Mushrooms, Broccolini, Asparagus, and Fontina Cheese Served in an Acorn Squash with Butternut Squash Puree

          Dinner Served with Artisan Rolls & Butter, House Brewed Coffee & Tea

          This year’s major sponsors include{' '}

            Dan Shaw
          ,
           {' '}

           Sabio
          , and {' '}

           Beneficial State Bank
          .

          For Additional Information

          Please contact David Molina at:

          david@operationcode.org

          (971) 279-2586 (work)

          <LinkButton
            text="Donate"
            theme="blue-large"
            link="https://opencollective.com/operationcode#support"
            isExternal
          />

          <LinkButton
            text="Purchase Tickets"
            theme="red-large"
            link="https://buytickets.at/opcode/122463"
            isExternal
          />

);

export default Benefit;
<|endoftext|>


<commit_before>"use strict";

/* global  __SCRIPT_URI_SPEC__  */
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "(startup|shutdown|install|uninstall)" }]*/

const { utils: Cu } = Components;
Cu.import("resource://gre/modules/Console.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

const CONFIGPATH = `${__SCRIPT_URI_SPEC__}/../Config.jsm`;
const { config } = Cu.import(CONFIGPATH, {});
const studyConfig = config.study;

const STUDYUTILSPATH = `${__SCRIPT_URI_SPEC__}/../${studyConfig.studyUtilsPath}`;
const { studyUtils } = Cu.import(STUDYUTILSPATH, {});

const REASONS = studyUtils.REASONS;

// var log = createLog(studyConfig.study.studyName, config.log.bootstrap.level);  // defined below.
// log("LOG started!");

/* Example addon-specific module imports.  Remember to Unload.
   Ideally, put ALL your feature code in a Feature.jsm file,
   NOT in this bootstrap.js.

  const BASE=`template-shield-study`;
  XPCOMUtils.defineLazyModuleGetter(this, "SomeExportedSymbol",
    `resource://${BASE}/SomeModule.jsm");

  XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
    "resource://gre/modules/Preferences.jsm");
*/

async function startup(addonData, reason) {
  // addonData: Array [ "id", "version", "installPath", "resourceURI", "instanceID", "webExtension" ]  bootstrap.js:48
  console.log("startup", REASONS[reason] || reason);

  // setup the studyUtils so that Telemetry is valid
  studyUtils.setup({
    ...config,
    addon: { id: addonData.id, version: addonData.version },
  });

  // choose the variation for this particular user, then set it.
  const variation = (studyConfig.forceVariation ||
    await studyUtils.deterministicVariation(
      studyConfig.weightedVariations
    )
  );
  studyUtils.setVariation(variation);

  // addon_install:  note first seen, check eligible
  if ((REASONS[reason]) === "ADDON_INSTALL") {
    studyUtils.firstSeen(); // sends telemetry "enter"
    const eligible = await config.isEligible(); // addon-specific
    if (!eligible) {
      // uses config.endings.ineligible.url if any,
      // sends UT for "ineligible"
      // then uninstalls addon
      await studyUtils.endStudy({reason: "ineligible"});
      return;
    }
  }

  // for all 'eligible' users, startup.
  await studyUtils.startup({reason});

  // log what the study variation and other info is.
  console.log(`info ${JSON.stringify(studyUtils.info())}`);

  // if you have code to handle expiration / long-timers, it could go here

  // If your study has an embedded webExtension, start it.
  const webExtension = addonData.webExtension;
  if (webExtension) {
    webExtension.startup().then(api => {
      const {browser} = api;
      /* spec for messages intended for Shield =>
        {shield:true,msg=[info|endStudy|telemetry],data=data}
      */
      browser.runtime.onMessage.addListener(studyUtils.respondToWebExtensionMessage);

      // other browser.runtime.onMessage handlers for your addon, if any

    });
  }
}

function shutdown(addonData, reason) {
  console.log("shutdown", REASONS[reason] || reason);
  // FRAGILE: handle uninstalls initiated by USER or by addon
  if (reason === REASONS.ADDON_UNINSTALL || reason === REASONS.ADDON_DISABLE) {
    console.log("uninstall or disable");
    if (!studyUtils._isEnding) {
      // we are the first 'uninstall' requestor => must be user action.
      console.log("user requested shutdown");
      studyUtils.endStudy({reason: "user-disable"});
      return;
    }
    // normal shutdown, or 2nd uninstall request
    console.log("Jsms unloading");

    // QA NOTE:  unload addon specific modules here.

    // clean up our modules.
    Cu.unload(CONFIGPATH);
    Cu.unload(STUDYUTILSPATH);

  }
}

function uninstall(addonData, reason) {
  console.log("uninstall", REASONS[reason] || reason);
}

function install(addonData, reason) {
  console.log("install", REASONS[reason] || reason);
  // handle ADDON_UPGRADE (if needful) here
}

/** CONSTANTS and other bootstrap.js utilities */

// logging
// function createLog(name, levelWord) {
//  Cu.import("resource://gre/modules/Log.jsm");
//  var L = Log.repository.getLogger(name);
//  L.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
//  L.level = Log.Level[levelWord] || Log.Level.Debug; // should be a config / pref
//  return L;
// }

<commit_msg>Made the example addon-specific module imports follow the same convention as config and studyUtils<commit_after>"use strict";

/* global  __SCRIPT_URI_SPEC__  */
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "(startup|shutdown|install|uninstall)" }]*/

const { utils: Cu } = Components;
Cu.import("resource://gre/modules/Console.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

const CONFIGPATH = `${__SCRIPT_URI_SPEC__}/../Config.jsm`;
const { config } = Cu.import(CONFIGPATH, {});
const studyConfig = config.study;

const STUDYUTILSPATH = `${__SCRIPT_URI_SPEC__}/../${studyConfig.studyUtilsPath}`;
const { studyUtils } = Cu.import(STUDYUTILSPATH, {});

const REASONS = studyUtils.REASONS;

// var log = createLog(studyConfig.study.studyName, config.log.bootstrap.level);  // defined below.
// log("LOG started!");

/* Example addon-specific module imports.  Remember to Unload during shutdown() below.
   Ideally, put ALL your feature code in a Feature.jsm file,
   NOT in this bootstrap.js.

  const FEATUREPATH = `${__SCRIPT_URI_SPEC__}/../Feature.jsm`;
  const { feature } = Cu.import(FEATUREPATH, {});

  const SOMEEXPORTEDSYMBOLPATH = `${__SCRIPT_URI_SPEC__}/../SomeExportedSymbol.jsm`;
  const { someExportedSymbol } = Cu.import(SOMEEXPORTEDSYMBOLPATH, {});

  XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
    "resource://gre/modules/Preferences.jsm");
*/

async function startup(addonData, reason) {
  // addonData: Array [ "id", "version", "installPath", "resourceURI", "instanceID", "webExtension" ]  bootstrap.js:48
  console.log("startup", REASONS[reason] || reason);

  // setup the studyUtils so that Telemetry is valid
  studyUtils.setup({
    ...config,
    addon: { id: addonData.id, version: addonData.version },
  });

  // choose the variation for this particular user, then set it.
  const variation = (studyConfig.forceVariation ||
    await studyUtils.deterministicVariation(
      studyConfig.weightedVariations
    )
  );
  studyUtils.setVariation(variation);

  // addon_install:  note first seen, check eligible
  if ((REASONS[reason]) === "ADDON_INSTALL") {
    studyUtils.firstSeen(); // sends telemetry "enter"
    const eligible = await config.isEligible(); // addon-specific
    if (!eligible) {
      // uses config.endings.ineligible.url if any,
      // sends UT for "ineligible"
      // then uninstalls addon
      await studyUtils.endStudy({reason: "ineligible"});
      return;
    }
  }

  // for all 'eligible' users, startup.
  await studyUtils.startup({reason});

  // log what the study variation and other info is.
  console.log(`info ${JSON.stringify(studyUtils.info())}`);

  // if you have code to handle expiration / long-timers, it could go here

  // If your study has an embedded webExtension, start it.
  const webExtension = addonData.webExtension;
  if (webExtension) {
    webExtension.startup().then(api => {
      const {browser} = api;
      /* spec for messages intended for Shield =>
        {shield:true,msg=[info|endStudy|telemetry],data=data}
      */
      browser.runtime.onMessage.addListener(studyUtils.respondToWebExtensionMessage);

      // other browser.runtime.onMessage handlers for your addon, if any

    });
  }
}

function shutdown(addonData, reason) {
  console.log("shutdown", REASONS[reason] || reason);
  // FRAGILE: handle uninstalls initiated by USER or by addon
  if (reason === REASONS.ADDON_UNINSTALL || reason === REASONS.ADDON_DISABLE) {
    console.log("uninstall or disable");
    if (!studyUtils._isEnding) {
      // we are the first 'uninstall' requestor => must be user action.
      console.log("user requested shutdown");
      studyUtils.endStudy({reason: "user-disable"});
      return;
    }
    // normal shutdown, or 2nd uninstall request
    console.log("Jsms unloading");

    // QA NOTE:  unload addon specific modules here.

    // clean up our modules.
    Cu.unload(CONFIGPATH);
    Cu.unload(STUDYUTILSPATH);
    //Cu.unload(FEATUREPATH);
    //Cu.unload(SOMEEXPORTEDSYMBOLPATH);

  }
}

function uninstall(addonData, reason) {
  console.log("uninstall", REASONS[reason] || reason);
}

function install(addonData, reason) {
  console.log("install", REASONS[reason] || reason);
  // handle ADDON_UPGRADE (if needful) here
}

/** CONSTANTS and other bootstrap.js utilities */

// logging
// function createLog(name, levelWord) {
//  Cu.import("resource://gre/modules/Log.jsm");
//  var L = Log.repository.getLogger(name);
//  L.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
//  L.level = Log.Level[levelWord] || Log.Level.Debug; // should be a config / pref
//  return L;
// }

<|endoftext|>


<commit_before>
/**
 * Panel to show Delivery info.
 */
Ext.define('devilry.extjshelpers.assignmentgroup.DeliveryInfo', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.deliveryinfo',
    cls: 'widget-deliveryinfo',
    html: '',
    requires: [
        'devilry.extjshelpers.assignmentgroup.FileMetaBrowserPanel'
    ],

    //width: 500,
    //style: {border: 'none'},

    config: {
        /**
         * @cfg
         * FileMeta ``Ext.data.Store``. (Required).
         * _Note_ that ``filemetastore.proxy.extraParams`` is changed by this
         * class.
         */
        filemetastore: undefined,

        /**
         * @cfg
         * A {@link devilry.extjshelpers.SingleRecordContainer} for Delivery.
         */
        delivery_recordcontainer: undefined,

        /**
         * @cfg
         * Delivery ``Ext.data.Model``.
         */
        deliverymodel: undefined,

        /**
         * @cfg
         * A {@link devilry.extjshelpers.SingleRecordContainer} for AssignmentGroup.
         */
        assignmentgroup_recordcontainer: undefined
    },

    tpl: Ext.create('Ext.XTemplate',
        '<tpl if="time_of_delivery">', // If time_of_delivery is false, the record is not loaded yet
        '    <tpl if="time_of_delivery > deadline__deadline">',
        '
',
        '
After deadline
',
        '
This delivery was made after the deadline ({deadline__deadline:date}).
',
        '
',
        '    </tpl>',
        '    <tpl if="!islatestDelivery">',
        '
',
        '
Not the latest delivery
',
        '
',
        '               The group has made one or more deliveries after the one you are currently viewing. Normally the latest delivery is corrected.',
        '               <tpl if="time_of_delivery > deadline__deadline">',
        '                   However since this delivery was made after the deadline, an earlier delivery may be corrected instead.',
        '               </tpl>',
        '               Choose Other deliveries in the toolbar to view other deliveries.',
        '
',
        '
',
        '    </tpl>',
        '
',
        '
Delivery number {number}
',
        '
This delivery was made {time_of_delivery:date}. Choose Browse files in the toolbar to download the delivered files.
',
        '
',
        '</tpl>'
    ),

    initComponent: function() {
        this.toolbar = Ext.widget('toolbar', {
            xtype: 'toolbar',
            dock: 'top',
            items: []
        });

        Ext.apply(this, {
            hidden: true,
            dockedItems: [this.toolbar]
        });
        this.callParent(arguments);

        this.deliverystore = this.createDeliveryStore();

        if(this.assignmentgroup_recordcontainer.record) {
            this.loadDeliveryStore();
        }
        this.assignmentgroup_recordcontainer.addListener('setRecord', this.loadDeliveryStore, this);

        if(this.delivery_recordcontainer.record) {
            this.onLoadDelivery();
        }
        this.delivery_recordcontainer.addListener('setRecord', this.onLoadSomething, this);
    },

    /**
     * @private
     */
    onLoadSomething: function() {
        if(this.delivery_recordcontainer.record && this.deliverystoreLoaded) {
            this.onLoadingComplete();
        }
    },

    /**
     * @private
     * Reload all deliveries on this assignmentgroup.
     * */
    loadDeliveryStore: function() {
        //this.deliverystore.pageSize = 3;
        this.deliverystore.proxy.extraParams.filters = Ext.JSON.encode([{
            field: 'deadline__assignment_group',
            comp: 'exact',
            value: this.assignmentgroup_recordcontainer.record.data.id
        }]);
        this.deliverystore.load({
            scope: this,
            callback: function(records, op, success) {
                if(success) {
                    this.deliverystoreLoaded = true;
                    this.onLoadSomething(records);
                } else {
                    throw "Failed to load delivery store.";
                }
            }
        });
    },

    /**
     * @private
     */
    onLoadingComplete: function() {
        var delivery = this.delivery_recordcontainer.record.data;
        var islatestDelivery = this.deliverystore.currentPage == 1 && this.deliverystore.data.items[0].data.id == delivery.id;

        this.show();
        this.toolbar.removeAll();

        var data = {
            islatestDelivery: islatestDelivery
        };
        Ext.apply(data, delivery);
        this.update(data);

        this.toolbar.add({
            xtype: 'button',
            text: 'Browse files',
            id: 'tooltip-browse-files',
            scale: 'large',
            menu: [], // To get an arrow
            enableToggle: true,
            listeners: {
                scope: this,
                click: this.showFileMetaBrowserWindow,
                render: function() {
                    Ext.create('devilry.extjshelpers.tooltips.assignmentgroup.BrowseFiles', {});
                }
            }
        });

        this.toolbar.add({
            xtype: 'button',
            menu: [], // To get an arrow
            id: 'tooltip-other-deliveries',
            text: 'Other deliveries',
            scale: 'large',
            //enableToggle: true,
            listeners: {
                scope: this,
                click: this.onOtherDeliveries
            }
        });
    },

    /**
     * @private
     * */
    createDeliveryStore: function() {
        var deliverystore = Ext.create('Ext.data.Store', {
            model: this.deliverymodel,
            remoteFilter: true,
            remoteSort: true,
            autoSync: true,
            groupField: 'deadline__deadline'
        });

        deliverystore.proxy.extraParams.orderby = Ext.JSON.encode(['-deadline__deadline', '-number']);
        return deliverystore;
    },

    /**
     * @private
     */
    onOtherDeliveries: function(button) {
        if(!this.deliveriesWindow) {
            this.deliveriesWindow = Ext.create('Ext.window.Window', {
                title: 'Deliveries by this group',
                height: 500,
                width: 400,
                modal: true,
                layout: 'fit',
                closeAction: 'hide',
                items: {
                    xtype: 'deliveriesonsinglegrouplisting',
                    store: this.deliverystore,
                    delivery_recordcontainer: this.delivery_recordcontainer
                },

                //listeners: {
                    //scope: this,
                    //close: function() {
                        //if(button) {
                            //button.toggle(false);
                        //}
                    //}
                //}
            });
        }
        this.deliveriesWindow.show();
        if(button) {
            this.deliveriesWindow.alignTo(button, 'bl', [0, 0]);
        }
    },

    /**
     * @private
     */
    showFileMetaBrowserWindow: function(button) {
        var fileBrowser = Ext.create('Ext.window.Window', {
            title: 'Files',
            height: 400,
            width: 500,
            modal: true,
            //animateTarget: button,
            layout: 'fit',
            items: [{
                xtype: 'filemetabrowserpanel',
                border: false,
                filemetastore: this.filemetastore,
                deliveryid: this.delivery_recordcontainer.record.data.id
            }],
            listeners: {
                scope: this,
                close: function() {
                    button.toggle(false);
                }
            }
        });
        fileBrowser.show();
        fileBrowser.alignTo(button, 'bl', [0, 0]);
    }
});
<commit_msg>apps.extjshelpers: Non-closable deliveries window on group load.<commit_after>
/**
 * Panel to show Delivery info.
 */
Ext.define('devilry.extjshelpers.assignmentgroup.DeliveryInfo', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.deliveryinfo',
    cls: 'widget-deliveryinfo',
    html: '',
    requires: [
        'devilry.extjshelpers.assignmentgroup.FileMetaBrowserPanel'
    ],

    //width: 500,
    //style: {border: 'none'},

    config: {
        /**
         * @cfg
         * FileMeta ``Ext.data.Store``. (Required).
         * _Note_ that ``filemetastore.proxy.extraParams`` is changed by this
         * class.
         */
        filemetastore: undefined,

        /**
         * @cfg
         * A {@link devilry.extjshelpers.SingleRecordContainer} for Delivery.
         */
        delivery_recordcontainer: undefined,

        /**
         * @cfg
         * Delivery ``Ext.data.Model``.
         */
        deliverymodel: undefined,

        /**
         * @cfg
         * A {@link devilry.extjshelpers.SingleRecordContainer} for AssignmentGroup.
         */
        assignmentgroup_recordcontainer: undefined
    },

    tpl: Ext.create('Ext.XTemplate',
        '<tpl if="time_of_delivery">', // If time_of_delivery is false, the record is not loaded yet
        '    <tpl if="time_of_delivery > deadline__deadline">',
        '
',
        '
After deadline
',
        '
This delivery was made after the deadline ({deadline__deadline:date}).
',
        '
',
        '    </tpl>',
        '    <tpl if="!islatestDelivery">',
        '
',
        '
Not the latest delivery
',
        '
',
        '               The group has made one or more deliveries after the one you are currently viewing. Normally the latest delivery is corrected.',
        '               <tpl if="time_of_delivery > deadline__deadline">',
        '                   However since this delivery was made after the deadline, an earlier delivery may be corrected instead.',
        '               </tpl>',
        '               Choose Other deliveries in the toolbar to view other deliveries.',
        '
',
        '
',
        '    </tpl>',
        '
',
        '
Delivery number {number}
',
        '
This delivery was made {time_of_delivery:date}. Choose Browse files in the toolbar to download the delivered files.
',
        '
',
        '</tpl>'
    ),

    initComponent: function() {
        this.toolbar = Ext.widget('toolbar', {
            xtype: 'toolbar',
            dock: 'top',
            items: []
        });

        Ext.apply(this, {
            hidden: true,
            dockedItems: [this.toolbar]
        });
        this.callParent(arguments);

        this.deliverystore = this.createDeliveryStore();

        if(this.assignmentgroup_recordcontainer.record) {
            this.loadDeliveryStore();
        }
        this.assignmentgroup_recordcontainer.addListener('setRecord', this.loadDeliveryStore, this);

        if(this.delivery_recordcontainer.record) {
            this.onLoadDelivery();
        }
        this.delivery_recordcontainer.addListener('setRecord', this.onLoadSomething, this);
    },

    /**
     * @private
     */
    onLoadSomething: function() {
        if(this.delivery_recordcontainer.record && this.deliverystoreLoaded) {
            this.onLoadingComplete();
        }
    },

    /**
     * @private
     * Reload all deliveries on this assignmentgroup.
     * */
    loadDeliveryStore: function() {
        //this.deliverystore.pageSize = 3;
        this.deliverystore.proxy.extraParams.filters = Ext.JSON.encode([{
            field: 'deadline__assignment_group',
            comp: 'exact',
            value: this.assignmentgroup_recordcontainer.record.data.id
        }]);
        this.deliverystore.load({
            scope: this,
            callback: function(records, op, success) {
                if(success) {
                    this.deliverystoreLoaded = true;
                    this.onLoadSomething(records);
                } else {
                    throw "Failed to load delivery store.";
                }
            }
        });
    },

    /**
     * @private
     */
    onLoadingComplete: function() {
        var delivery = this.delivery_recordcontainer.record.data;
        var islatestDelivery = this.deliverystore.currentPage == 1 && this.deliverystore.data.items[0].data.id == delivery.id;

        this.show();
        this.toolbar.removeAll();

        var data = {
            islatestDelivery: islatestDelivery
        };
        Ext.apply(data, delivery);
        this.update(data);

        this.toolbar.add({
            xtype: 'button',
            text: 'Browse files',
            id: 'tooltip-browse-files',
            scale: 'large',
            menu: [], // To get an arrow
            enableToggle: true,
            listeners: {
                scope: this,
                click: this.showFileMetaBrowserWindow,
                render: function() {
                    Ext.create('devilry.extjshelpers.tooltips.assignmentgroup.BrowseFiles', {});
                }
            }
        });

        this.toolbar.add({
            xtype: 'button',
            menu: [], // To get an arrow
            id: 'tooltip-other-deliveries',
            text: 'Other deliveries',
            scale: 'large',
            //enableToggle: true,
            listeners: {
                scope: this,
                click: this.onOtherDeliveries
            }
        });
    },

    /**
     * @private
     * */
    createDeliveryStore: function() {
        var deliverystore = Ext.create('Ext.data.Store', {
            model: this.deliverymodel,
            remoteFilter: true,
            remoteSort: true,
            autoSync: true,
            groupField: 'deadline__deadline'
        });

        deliverystore.proxy.extraParams.orderby = Ext.JSON.encode(['-deadline__deadline', '-number']);
        return deliverystore;
    },

    /**
     * @private
     */
    onOtherDeliveries: function(button, notClosable) {
        var deliveriesWindow = Ext.create('Ext.window.Window', {
            title: 'Deliveries by this group',
            height: 500,
            width: 400,
            modal: true,
            layout: 'fit',
            closeAction: 'hide',
            closable: button != undefined,
            items: {
                xtype: 'deliveriesonsinglegrouplisting',
                store: this.deliverystore,
                delivery_recordcontainer: this.delivery_recordcontainer
            }
        });
        deliveriesWindow.show();
        if(button) {
            deliveriesWindow.alignTo(button, 'bl', [0, 0]);
        }
    },

    /**
     * @private
     */
    showFileMetaBrowserWindow: function(button) {
        var fileBrowser = Ext.create('Ext.window.Window', {
            title: 'Files',
            height: 400,
            width: 500,
            modal: true,
            //animateTarget: button,
            layout: 'fit',
            items: [{
                xtype: 'filemetabrowserpanel',
                border: false,
                filemetastore: this.filemetastore,
                deliveryid: this.delivery_recordcontainer.record.data.id
            }],
            listeners: {
                scope: this,
                close: function() {
                    button.toggle(false);
                }
            }
        });
        fileBrowser.show();
        fileBrowser.alignTo(button, 'bl', [0, 0]);
    }
});
<|endoftext|>


<commit_before>const auth = require('@feathersjs/authentication');
const errors = require('@feathersjs/errors');
const globalHooks = require('../../../hooks');
const Hydra = require('../hydra.js');

const properties = 'title="username" style="height: 26px; width: 180px; border: none;"';
const iframeSubject = (pseudonym, url) => `<iframe src="${url}/oauth2/username/${pseudonym}" ${properties}></iframe>`;

exports.getSubject = iframeSubject;

const setSubject = (hook) => {
	if (!hook.params.query.accept) return hook;
	return hook.app.service('ltiTools').find({
		query: {
			oAuthClientId: hook.params.loginRequest.client.client_id,
		},
	}).then(tools => hook.app.service('pseudonym').find({
		query: {
			toolId: tools.data[0]._id,
			userId: hook.params.account.userId,
		},
	}).then((pseudonyms) => {
		const { pseudonym } = pseudonyms.data[0];
		if (!hook.data) hook.data = {};
		hook.data.subject = hook.params.account.userId;
		if (tools.data[0].useIframePseudonym) {
			hook.data.force_subject_identifier = iframeSubject(pseudonym, hook.app.settings.services.web);
		} else {
			hook.data.force_subject_identifier = pseudonym;
		}
		return hook;
	}));
};

const setIdToken = (hook) => {
	if (!hook.params.query.accept) return hook;
	hook.data.session = {
		id_token: {
			iframe: iframeSubject(hook.params.consentRequest.subject, hook.app.settings.services.web),
		},
	};
	return hook;
};

const injectLoginRequest = hook => Hydra(hook.app.settings.services.hydra).getLoginRequest(hook.id)
	.then((loginRequest) => {
		hook.params.loginRequest = loginRequest;
		return hook;
	});

const injectConsentRequest = hook => Hydra(hook.app.settings.services.hydra).getConsentRequest(hook.id)
	.then((consentRequest) => {
		hook.params.consentRequest = consentRequest;
		return hook;
	});

const validateSubject = (hook) => {
	if (hook.params.consentRequest.subject === hook.params.account.userId.toString()) return hook;
	throw new errors.Forbidden("You want to patch another user's consent");
};

const managesOwnConsents = (hook) => {
	if (hook.id === hook.params.account.userId.toString()) return hook;
	throw new errors.Forbidden("You want to manage another user's consents");
};

exports.hooks = {
	clients: {
		before: {
			all: [
				auth.hooks.authenticate('jwt'),
				globalHooks.ifNotLocal(globalHooks.isSuperHero()),
			],
		},
	},
	loginRequest: {
		before: {
			patch: [auth.hooks.authenticate('jwt'), injectLoginRequest, setSubject],
		},
	},
	consentRequest: {
		before: {
			all: [auth.hooks.authenticate('jwt')],
			patch: [injectConsentRequest, validateSubject, setIdToken],
		},
	},
	introspect: {
		before: {
			create: [globalHooks.ifNotLocal(() => { throw new errors.MethodNotAllowed(); })],
		},
	},
	consentSessions: {
		before: {
			all: [auth.hooks.authenticate('jwt'), managesOwnConsents],
		},
	},
};
<commit_msg>set pseudonym in iframe<commit_after>const auth = require('@feathersjs/authentication');
const errors = require('@feathersjs/errors');
const globalHooks = require('../../../hooks');
const Hydra = require('../hydra.js');

const properties = 'title="username" style="height: 26px; width: 180px; border: none;"';
const iframeSubject = (pseudonym, url) => `<iframe src="${url}/oauth2/username/${pseudonym}" ${properties}></iframe>`;

exports.getSubject = iframeSubject;

const setSubject = (hook) => {
	if (!hook.params.query.accept) return hook;
	return hook.app.service('ltiTools').find({
		query: {
			oAuthClientId: hook.params.loginRequest.client.client_id,
		},
	}).then(tools => hook.app.service('pseudonym').find({
		query: {
			toolId: tools.data[0]._id,
			userId: hook.params.account.userId,
		},
	}).then((pseudonyms) => {
		const { pseudonym } = pseudonyms.data[0];
		if (!hook.data) hook.data = {};
		hook.data.subject = hook.params.account.userId;
		if (tools.data[0].useIframePseudonym) {
			hook.data.force_subject_identifier = iframeSubject(pseudonym, hook.app.settings.services.web);
		} else {
			hook.data.force_subject_identifier = pseudonym;
		}
		return hook;
	}));
};

const setIdToken = (hook) => {
	if (!hook.params.query.accept) return hook;
	return hook.app.service('ltiTools').find({
		query: {
			oAuthClientId: hook.params.consentRequest.client.client_id,
		},
	}).then(tools => hook.app.service('pseudonym').find({
		query: {
			toolId: tools.data[0]._id,
			userId: hook.params.account.userId,
		},
	}).then((pseudonyms) => {
		const { pseudonym } = pseudonyms.data[0];
		hook.data.session = {
			id_token: {
				iframe: iframeSubject(pseudonym, hook.app.settings.services.web),
			},
		};
		return hook;
	}));
};

const injectLoginRequest = hook => Hydra(hook.app.settings.services.hydra).getLoginRequest(hook.id)
	.then((loginRequest) => {
		hook.params.loginRequest = loginRequest;
		return hook;
	});

const injectConsentRequest = hook => Hydra(hook.app.settings.services.hydra).getConsentRequest(hook.id)
	.then((consentRequest) => {
		hook.params.consentRequest = consentRequest;
		return hook;
	});

const validateSubject = (hook) => {
	if (hook.params.consentRequest.subject === hook.params.account.userId.toString()) return hook;
	throw new errors.Forbidden("You want to patch another user's consent");
};

const managesOwnConsents = (hook) => {
	if (hook.id === hook.params.account.userId.toString()) return hook;
	throw new errors.Forbidden("You want to manage another user's consents");
};

exports.hooks = {
	clients: {
		before: {
			all: [
				auth.hooks.authenticate('jwt'),
				globalHooks.ifNotLocal(globalHooks.isSuperHero()),
			],
		},
	},
	loginRequest: {
		before: {
			patch: [auth.hooks.authenticate('jwt'), injectLoginRequest, setSubject],
		},
	},
	consentRequest: {
		before: {
			all: [auth.hooks.authenticate('jwt')],
			patch: [injectConsentRequest, validateSubject, setIdToken],
		},
	},
	introspect: {
		before: {
			create: [globalHooks.ifNotLocal(() => { throw new errors.MethodNotAllowed(); })],
		},
	},
	consentSessions: {
		before: {
			all: [auth.hooks.authenticate('jwt'), managesOwnConsents],
		},
	},
};
<|endoftext|>