<commit_before>const RenderString = Vue.component('render-string', {
    template: `

        {{ field.Name }}
        <input v-model="storage[field.Key]">
`,
    created: function () {
        if (this.storage[this.field.Key] == null) {
            this.$set(this.storage, this.field.Key, "")
        }
    },
    props: {
        storage: Object,
        field: Object
    }
})
const RenderInteger = Vue.component('render-integer', {
    template: `

    {{ field.Name }}
    <input type="number" v-model="storage[field.Key]">
`,
    created: function () {
        if (this.storage[this.field.Key] == null) {
            this.$set(this.storage, this.field.Key, 0)
        }
    },
    props: {
        storage: Object,
        field: Object
    }
})
const RenderBool = Vue.component('render-bool', {
    template: `

    {{ field.Name }}
     <input type="checkbox" v-model="storage[field.Key]">
`,
    created: function () {
        if (this.storage[this.field.Key] == null) {
            this.$set(this.storage, this.field.Key, false)
        }
    },
    props: {
        storage: Object,
        field: Object
    }
})
const RenderList = Vue.component('render-list', {
    template: `
{{ field.Name }}:

<input v-model="storage[field.Key][key]">

Add Tag

`,
    props: {
        storage: Object,
        field: Object
    },
    created: function () {
        if (this.storage[this.field.Key] == null) {
            this.$set(this.storage, this.field.Key, [])
        }
    },
    methods: {
        addTag: function () {
            if (this.storage[this.field.Key] == null) {
                this.storage[this.field.Key] = [];
            }
            this.storage[this.field.Key].push("");
        }
    }
})
const RenderField = Vue.component('render-field', {
    template: `

    <component :is=field.Type :storage=storage :field=field></component>
`,
    computed: {
        fieldType: function () {
            return this.field.Type
        }
    },
    components: {
        string: RenderString,
        int: RenderInteger,
        bool: RenderBool,
        list: RenderList
    },

    props: {
        field: Object,
        storage: Object
    }
})
const Home = Vue.component('home', {
    data: function () {
        return {
            collections: {}
        }
    },
    template: `

                <router-link
                    active-class="active"
                    class="header"
                    :to="{ name: 'collection', params: { cid: key}}">
                {{key}}
                </router-link>

            <router-view></router-view>

    `,
    props: ['cid'],
    mounted: function () {
        this.$http.get('/collection').then(
            (res) => {
                this.collections = res.body;
            }
        );
        //this.collections = data;
    }
})

const Collection = Vue.component('collection', {
    template: `

            <router-link
                active-class="active"
                class="item"
                :to="{ name: 'item', params: { iid: key}}">
                {{key}}
                </router-link>

            <router-view></router-view>

    `,
    data: function () {
        return {
            items: { Storages: null }
        }
    },
    methods: {
        fetchData: function () {
            this.$http.get('/collection/' + this.cid).then(
                (res) => {
                    this.items = res.body;
                }
            );
        }
    },
    created: function () {
        this.fetchData()
    },
    watch: {
        '$route': 'fetchData'
    },
    props: ['cid']
})

const Item = Vue.component('item', {
    template: `

    <form class="ui small form">

{{ iid }}

        <render-field :field=f :storage=item[f.Type] ></render-field>

        <button class="ui button" @click="saveData">Save Data</button>
    </form>

`,
    data: function () {
        return {
            item: { fields: [] }
        }
    },
    methods: {
        fetchData: function () {
            this.$http.get('/collection/' + this.cid + '/' + this.iid).then(
                (res) => {
                    this.item = res.body;
                }
            );
        },
        saveData: function () {
            this.$http.post('/collection/' + this.cid + '/' + this.iid, this.item);
        }
    },
    created: function () {
        this.fetchData()
    },
    watch: {
        '$route': 'fetchData'
    },
    props: ['cid', 'iid']
})

const Breadcrumb = Vue.component('breadcrumb', {
    template: `

    <router-link class="section" to="/">Home</router-link>
    /
    <router-link
                v-if="cid"

                class="section"
                :to="{ name: 'collection', params: { cid: cid}}">
                {{cid}}
                </router-link>
    /

{{ iid }}

    `,
    props: ['cid', 'iid']
})

const routes = [
    {
        path: '/',
        name: 'home',
        components: {
            default: Home,
            breadcrumb: Breadcrumb
        },
        children: [
        ]
    },
    {
        path: '/:cid',
        name: 'collection',
        components: {
            default: Collection,
            breadcrumb: Breadcrumb
        },
        props: {
            default: true,
            breadcrumb: true
        },
        children: [

        ]
    },
    {
        path: '/:cid/:iid',
        name: 'item',
        components: {
            default: Item,
            breadcrumb: Breadcrumb
        },
        props: {
            default: true,
            breadcrumb: true
        }
    },
]

const router = new VueRouter({
    routes: routes
})

const app = new Vue({
    router,
    data: {
        collectionName: "",
        itemName: ""
    }
}).$mount('#app')

$(document)
    .ready(function () {
        $('.ui.dropdown')
            .dropdown()
            ;
    })
    ;<commit_msg>Add and remove tags in vue component<commit_after>const RenderString = Vue.component('render-string', {
    template: `

        {{ field.Name }}
        <input v-model="storage[field.Key]">
`,
    created: function () {
        if (this.storage[this.field.Key] == null) {
            this.$set(this.storage, this.field.Key, "")
        }
    },
    props: {
        storage: Object,
        field: Object
    }
})
const RenderInteger = Vue.component('render-integer', {
    template: `

    {{ field.Name }}
    <input type="number" v-model="storage[field.Key]">
`,
    created: function () {
        if (this.storage[this.field.Key] == null) {
            this.$set(this.storage, this.field.Key, 0)
        }
    },
    props: {
        storage: Object,
        field: Object
    }
})
const RenderBool = Vue.component('render-bool', {
    template: `

    {{ field.Name }}
     <input type="checkbox" v-model="storage[field.Key]">
`,
    created: function () {
        if (this.storage[this.field.Key] == null) {
            this.$set(this.storage, this.field.Key, false)
        }
    },
    props: {
        storage: Object,
        field: Object
    }
})
const RenderList = Vue.component('render-list', {
    template: `
{{ field.Name }}:

    {{ storage[field.Key][key] }}

  <input type="text" v-model="newTagVal">

    Add {{ field.Name }}

`,
    data: function (){
        return {
            newTagVal: ""
        }
    },
    props: {
        storage: Object,
        field: Object
    },
    created: function () {
        if (this.storage[this.field.Key] == null) {
            this.$set(this.storage, this.field.Key, [])
        }
    },
    methods: {
        addTag: function () {
            if (this.storage[this.field.Key] == null) {
                this.storage[this.field.Key] = [];
            }
            this.storage[this.field.Key].push(this.newTagVal);
        },
        removeTag: function (key) {
            this.storage[this.field.Key].splice(key,1);
        }
    }
})
const RenderField = Vue.component('render-field', {
    template: `

    <component :is=field.Type :storage=storage :field=field></component>
`,
    computed: {
        fieldType: function () {
            return this.field.Type
        }
    },
    components: {
        string: RenderString,
        int: RenderInteger,
        bool: RenderBool,
        list: RenderList
    },

    props: {
        field: Object,
        storage: Object
    }
})
const Home = Vue.component('home', {
    data: function () {
        return {
            collections: {}
        }
    },
    template: `

                <router-link
                    active-class="active"
                    class="header"
                    :to="{ name: 'collection', params: { cid: key}}">
                {{key}}
                </router-link>

            <router-view></router-view>

    `,
    props: ['cid'],
    mounted: function () {
        this.$http.get('/collection').then(
            (res) => {
                this.collections = res.body;
            }
        );
        //this.collections = data;
    }
})

const Collection = Vue.component('collection', {
    template: `

            <router-link
                active-class="active"
                class="item"
                :to="{ name: 'item', params: { iid: key}}">
                {{key}}
                </router-link>

            <router-view></router-view>

    `,
    data: function () {
        return {
            items: { Storages: null }
        }
    },
    methods: {
        fetchData: function () {
            this.$http.get('/collection/' + this.cid).then(
                (res) => {
                    this.items = res.body;
                }
            );
        }
    },
    created: function () {
        this.fetchData()
    },
    watch: {
        '$route': 'fetchData'
    },
    props: ['cid']
})

const Item = Vue.component('item', {
    template: `

    <form class="ui small form">

{{ iid }}

        <render-field :field=f :storage=item[f.Type] ></render-field>

        <button class="ui button" @click="saveData">Save Data</button>
    </form>

`,
    data: function () {
        return {
            item: { fields: [] }
        }
    },
    methods: {
        fetchData: function () {
            this.$http.get('/collection/' + this.cid + '/' + this.iid).then(
                (res) => {
                    this.item = res.body;
                }
            );
        },
        saveData: function () {
            this.$http.post('/collection/' + this.cid + '/' + this.iid, this.item);
        }
    },
    created: function () {
        this.fetchData()
    },
    watch: {
        '$route': 'fetchData'
    },
    props: ['cid', 'iid']
})

const Breadcrumb = Vue.component('breadcrumb', {
    template: `

    <router-link class="section" to="/">Home</router-link>
    /
    <router-link
                v-if="cid"
                class="section"
                :to="{ name: 'collection', params: { cid: cid}}">
                {{cid}}
                </router-link>
    /

{{ iid }}

    `,
    props: ['cid', 'iid']
})

const routes = [
    {
        path: '/',
        name: 'home',
        components: {
            default: Home,
            breadcrumb: Breadcrumb
        },
        children: [
        ]
    },
    {
        path: '/:cid',
        name: 'collection',
        components: {
            default: Collection,
            breadcrumb: Breadcrumb
        },
        props: {
            default: true,
            breadcrumb: true
        },
        children: [

        ]
    },
    {
        path: '/:cid/:iid',
        name: 'item',
        components: {
            default: Item,
            breadcrumb: Breadcrumb
        },
        props: {
            default: true,
            breadcrumb: true
        }
    },
]

const router = new VueRouter({
    routes: routes
})

const app = new Vue({
    router,
    data: {
        collectionName: "",
        itemName: ""
    }
}).$mount('#app')

$(document)
    .ready(function () {
        $('.ui.dropdown')
            .dropdown()
            ;
    })
    ;<|endoftext|>


<commit_before>'use strict'

module.exports =
class StateStore {
  constructor (databaseName, version) {
    this.dbPromise = new Promise((resolve) => {
      let dbOpenRequest = indexedDB.open(databaseName, version)
      dbOpenRequest.onupgradeneeded = (event) => {
        let db = event.target.result
        db.createObjectStore('states')
      }
      dbOpenRequest.onsuccess = () => {
        resolve(dbOpenRequest.result)
      }
      dbOpenRequest.onerror = (error) => {
        console.error('Could not connect to indexedDB', error)
        resolve(null)
      }
    })
  }

  connect () {
    return this.dbPromise.then(db => !!db)
  }

  save (key, value) {
    return new Promise((resolve, reject) => {
      this.dbPromise.then(db => {
        if (db == null) resolve()

        var request = db.transaction(['states'], 'readwrite')
          .objectStore('states')
          .put({value: value, storedAt: new Date().toString()}, key)

        request.onsuccess = resolve
        request.onerror = reject
      })
    })
  }

  load (key) {
    return this.dbPromise.then(db => {
      if (!db) return

      return new Promise((resolve, reject) => {
        var request = db.transaction(['states'])
          .objectStore('states')
          .get(key)

        request.onsuccess = (event) => {
          let result = event.target.result
          if (result && !result.isJSON) {
            resolve(result.value)
          } else {
            resolve(null)
          }
        }

        request.onerror = (event) => reject(event)
      })
    })
  }

  clear () {
    return this.dbPromise.then(db => {
      if (!db) return

      return new Promise((resolve, reject) => {
        var request = db.transaction(['states'], 'readwrite')
          .objectStore('states')
          .clear()

        request.onsuccess = resolve
        request.onerror = reject
      })
    })
  }

  count () {
    return this.dbPromise.then(db => {
      if (!db) return

      return new Promise((resolve, reject) => {
        var request = db.transaction(['states'])
          .objectStore('states')
          .count()

        request.onsuccess = () => {
          resolve(request.result)
        }
        request.onerror = reject
      })
    })
  }
}
<commit_msg>Fix null guard in StateStore<commit_after>'use strict'

module.exports =
class StateStore {
  constructor (databaseName, version) {
    this.dbPromise = new Promise((resolve) => {
      let dbOpenRequest = indexedDB.open(databaseName, version)
      dbOpenRequest.onupgradeneeded = (event) => {
        let db = event.target.result
        db.createObjectStore('states')
      }
      dbOpenRequest.onsuccess = () => {
        resolve(dbOpenRequest.result)
      }
      dbOpenRequest.onerror = (error) => {
        console.error('Could not connect to indexedDB', error)
        resolve(null)
      }
    })
  }

  connect () {
    return this.dbPromise.then(db => !!db)
  }

  save (key, value) {
    return new Promise((resolve, reject) => {
      this.dbPromise.then(db => {
        if (db == null) return resolve()

        var request = db.transaction(['states'], 'readwrite')
          .objectStore('states')
          .put({value: value, storedAt: new Date().toString()}, key)

        request.onsuccess = resolve
        request.onerror = reject
      })
    })
  }

  load (key) {
    return this.dbPromise.then(db => {
      if (!db) return

      return new Promise((resolve, reject) => {
        var request = db.transaction(['states'])
          .objectStore('states')
          .get(key)

        request.onsuccess = (event) => {
          let result = event.target.result
          if (result && !result.isJSON) {
            resolve(result.value)
          } else {
            resolve(null)
          }
        }

        request.onerror = (event) => reject(event)
      })
    })
  }

  clear () {
    return this.dbPromise.then(db => {
      if (!db) return

      return new Promise((resolve, reject) => {
        var request = db.transaction(['states'], 'readwrite')
          .objectStore('states')
          .clear()

        request.onsuccess = resolve
        request.onerror = reject
      })
    })
  }

  count () {
    return this.dbPromise.then(db => {
      if (!db) return

      return new Promise((resolve, reject) => {
        var request = db.transaction(['states'])
          .objectStore('states')
          .count()

        request.onsuccess = () => {
          resolve(request.result)
        }
        request.onerror = reject
      })
    })
  }
}
<|endoftext|>


<commit_before>import audio from "./../audio/audio.js";
import utils from "./../utils/utils.js";
import event from "./../system/event.js";
import timer from "./../system/timer.js";
import game from "./../game.js";
import Stage from "./../state/stage.js";
import defaultLoadingScreen from "./../loader/loadingscreen.js";

// current state
var _state = -1;

// requestAnimeFrame Id
var _animFrameId = -1;

// whether the game state is "paused"
var _isPaused = false;

// list of stages
var _stages = {};

// fading transition parameters between screen
var _fade = {
    color : "",
    duration : 0
};

// callback when state switch is done
/** @ignore */
var _onSwitchComplete = null;

// just to keep track of possible extra arguments
var _extraArgs = null;

// store the elapsed time during pause/stop period
var _pauseTime = 0;

/**
 * @ignore
 */
function _startRunLoop() {
    // ensure nothing is running first and in valid state
    if ((_animFrameId === -1) && (_state !== -1)) {
        // reset the timer
        timer.reset();

        // start the main loop
        _animFrameId = window.requestAnimationFrame(_renderFrame);
    }
}

/**
 * Resume the game loop after a pause.
 * @ignore
 */
function _resumeRunLoop() {
    // ensure game is actually paused and in valid state
    if (_isPaused && (_state !== -1)) {
        // reset the timer
        timer.reset();

        _isPaused = false;
    }
}

/**
 * Pause the loop for most screen objects.
 * @ignore
 */
function _pauseRunLoop() {
    // Set the paused boolean to stop updates on (most) entities
    _isPaused = true;
}

/**
 * this is only called when using requestAnimFrame stuff
 * @param {Number} time current timestamp in milliseconds
 * @ignore
 */
function _renderFrame(time) {
    var stage = _stages[_state].stage;
    // update all game objects
    game.update(time, stage);
    // render all game objects
    game.draw(stage);
    // schedule the next frame update
    if (_animFrameId !== -1) {
        _animFrameId = window.requestAnimationFrame(_renderFrame);
    }
}

/**
 * stop the SO main loop
 * @ignore
 */
function _stopRunLoop() {
    // cancel any previous animationRequestFrame
    window.cancelAnimationFrame(_animFrameId);
    _animFrameId = -1;
}

/**
 * start the SO main loop
 * @ignore
 */
function _switchState(state) {
    // clear previous interval if any
    _stopRunLoop();

    // call the stage destroy method
    if (_stages[_state]) {
        // just notify the object
        _stages[_state].stage.destroy();
    }

    if (_stages[state]) {
        // set the global variable
        _state = state;

        // call the reset function with _extraArgs as arguments
        _stages[_state].stage.reset.apply(_stages[_state].stage, _extraArgs);

        // and start the main loop of the
        // new requested state
        _startRunLoop();

        // execute callback if defined
        if (_onSwitchComplete) {
            _onSwitchComplete();
        }

        // force repaint
        game.repaint();
    }
}

/**
 * a State Manager (state machine)
 * @namespace state
 * @memberOf me
 */

var state = {

    /**
     * default state ID for Loading Stage
     * @constant
     * @name LOADING
     * @memberOf me.state
     */
    LOADING : 0,

    /**
     * default state ID for Menu Stage
     * @constant
     * @name MENU
     * @memberOf me.state
     */
    MENU : 1,

    /**
     * default state ID for "Ready" Stage
     * @constant
     * @name READY
     * @memberOf me.state
     */
    READY : 2,

    /**
     * default state ID for Play Stage
     * @constant
     * @name PLAY
     * @memberOf me.state
     */
    PLAY : 3,

    /**
     * default state ID for Game Over Stage
     * @constant
     * @name GAMEOVER
     * @memberOf me.state
     */
    GAMEOVER : 4,

    /**
     * default state ID for Game End Stage
     * @constant
     * @name GAME_END
     * @memberOf me.state
     */
    GAME_END : 5,

    /**
     * default state ID for High Score Stage
     * @constant
     * @name SCORE
     * @memberOf me.state
     */
    SCORE : 6,

    /**
     * default state ID for Credits Stage
     * @constant
     * @name CREDITS
     * @memberOf me.state
     */
    CREDITS : 7,

    /**
     * default state ID for Settings Stage
     * @constant
     * @name SETTINGS
     * @memberOf me.state
     */
    SETTINGS : 8,

    /**
     * default state ID for the default Stage
     * (the default stage is the one running as soon as melonJS is started)
     * @constant
     * @name SETTINGS
     * @memberOf me.state
     */
    DEFAULT : 9,

    /**
     * default state ID for user defined constants

     * @constant
     * @name USER
     * @memberOf me.state
     * @example
     * var STATE_INFO = me.state.USER + 0;
     * var STATE_WARN = me.state.USER + 1;
     * var STATE_ERROR = me.state.USER + 2;
     * var STATE_CUTSCENE = me.state.USER + 3;
     */
    USER : 100,

    /**
     * onPause callback
     * @function
     * @name onPause
     * @memberOf me.state
     */
    onPause : null,

    /**
     * onResume callback
     * @function
     * @name onResume
     * @memberOf me.state
     */
    onResume : null,

    /**
     * onStop callback
     * @function
     * @name onStop
     * @memberOf me.state
     */
    onStop : null,

    /**
     * onRestart callback
     * @function
     * @name onRestart
     * @memberOf me.state
     */
    onRestart : null,

    /**
     * @ignore
     */
    init() {
        // set the built-in loading stage
        this.set(this.LOADING, defaultLoadingScreen);
        // set and enable the default stage
        this.set(this.DEFAULT, new Stage());
        // enable by default as soon as the display is initialized
        var _state = this;
        event.subscribe(event.VIDEO_INIT, function () {
            _state.change(_state.DEFAULT, true);
        });
    },

    /**
     * Stop the current screen object.
     * @name stop
     * @memberOf me.state
     * @public
     * @function
     * @param {Boolean} pauseTrack pause current track on screen stop.
     */
    stop(music) {
        // only stop when we are not loading stuff
        if ((_state !== this.LOADING) && this.isRunning()) {
            // stop the main loop
            _stopRunLoop();
            // current music stop
            if (music === true) {
                audio.pauseTrack();
            }

            // store time when stopped
            _pauseTime = window.performance.now();

            // publish the stop notification
            event.publish(event.STATE_STOP);
            // any callback defined ?
            if (typeof(this.onStop) === "function") {
                this.onStop();
            }
        }
    },

    /**
     * pause the current screen object
     * @name pause
     * @memberOf me.state
     * @public
     * @function
     * @param {Boolean} pauseTrack pause current track on screen pause
     */
    pause(music) {
        // only pause when we are not loading stuff
        if ((_state !== this.LOADING) && !this.isPaused()) {
            // stop the main loop
            _pauseRunLoop();
            // current music stop
            if (music === true) {
                audio.pauseTrack();
            }

            // store time when paused
            _pauseTime = window.performance.now();

            // publish the pause event
            event.publish(event.STATE_PAUSE);
            // any callback defined ?
            if (typeof(this.onPause) === "function") {
                this.onPause();
            }
        }
    },

    /**
     * Restart the screen object from a full stop.
     * @name restart
     * @memberOf me.state
     * @public
     * @function
     * @param {Boolean} resumeTrack resume current track on screen resume
     */
    restart(music) {
        if (!this.isRunning()) {
            // restart the main loop
            _startRunLoop();
            // current music stop
            if (music === true) {
                audio.resumeTrack();
            }

            // calculate the elpased time
            _pauseTime = window.performance.now() - _pauseTime;

            // force repaint
            game.repaint();

            // publish the restart notification
            event.publish(event.STATE_RESTART, [ _pauseTime ]);
            // any callback defined ?
            if (typeof(this.onRestart) === "function") {
                this.onRestart();
            }
        }
    },

    /**
     * resume the screen object
     * @name resume
     * @memberOf me.state
     * @public
     * @function
     * @param {Boolean} resumeTrack resume current track on screen resume
     */
    resume(music) {
        if (this.isPaused()) {
            // resume the main loop
            _resumeRunLoop();
            // current music stop
            if (music === true) {
                audio.resumeTrack();
            }

            // calculate the elpased time
            _pauseTime = window.performance.now() - _pauseTime;

            // publish the resume event
            event.publish(event.STATE_RESUME, [ _pauseTime ]);
            // any callback defined ?
            if (typeof(this.onResume) === "function") {
                this.onResume();
            }
        }
    },

    /**
     * return the running state of the state manager
     * @name isRunning
     * @memberOf me.state
     * @public
     * @function
     * @return {Boolean} true if a "process is running"
     */
    isRunning() {
        return _animFrameId !== -1;
    },

    /**
     * Return the pause state of the state manager
     * @name isPaused
     * @memberOf me.state
     * @public
     * @function
     * @return {Boolean} true if the game is paused
     */
    isPaused() {
        return _isPaused;
    },

    /**
     * associate the specified state with a Stage
     * @name set
     * @memberOf me.state
     * @public
     * @function
     * @param {Number} state State ID (see constants)
     * @param {me.Stage} stage Instantiated Stage to associate with state ID
     * @param {Boolean} [start = false] if true the state will be changed immediately after adding it.
     * @example
     * var MenuButton = me.GUI_Object.extend({
     *     "onClick" : function () {
     *         // Change to the PLAY state when the button is clicked
     *         me.state.change(me.state.PLAY);
     *         return true;
     *     }
     * });
     *
     * var MenuScreen = me.Stage.extend({
     *     onResetEvent: function() {
     *         // Load background image
     *         me.game.world.addChild(
     *             new me.ImageLayer(0, 0, {
     *                 image : "bg",
     *                 z: 0 // z-index
     *             }
     *         );
     *
     *         // Add a button
     *         me.game.world.addChild(
     *             new MenuButton(350, 200, { "image" : "start" }),
     *             1 // z-index
     *         );
     *
     *         // Play music
     *         me.audio.playTrack("menu");
     *     },
     *
     *     "onDestroyEvent" : function () {
     *         // Stop music
     *         me.audio.stopTrack();
     *     }
     * });
     *
     * me.state.set(me.state.MENU, new MenuScreen());
     */
    set(state, stage, start) {
        if (typeof stage !== "undefined" && stage.constructor === Stage) {
            throw new Error(stage + " is not an instance of me.Stage");
        }
        _stages[state] = {};
        _stages[state].stage = stage;
        _stages[state].transition = true;

        if (start === true) {
            this.change(state);
        }
    },

    /**
     * return a reference to the current screen object

     * useful to call a object specific method
     * @name current
     * @memberOf me.state
     * @public
     * @function
     * @return {me.Stage}
     */
    current() {
        if (typeof _stages[_state] !== "undefined") {
            return _stages[_state].stage;
        }
    },

    /**
     * specify a global transition effect
     * @name transition
     * @memberOf me.state
     * @public
     * @function
     * @param {String} effect (only "fade" is supported for now)
     * @param {me.Color|String} color a CSS color value
     * @param {Number} [duration=1000] expressed in milliseconds
     */
    transition(effect, color, duration) {
        if (effect === "fade") {
            _fade.color = color;
            _fade.duration = duration;
        }
    },

    /**
     * enable/disable transition for a specific state (by default enabled for all)
     * @name setTransition
     * @memberOf me.state
     * @public
     * @function
     * @param {Number} state State ID (see constants)
     * @param {Boolean} enable
     */
    setTransition(state, enable) {
        _stages[state].transition = enable;
    },

    /**
     * change the game/app state
     * @name change
     * @memberOf me.state
     * @public
     * @function
     * @param {Number} state State ID (see constants)
     * @param {Boolean} forceChange if true the state will be changed immediately
     * @param {} [arguments...] extra arguments to be passed to the reset functions
     * @example
     * // The onResetEvent method on the play screen will receive two args:
     * // "level_1" and the number 3
     * me.state.change(me.state.PLAY, "level_1", 3);
     */
    change(state, forceChange) {
        // Protect against undefined Stage
        if (typeof(_stages[state]) === "undefined") {
            throw new Error("Undefined Stage for state '" + state + "'");
        }

        if (this.isCurrent(state)) {
            // do nothing if already the current state
            return;
        }

        _extraArgs = null;
        if (arguments.length > 1) {
            // store extra arguments if any
            _extraArgs = Array.prototype.slice.call(arguments, 1);
        }
        // if fading effect
        if (_fade.duration && _stages[state].transition) {
            /** @ignore */
            _onSwitchComplete = function() {
                game.viewport.fadeOut(_fade.color, _fade.duration);
            };
            game.viewport.fadeIn(
                _fade.color,
                _fade.duration,
                function () {
                    utils.function.defer(_switchState, this, state);
                }
            );

        }
        // else just switch without any effects
        else {
            // wait for the last frame to be
            // "finished" before switching
            if (forceChange === true) {
                _switchState(state);
            } else {
                utils.function.defer(_switchState, this, state);
            }
        }
    },

    /**
     * return true if the specified state is the current one
     * @name isCurrent
     * @memberOf me.state
     * @public
     * @function
     * @param {Number} state State ID (see constants)
     */
    isCurrent(state) {
        return _state === state;
    }

};
export default state;
<commit_msg>Revert "workaround for instanceof not properly working in es6 mode with Jay inheritance"<commit_after>import audio from "./../audio/audio.js";
import utils from "./../utils/utils.js";
import event from "./../system/event.js";
import timer from "./../system/timer.js";
import game from "./../game.js";
import Stage from "./../state/stage.js";
import defaultLoadingScreen from "./../loader/loadingscreen.js";

// current state
var _state = -1;

// requestAnimeFrame Id
var _animFrameId = -1;

// whether the game state is "paused"
var _isPaused = false;

// list of stages
var _stages = {};

// fading transition parameters between screen
var _fade = {
    color : "",
    duration : 0
};

// callback when state switch is done
/** @ignore */
var _onSwitchComplete = null;

// just to keep track of possible extra arguments
var _extraArgs = null;

// store the elapsed time during pause/stop period
var _pauseTime = 0;

/**
 * @ignore
 */
function _startRunLoop() {
    // ensure nothing is running first and in valid state
    if ((_animFrameId === -1) && (_state !== -1)) {
        // reset the timer
        timer.reset();

        // start the main loop
        _animFrameId = window.requestAnimationFrame(_renderFrame);
    }
}

/**
 * Resume the game loop after a pause.
 * @ignore
 */
function _resumeRunLoop() {
    // ensure game is actually paused and in valid state
    if (_isPaused && (_state !== -1)) {
        // reset the timer
        timer.reset();

        _isPaused = false;
    }
}

/**
 * Pause the loop for most screen objects.
 * @ignore
 */
function _pauseRunLoop() {
    // Set the paused boolean to stop updates on (most) entities
    _isPaused = true;
}

/**
 * this is only called when using requestAnimFrame stuff
 * @param {Number} time current timestamp in milliseconds
 * @ignore
 */
function _renderFrame(time) {
    var stage = _stages[_state].stage;
    // update all game objects
    game.update(time, stage);
    // render all game objects
    game.draw(stage);
    // schedule the next frame update
    if (_animFrameId !== -1) {
        _animFrameId = window.requestAnimationFrame(_renderFrame);
    }
}

/**
 * stop the SO main loop
 * @ignore
 */
function _stopRunLoop() {
    // cancel any previous animationRequestFrame
    window.cancelAnimationFrame(_animFrameId);
    _animFrameId = -1;
}

/**
 * start the SO main loop
 * @ignore
 */
function _switchState(state) {
    // clear previous interval if any
    _stopRunLoop();

    // call the stage destroy method
    if (_stages[_state]) {
        // just notify the object
        _stages[_state].stage.destroy();
    }

    if (_stages[state]) {
        // set the global variable
        _state = state;

        // call the reset function with _extraArgs as arguments
        _stages[_state].stage.reset.apply(_stages[_state].stage, _extraArgs);

        // and start the main loop of the
        // new requested state
        _startRunLoop();

        // execute callback if defined
        if (_onSwitchComplete) {
            _onSwitchComplete();
        }

        // force repaint
        game.repaint();
    }
}

/**
 * a State Manager (state machine)
 * @namespace state
 * @memberOf me
 */

var state = {

    /**
     * default state ID for Loading Stage
     * @constant
     * @name LOADING
     * @memberOf me.state
     */
    LOADING : 0,

    /**
     * default state ID for Menu Stage
     * @constant
     * @name MENU
     * @memberOf me.state
     */
    MENU : 1,

    /**
     * default state ID for "Ready" Stage
     * @constant
     * @name READY
     * @memberOf me.state
     */
    READY : 2,

    /**
     * default state ID for Play Stage
     * @constant
     * @name PLAY
     * @memberOf me.state
     */
    PLAY : 3,

    /**
     * default state ID for Game Over Stage
     * @constant
     * @name GAMEOVER
     * @memberOf me.state
     */
    GAMEOVER : 4,

    /**
     * default state ID for Game End Stage
     * @constant
     * @name GAME_END
     * @memberOf me.state
     */
    GAME_END : 5,

    /**
     * default state ID for High Score Stage
     * @constant
     * @name SCORE
     * @memberOf me.state
     */
    SCORE : 6,

    /**
     * default state ID for Credits Stage
     * @constant
     * @name CREDITS
     * @memberOf me.state
     */
    CREDITS : 7,

    /**
     * default state ID for Settings Stage
     * @constant
     * @name SETTINGS
     * @memberOf me.state
     */
    SETTINGS : 8,

    /**
     * default state ID for the default Stage
     * (the default stage is the one running as soon as melonJS is started)
     * @constant
     * @name SETTINGS
     * @memberOf me.state
     */
    DEFAULT : 9,

    /**
     * default state ID for user defined constants

     * @constant
     * @name USER
     * @memberOf me.state
     * @example
     * var STATE_INFO = me.state.USER + 0;
     * var STATE_WARN = me.state.USER + 1;
     * var STATE_ERROR = me.state.USER + 2;
     * var STATE_CUTSCENE = me.state.USER + 3;
     */
    USER : 100,

    /**
     * onPause callback
     * @function
     * @name onPause
     * @memberOf me.state
     */
    onPause : null,

    /**
     * onResume callback
     * @function
     * @name onResume
     * @memberOf me.state
     */
    onResume : null,

    /**
     * onStop callback
     * @function
     * @name onStop
     * @memberOf me.state
     */
    onStop : null,

    /**
     * onRestart callback
     * @function
     * @name onRestart
     * @memberOf me.state
     */
    onRestart : null,

    /**
     * @ignore
     */
    init() {
        // set the built-in loading stage
        this.set(this.LOADING, defaultLoadingScreen);
        // set and enable the default stage
        this.set(this.DEFAULT, new Stage());
        // enable by default as soon as the display is initialized
        var _state = this;
        event.subscribe(event.VIDEO_INIT, function () {
            _state.change(_state.DEFAULT, true);
        });
    },

    /**
     * Stop the current screen object.
     * @name stop
     * @memberOf me.state
     * @public
     * @function
     * @param {Boolean} pauseTrack pause current track on screen stop.
     */
    stop(music) {
        // only stop when we are not loading stuff
        if ((_state !== this.LOADING) && this.isRunning()) {
            // stop the main loop
            _stopRunLoop();
            // current music stop
            if (music === true) {
                audio.pauseTrack();
            }

            // store time when stopped
            _pauseTime = window.performance.now();

            // publish the stop notification
            event.publish(event.STATE_STOP);
            // any callback defined ?
            if (typeof(this.onStop) === "function") {
                this.onStop();
            }
        }
    },

    /**
     * pause the current screen object
     * @name pause
     * @memberOf me.state
     * @public
     * @function
     * @param {Boolean} pauseTrack pause current track on screen pause
     */
    pause(music) {
        // only pause when we are not loading stuff
        if ((_state !== this.LOADING) && !this.isPaused()) {
            // stop the main loop
            _pauseRunLoop();
            // current music stop
            if (music === true) {
                audio.pauseTrack();
            }

            // store time when paused
            _pauseTime = window.performance.now();

            // publish the pause event
            event.publish(event.STATE_PAUSE);
            // any callback defined ?
            if (typeof(this.onPause) === "function") {
                this.onPause();
            }
        }
    },

    /**
     * Restart the screen object from a full stop.
     * @name restart
     * @memberOf me.state
     * @public
     * @function
     * @param {Boolean} resumeTrack resume current track on screen resume
     */
    restart(music) {
        if (!this.isRunning()) {
            // restart the main loop
            _startRunLoop();
            // current music stop
            if (music === true) {
                audio.resumeTrack();
            }

            // calculate the elpased time
            _pauseTime = window.performance.now() - _pauseTime;

            // force repaint
            game.repaint();

            // publish the restart notification
            event.publish(event.STATE_RESTART, [ _pauseTime ]);
            // any callback defined ?
            if (typeof(this.onRestart) === "function") {
                this.onRestart();
            }
        }
    },

    /**
     * resume the screen object
     * @name resume
     * @memberOf me.state
     * @public
     * @function
     * @param {Boolean} resumeTrack resume current track on screen resume
     */
    resume(music) {
        if (this.isPaused()) {
            // resume the main loop
            _resumeRunLoop();
            // current music stop
            if (music === true) {
                audio.resumeTrack();
            }

            // calculate the elpased time
            _pauseTime = window.performance.now() - _pauseTime;

            // publish the resume event
            event.publish(event.STATE_RESUME, [ _pauseTime ]);
            // any callback defined ?
            if (typeof(this.onResume) === "function") {
                this.onResume();
            }
        }
    },

    /**
     * return the running state of the state manager
     * @name isRunning
     * @memberOf me.state
     * @public
     * @function
     * @return {Boolean} true if a "process is running"
     */
    isRunning() {
        return _animFrameId !== -1;
    },

    /**
     * Return the pause state of the state manager
     * @name isPaused
     * @memberOf me.state
     * @public
     * @function
     * @return {Boolean} true if the game is paused
     */
    isPaused() {
        return _isPaused;
    },

    /**
     * associate the specified state with a Stage
     * @name set
     * @memberOf me.state
     * @public
     * @function
     * @param {Number} state State ID (see constants)
     * @param {me.Stage} stage Instantiated Stage to associate with state ID
     * @param {Boolean} [start = false] if true the state will be changed immediately after adding it.
     * @example
     * var MenuButton = me.GUI_Object.extend({
     *     "onClick" : function () {
     *         // Change to the PLAY state when the button is clicked
     *         me.state.change(me.state.PLAY);
     *         return true;
     *     }
     * });
     *
     * var MenuScreen = me.Stage.extend({
     *     onResetEvent: function() {
     *         // Load background image
     *         me.game.world.addChild(
     *             new me.ImageLayer(0, 0, {
     *                 image : "bg",
     *                 z: 0 // z-index
     *             }
     *         );
     *
     *         // Add a button
     *         me.game.world.addChild(
     *             new MenuButton(350, 200, { "image" : "start" }),
     *             1 // z-index
     *         );
     *
     *         // Play music
     *         me.audio.playTrack("menu");
     *     },
     *
     *     "onDestroyEvent" : function () {
     *         // Stop music
     *         me.audio.stopTrack();
     *     }
     * });
     *
     * me.state.set(me.state.MENU, new MenuScreen());
     */
    set(state, stage, start) {
        if (!(stage instanceof Stage)) {
            throw new Error(stage + " is not an instance of me.Stage");
        }
        _stages[state] = {};
        _stages[state].stage = stage;
        _stages[state].transition = true;

        if (start === true) {
            this.change(state);
        }
    },

    /**
     * return a reference to the current screen object

     * useful to call a object specific method
     * @name current
     * @memberOf me.state
     * @public
     * @function
     * @return {me.Stage}
     */
    current() {
        if (typeof _stages[_state] !== "undefined") {
            return _stages[_state].stage;
        }
    },

    /**
     * specify a global transition effect
     * @name transition
     * @memberOf me.state
     * @public
     * @function
     * @param {String} effect (only "fade" is supported for now)
     * @param {me.Color|String} color a CSS color value
     * @param {Number} [duration=1000] expressed in milliseconds
     */
    transition(effect, color, duration) {
        if (effect === "fade") {
            _fade.color = color;
            _fade.duration = duration;
        }
    },

    /**
     * enable/disable transition for a specific state (by default enabled for all)
     * @name setTransition
     * @memberOf me.state
     * @public
     * @function
     * @param {Number} state State ID (see constants)
     * @param {Boolean} enable
     */
    setTransition(state, enable) {
        _stages[state].transition = enable;
    },

    /**
     * change the game/app state
     * @name change
     * @memberOf me.state
     * @public
     * @function
     * @param {Number} state State ID (see constants)
     * @param {Boolean} forceChange if true the state will be changed immediately
     * @param {} [arguments...] extra arguments to be passed to the reset functions
     * @example
     * // The onResetEvent method on the play screen will receive two args:
     * // "level_1" and the number 3
     * me.state.change(me.state.PLAY, "level_1", 3);
     */
    change(state, forceChange) {
        // Protect against undefined Stage
        if (typeof(_stages[state]) === "undefined") {
            throw new Error("Undefined Stage for state '" + state + "'");
        }

        if (this.isCurrent(state)) {
            // do nothing if already the current state
            return;
        }

        _extraArgs = null;
        if (arguments.length > 1) {
            // store extra arguments if any
            _extraArgs = Array.prototype.slice.call(arguments, 1);
        }
        // if fading effect
        if (_fade.duration && _stages[state].transition) {
            /** @ignore */
            _onSwitchComplete = function() {
                game.viewport.fadeOut(_fade.color, _fade.duration);
            };
            game.viewport.fadeIn(
                _fade.color,
                _fade.duration,
                function () {
                    utils.function.defer(_switchState, this, state);
                }
            );

        }
        // else just switch without any effects
        else {
            // wait for the last frame to be
            // "finished" before switching
            if (forceChange === true) {
                _switchState(state);
            } else {
                utils.function.defer(_switchState, this, state);
            }
        }
    },

    /**
     * return true if the specified state is the current one
     * @name isCurrent
     * @memberOf me.state
     * @public
     * @function
     * @param {Number} state State ID (see constants)
     */
    isCurrent(state) {
        return _state === state;
    }

};
export default state;
<|endoftext|>


<commit_before>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Class = require('../../utils/Class');
var Utils = require('../../renderer/webgl/Utils');
var Vector3 = require('../../math/Vector3');

/**
 * @classdesc
 * A Vertex Geometry Object.
 *
 * This class consists of all the information required for a single vertex within a Face Geometry Object.
 *
 * Faces, and thus Vertex objects, are used by the Mesh Game Object in order to render objects in WebGL.
 *
 * @class Vertex
 * @memberof Phaser.Geom.Mesh
 * @constructor
 * @extends Phaser.Math.Vector3
 * @since 3.50.0
 *
 * @param {number} x - The x position of the vertex.
 * @param {number} y - The y position of the vertex.
 * @param {number} z - The z position of the vertex.
 * @param {number} u - The UV u coordinate of the vertex.
 * @param {number} v - The UV v coordinate of the vertex.
 * @param {number} [color=0xffffff] - The color value of the vertex.
 * @param {number} [alpha=1] - The alpha value of the vertex.
 */
var Vertex = new Class({

    Extends: Vector3,

    initialize:

    function Vertex (x, y, z, u, v, color, alpha, nx, ny, nz)
    {
        if (color === undefined) { color = 0xffffff; }
        if (alpha === undefined) { alpha = 1; }
        if (nx === undefined) { nx = 0; }
        if (ny === undefined) { ny = 0; }
        if (nz === undefined) { nz = 0; }

        Vector3.call(this, x, y, z);

        /**
         * The projected x coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vx
         * @type {number}
         * @since 3.50.0
         */
        this.vx = 0;

        /**
         * The projected y coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vy
         * @type {number}
         * @since 3.50.0
         */
        this.vy = 0;

        /**
         * The projected z coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vz
         * @type {number}
         * @since 3.50.0
         */
        this.vz = 0;

        /**
         * The projected x coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vx
         * @type {number}
         * @since 3.50.0
         */
        this.nx = nx;

        /**
         * The projected y coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vy
         * @type {number}
         * @since 3.50.0
         */
        this.ny = ny;

        /**
         * The projected z coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vz
         * @type {number}
         * @since 3.50.0
         */
        this.nz = nz;

        /**
         * UV u coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#u
         * @type {number}
         * @since 3.50.0
         */
        this.u = u;

        /**
         * UV v coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#v
         * @type {number}
         * @since 3.50.0
         */
        this.v = v;

        /**
         * The color value of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#color
         * @type {number}
         * @since 3.50.0
         */
        this.color = color;

        /**
         * The alpha value of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#alpha
         * @type {number}
         * @since 3.50.0
         */
        this.alpha = alpha;
    },

    /**
     * Transforms this vertex by the given matrix, storing the results in `vx`, `vy` and `vz`.
     *
     * @method Phaser.Geom.Mesh.Vertex#transformCoordinatesLocal
     * @since 3.50.0
     *
     * @param {Phaser.Math.Matrix4} transformMatrix - The transform matrix to apply to this vertex.
     * @param {number} width - The width of the parent Mesh.
     * @param {number} height - The height of the parent Mesh.
     * @param {number} cameraZ - The z position of the MeshCamera.
     */
    transformCoordinatesLocal: function (transformMatrix, width, height, cameraZ)
    {
        var x = this.x;
        var y = this.y;
        var z = this.z;

        var m = transformMatrix.val;

        var tx = (x * m[0]) + (y * m[4]) + (z * m[8]) + m[12];
        var ty = (x * m[1]) + (y * m[5]) + (z * m[9]) + m[13];
        var tz = (x * m[2]) + (y * m[6]) + (z * m[10]) + m[14];
        var tw = (x * m[3]) + (y * m[7]) + (z * m[11]) + m[15];

        this.vx = (tx / tw) * width;
        this.vy = -(ty / tw) * height;

        if (cameraZ <= 0)
        {
            this.vz = (tz / tw);
        }
        else
        {
            this.vz = -(tz / tw);
        }
    },

    /**
     * Loads the data from this Vertex into the given Typed Arrays.
     *
     * @method Phaser.Geom.Mesh.Vertex#load
     * @since 3.50.0
     *
     * @param {Float32Array} F32 - A Float32 Array to insert the position, UV and unit data in to.
     * @param {Uint32Array} U32 - A Uint32 Array to insert the color and alpha data in to.
     * @param {number} offset - The index of the array to insert this Vertex to.
     * @param {number} textureUnit - The texture unit currently in use.
     * @param {number} alpha - The alpha of the parent object.
     * @param {number} a - The parent transform matrix data a component.
     * @param {number} b - The parent transform matrix data b component.
     * @param {number} c - The parent transform matrix data c component.
     * @param {number} d - The parent transform matrix data d component.
     * @param {number} e - The parent transform matrix data e component.
     * @param {number} f - The parent transform matrix data f component.
     * @param {boolean} roundPixels - Round the vertex position or not?
     *
     * @return {number} The new array offset.
     */
    load: function (F32, U32, offset, textureUnit, tintEffect, alpha, a, b, c, d, e, f, roundPixels)
    {
        var tx = this.vx * a + this.vy * c + e;
        var ty = this.vx * b + this.vy * d + f;

        if (roundPixels)
        {
            tx = Math.round(tx);
            ty = Math.round(ty);
        }

        F32[++offset] = tx;
        F32[++offset] = ty;
        F32[++offset] = this.u;
        F32[++offset] = this.v;
        F32[++offset] = textureUnit;
        F32[++offset] = tintEffect;
        U32[++offset] = Utils.getTintAppendFloatAlpha(this.color, alpha * this.alpha);

        return offset;
    }

});

module.exports = Vertex;
<commit_msg>Added JSDocs<commit_after>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Class = require('../../utils/Class');
var Utils = require('../../renderer/webgl/Utils');
var Vector3 = require('../../math/Vector3');

/**
 * @classdesc
 * A Vertex Geometry Object.
 *
 * This class consists of all the information required for a single vertex within a Face Geometry Object.
 *
 * Faces, and thus Vertex objects, are used by the Mesh Game Object in order to render objects in WebGL.
 *
 * @class Vertex
 * @memberof Phaser.Geom.Mesh
 * @constructor
 * @extends Phaser.Math.Vector3
 * @since 3.50.0
 *
 * @param {number} x - The x position of the vertex.
 * @param {number} y - The y position of the vertex.
 * @param {number} z - The z position of the vertex.
 * @param {number} u - The UV u coordinate of the vertex.
 * @param {number} v - The UV v coordinate of the vertex.
 * @param {number} [color=0xffffff] - The color value of the vertex.
 * @param {number} [alpha=1] - The alpha value of the vertex.
 * @param {number} [nx=0] - The x normal value of the vertex.
 * @param {number} [ny=0] - The y normal value of the vertex.
 * @param {number} [nz=0] - The z normal value of the vertex.
 */
var Vertex = new Class({

    Extends: Vector3,

    initialize:

    function Vertex (x, y, z, u, v, color, alpha, nx, ny, nz)
    {
        if (color === undefined) { color = 0xffffff; }
        if (alpha === undefined) { alpha = 1; }
        if (nx === undefined) { nx = 0; }
        if (ny === undefined) { ny = 0; }
        if (nz === undefined) { nz = 0; }

        Vector3.call(this, x, y, z);

        /**
         * The projected x coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vx
         * @type {number}
         * @since 3.50.0
         */
        this.vx = 0;

        /**
         * The projected y coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vy
         * @type {number}
         * @since 3.50.0
         */
        this.vy = 0;

        /**
         * The projected z coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vz
         * @type {number}
         * @since 3.50.0
         */
        this.vz = 0;

        /**
         * The projected x coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vx
         * @type {number}
         * @since 3.50.0
         */
        this.nx = nx;

        /**
         * The projected y coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vy
         * @type {number}
         * @since 3.50.0
         */
        this.ny = ny;

        /**
         * The projected z coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vz
         * @type {number}
         * @since 3.50.0
         */
        this.nz = nz;

        /**
         * UV u coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#u
         * @type {number}
         * @since 3.50.0
         */
        this.u = u;

        /**
         * UV v coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#v
         * @type {number}
         * @since 3.50.0
         */
        this.v = v;

        /**
         * The color value of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#color
         * @type {number}
         * @since 3.50.0
         */
        this.color = color;

        /**
         * The alpha value of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#alpha
         * @type {number}
         * @since 3.50.0
         */
        this.alpha = alpha;
    },

    /**
     * Transforms this vertex by the given matrix, storing the results in `vx`, `vy` and `vz`.
     *
     * @method Phaser.Geom.Mesh.Vertex#transformCoordinatesLocal
     * @since 3.50.0
     *
     * @param {Phaser.Math.Matrix4} transformMatrix - The transform matrix to apply to this vertex.
     * @param {number} width - The width of the parent Mesh.
     * @param {number} height - The height of the parent Mesh.
     * @param {number} cameraZ - The z position of the MeshCamera.
     */
    transformCoordinatesLocal: function (transformMatrix, width, height, cameraZ)
    {
        var x = this.x;
        var y = this.y;
        var z = this.z;

        var m = transformMatrix.val;

        var tx = (x * m[0]) + (y * m[4]) + (z * m[8]) + m[12];
        var ty = (x * m[1]) + (y * m[5]) + (z * m[9]) + m[13];
        var tz = (x * m[2]) + (y * m[6]) + (z * m[10]) + m[14];
        var tw = (x * m[3]) + (y * m[7]) + (z * m[11]) + m[15];

        this.vx = (tx / tw) * width;
        this.vy = -(ty / tw) * height;

        if (cameraZ <= 0)
        {
            this.vz = (tz / tw);
        }
        else
        {
            this.vz = -(tz / tw);
        }
    },

    /**
     * Loads the data from this Vertex into the given Typed Arrays.
     *
     * @method Phaser.Geom.Mesh.Vertex#load
     * @since 3.50.0
     *
     * @param {Float32Array} F32 - A Float32 Array to insert the position, UV and unit data in to.
     * @param {Uint32Array} U32 - A Uint32 Array to insert the color and alpha data in to.
     * @param {number} offset - The index of the array to insert this Vertex to.
     * @param {number} textureUnit - The texture unit currently in use.
     * @param {number} alpha - The alpha of the parent object.
     * @param {number} a - The parent transform matrix data a component.
     * @param {number} b - The parent transform matrix data b component.
     * @param {number} c - The parent transform matrix data c component.
     * @param {number} d - The parent transform matrix data d component.
     * @param {number} e - The parent transform matrix data e component.
     * @param {number} f - The parent transform matrix data f component.
     * @param {boolean} roundPixels - Round the vertex position or not?
     *
     * @return {number} The new array offset.
     */
    load: function (F32, U32, offset, textureUnit, tintEffect, alpha, a, b, c, d, e, f, roundPixels)
    {
        var tx = this.vx * a + this.vy * c + e;
        var ty = this.vx * b + this.vy * d + f;

        if (roundPixels)
        {
            tx = Math.round(tx);
            ty = Math.round(ty);
        }

        F32[++offset] = tx;
        F32[++offset] = ty;
        F32[++offset] = this.u;
        F32[++offset] = this.v;
        F32[++offset] = textureUnit;
        F32[++offset] = tintEffect;
        U32[++offset] = Utils.getTintAppendFloatAlpha(this.color, alpha * this.alpha);

        return offset;
    }

});

module.exports = Vertex;
<|endoftext|>


<commit_before>import * as I from 'immutable';
import * as F from '../arithmetic/float';
import _M from '../arithmetic/matrix';
import _V from '../arithmetic/vector';

const M = _M(F, 0, 1);
const V = _V(F, 0);

const reductions = (xs, fn, init) =>
  xs.reduce((a, x) => a.push(fn(a.last(), x)), I.List([init]));

const pairs = as => as.pop().zip(as.shift()).push([as.last(), as.first()]);

const corners = pos => idcs => idcs.map(i => pos.get(i));

const centroid = pos => V.scaled(1/I.List(pos).size, pos.reduce(V.plus));

const dedupe = a => I.List(I.Set(a));

const projection = (origin, normal) => p => {
  const d = V.minus(p, origin);
  return V.plus(origin, V.minus(d, V.scaled(V.dotProduct(normal, d), normal)));
};

const faceNormal = vs => V.normalized(
  pairs(I.List(vs))
    .map(e => V.crossProduct(e[0], e[1]))
    .reduce(V.plus)
);

export function faceNormals(pos, faces) {
  return faces.map(corners(pos)).map(faceNormal);
};

export function vertexNormals(pos, faces, faceNormals) {
  const normals = pos.map(v => V.scaled(0, v)).asMutable();

  faces.forEach((f, i) => {
    const n = faceNormals.get(i);
    f.forEach(k => { normals.update(k, v => V.plus(v, n)); });
  });

  return normals.map(V.normalized);
};

const edgeIndexes = faces => {
  const eKey     = ([v, w]) => I.List(v < w ? [v, w] : [w, v]);
  const edges    = dedupe(faces.flatMap(is => pairs(is).map(eKey)));
  const index    = I.Map(edges.map((e, i) => [e, i]));
  const findPair = ([v,w]) => index.get(eKey([v, w]));
  const lookup   = faces.map(is => pairs(is).map(findPair));

  return { edges, lookup }
};

const adjustedPositions = (faces, pos, isFixed) => {
  const coord = (face, idx, factor) => V.scaled(factor, pos.get(face.get(idx)));
  const facesByVertex = faces.groupBy(f => f.get(0));

  return pos.map((p, i) => {
    if (isFixed.get(i) || facesByVertex.get(i) == null)
      return p;

    const m = facesByVertex.get(i).size;
    const t = facesByVertex.get(i)
      .flatMap(f => [coord(f, 1, 2), coord(f, 3, 2), coord(f, 2, -1)])
      .reduce(V.plus);
    return V.plus(V.scaled(1/(m*m), t), V.scaled((m-3)/m, p));
  });
};

export function subD({ faces, pos, isFixed }) {
  const n = pos.size;
  const m = faces.size;
  const { edges, lookup } = edgeIndexes(faces);

  const newFaces = faces.flatMap((vs, f) => {
    const edge = i => n + m + lookup.get(f).get(i);
    const prev = i => (i + vs.size - 1) % vs.size;
    return vs.map((v, i) => I.List([v, edge(i), n + f, edge(prev(i))]));
  });

  const ffix = I.Repeat(false, faces.size);
  const fpos = faces.map(corners(pos)).map(centroid);

  const facesByEdge = lookup
    .flatMap((a, f) => a.map(e => [e, f]))
    .groupBy(([e, f]) => e)
    .map(a => a.map(([e, f]) => f));

  const efix = edges.map(([v, w]) => isFixed.get(v) && isFixed.get(w));
  const epos = edges.map(([v, w], i) => centroid(
    (efix.get(i) ? I.List() : facesByEdge.get(i).map(v => fpos.get(v)))
      .concat([pos.get(v), pos.get(w)])));

  return {
    pos    : adjustedPositions(newFaces, pos.concat(fpos, epos), isFixed),
    isFixed: isFixed.concat(ffix, efix),
    faces  : newFaces
  };
};

export function neighbors(faces) {
  return faces
    .flatMap(is => pairs(is).flatMap(([v, w]) => [[v, w], [w, v]]))
    .groupBy(([v, w]) => v)
    .map(a => dedupe(a.map(([v, w]) => w)))
  ;
};

export function smooth({ faces, pos, isFixed }) {
  const nbs = neighbors(faces);
  const newPositions = pos.map((p, i) => (
    isFixed.get(i) ? p : centroid(nbs.get(i).map(v => pos.get(v)))
  ));

  return {
    faces,
    pos: newPositions,
    isFixed
  };
};

const flattened = vs => vs.map(projection(centroid(vs), faceNormal(vs)));

const scaled = (f, vs) => {
  const c = centroid(vs);
  return vs.map(v => V.plus(V.scaled(f, v), V.scaled(1-f, c)));
};

const withCenterFaces = ({ faces, pos, isFixed }, fn) => {
  const centerFaces = faces
    .map(corners(pos))
    .map(vs => scaled(0.5, flattened(vs)));
  const offsets = reductions(centerFaces, (a, vs) => a + vs.size, pos.size);
  const extraPositions = centerFaces.flatten(1);

  const newFaces = faces.flatMap((is, f) => {
    const k = offsets.get(f);
    const m = is.size;
    const center = I.List(I.Range(k, k+m));
    const gallery = I.Range(0, m).map(i => {
      const j = (i + 1) % m;
      return I.List([is.get(i), is.get(j), j+k, i+k]);
    });
    return I.List(gallery).push(center);
  });

  return {
    faces  : newFaces,
    pos    : pos.concat(extraPositions),
    isFixed: isFixed.concat(extraPositions.map(p => false))
  };
};

export function withFlattenedCenterFaces(surface) {
  return withCenterFaces(surface, vs => scaled(0.5, flattened(vs)));
};

if (require.main == module) {
  const cube = {
    pos: I.fromJS([[0,0,0], [0,0,1], [0,1,0], [0,1,1],
                   [1,0,0], [1,0,1], [1,1,0], [1,1,1]]).map(V.make),
    faces: I.fromJS([[0,1,3,2],[5,4,6,7],
                     [1,0,4,5],[2,3,7,6],
                     [0,2,6,4],[3,1,5,7]]),
    isFixed: I.Range(0,8).map(i => i < 4)
  };

  const cds = {
    pos: I.fromJS([
      [-1,-1,-2], [-1,-1, 0], [-1,-1, 2],
      [-1, 1,-2], [-1, 1, 0], [-1, 1, 2],
      [ 1,-1,-2], [ 1,-1, 0], [ 1,-1, 2],
      [ 1, 1,-2], [ 1, 1, 0], [ 1, 1, 2]
    ]).map(V.make),

    faces: I.fromJS([
      [  6,  7,  8,  2,  1,  0],
      [  3,  4,  5, 11, 10,  9],
      [  1,  2,  8,  7, 10, 11,  5,  4],
      [  7,  6,  0,  1,  4,  3,  9, 10]
    ]),

    isFixed: I.Range(0, 12).map(i => true)
  };

  const normals = faceNormals(cube.pos, cube.faces);

  console.log(normals);

  console.log(vertexNormals(cube.pos, cube.faces, normals));

  console.log(subD(cube));
  console.log(smooth(cube));
  console.log(withFlattenedCenterFaces(cds));
}
<commit_msg>implement basic beveling<commit_after>import * as I from 'immutable';
import * as F from '../arithmetic/float';
import _M from '../arithmetic/matrix';
import _V from '../arithmetic/vector';

const M = _M(F, 0, 1);
const V = _V(F, 0);

const reductions = (xs, fn, init) =>
  xs.reduce((a, x) => a.push(fn(a.last(), x)), I.List([init]));

const pairs = as => as.pop().zip(as.shift()).push([as.last(), as.first()]);

const corners = pos => idcs => idcs.map(i => pos.get(i));

const centroid = pos => V.scaled(1/I.List(pos).size, pos.reduce(V.plus));

const dedupe = a => I.List(I.Set(a));

const projection = (normal, origin = V.scaled(0, normal)) => p => {
  const d = V.minus(p, origin);
  return V.plus(origin, V.minus(d, V.scaled(V.dotProduct(normal, d), normal)));
};

const faceNormal = vs => V.normalized(
  pairs(I.List(vs))
    .map(e => V.crossProduct(e[0], e[1]))
    .reduce(V.plus)
);

export function faceNormals(pos, faces) {
  return faces.map(corners(pos)).map(faceNormal);
};

export function vertexNormals(pos, faces, faceNormals) {
  const normals = pos.map(v => V.scaled(0, v)).asMutable();

  faces.forEach((f, i) => {
    const n = faceNormals.get(i);
    f.forEach(k => { normals.update(k, v => V.plus(v, n)); });
  });

  return normals.map(V.normalized);
};

const edgeIndexes = faces => {
  const eKey     = ([v, w]) => I.List(v < w ? [v, w] : [w, v]);
  const edges    = dedupe(faces.flatMap(is => pairs(is).map(eKey)));
  const index    = I.Map(edges.map((e, i) => [e, i]));
  const findPair = ([v,w]) => index.get(eKey([v, w]));
  const lookup   = faces.map(is => pairs(is).map(findPair));

  return { edges, lookup }
};

const adjustedPositions = (faces, pos, isFixed) => {
  const coord = (face, idx, factor) => V.scaled(factor, pos.get(face.get(idx)));
  const facesByVertex = faces.groupBy(f => f.get(0));

  return pos.map((p, i) => {
    if (isFixed.get(i) || facesByVertex.get(i) == null)
      return p;

    const m = facesByVertex.get(i).size;
    const t = facesByVertex.get(i)
      .flatMap(f => [coord(f, 1, 2), coord(f, 3, 2), coord(f, 2, -1)])
      .reduce(V.plus);
    return V.plus(V.scaled(1/(m*m), t), V.scaled((m-3)/m, p));
  });
};

export function subD({ faces, pos, isFixed }) {
  const n = pos.size;
  const m = faces.size;
  const { edges, lookup } = edgeIndexes(faces);

  const newFaces = faces.flatMap((vs, f) => {
    const edge = i => n + m + lookup.get(f).get(i);
    const prev = i => (i + vs.size - 1) % vs.size;
    return vs.map((v, i) => I.List([v, edge(i), n + f, edge(prev(i))]));
  });

  const ffix = I.Repeat(false, faces.size);
  const fpos = faces.map(corners(pos)).map(centroid);

  const facesByEdge = lookup
    .flatMap((a, f) => a.map(e => [e, f]))
    .groupBy(([e, f]) => e)
    .map(a => a.map(([e, f]) => f));

  const efix = edges.map(([v, w]) => isFixed.get(v) && isFixed.get(w));
  const epos = edges.map(([v, w], i) => centroid(
    (efix.get(i) ? I.List() : facesByEdge.get(i).map(v => fpos.get(v)))
      .concat([pos.get(v), pos.get(w)])));

  return {
    pos    : adjustedPositions(newFaces, pos.concat(fpos, epos), isFixed),
    isFixed: isFixed.concat(ffix, efix),
    faces  : newFaces
  };
};

export function neighbors(faces) {
  return faces
    .flatMap(is => pairs(is).flatMap(([v, w]) => [[v, w], [w, v]]))
    .groupBy(([v, w]) => v)
    .map(a => dedupe(a.map(([v, w]) => w)))
  ;
};

export function smooth({ faces, pos, isFixed }) {
  const nbs = neighbors(faces);
  const newPositions = pos.map((p, i) => (
    isFixed.get(i) ? p : centroid(nbs.get(i).map(v => pos.get(v)))
  ));

  return {
    faces,
    pos: newPositions,
    isFixed
  };
};

const flattened = vs => vs.map(projection(faceNormal(vs), centroid(vs)));

const scaled = (f, vs) => {
  const c = centroid(vs);
  return vs.map(v => V.plus(V.scaled(f, v), V.scaled(1-f, c)));
};

const withCenterFaces = ({ faces, pos, isFixed }, fn) => {
  const centerFaces = faces.map(corners(pos)).map(fn);
  const offsets = reductions(centerFaces, (a, vs) => a + vs.size, pos.size);
  const extraPositions = centerFaces.flatten(1);

  const newFaces = faces.flatMap((is, f) => {
    const k = offsets.get(f);
    const m = is.size;
    const center = I.List(I.Range(k, k+m));
    const gallery = I.Range(0, m).map(i => {
      const j = (i + 1) % m;
      return I.List([is.get(i), is.get(j), j+k, i+k]);
    });
    return I.List(gallery).push(center);
  });

  return {
    faces  : newFaces,
    pos    : pos.concat(extraPositions),
    isFixed: isFixed.concat(extraPositions.map(p => false))
  };
};

export function withFlattenedCenterFaces(surface) {
  return withCenterFaces(surface, vs => scaled(0.5, flattened(vs)));
};

export function beveled(surface, wd) {
  return withCenterFaces(surface, vs => {
    const n = vs.size;
    const c = centroid(vs);

    return vs.map((v, i) => {
      const vu = V.normalized(V.minus(vs.get((i + n - 1) % n), v));
      const vw = V.normalized(V.minus(vs.get((i + 1) % n), v));
      const d  = V.plus(vu, vw);
      const ln = wd * V.norm(d) / V.norm(projection(vu)(d));
      const s  = V.normalized(V.crossProduct(d, V.crossProduct(vu, vw)));
      const t  = projection(s)(V.minus(c, v));
      const f  = ln / V.norm(t);
      return V.plus(v, V.scaled(f, t));
    });
  });
};

if (require.main == module) {
  const cube = {
    pos: I.fromJS([[0,0,0], [0,0,1], [0,1,0], [0,1,1],
                   [1,0,0], [1,0,1], [1,1,0], [1,1,1]]).map(V.make),
    faces: I.fromJS([[0,1,3,2],[5,4,6,7],
                     [1,0,4,5],[2,3,7,6],
                     [0,2,6,4],[3,1,5,7]]),
    isFixed: I.Range(0,8).map(i => i < 4)
  };

  const cds = {
    pos: I.fromJS([
      [-1,-1,-2], [-1,-1, 0], [-1,-1, 2],
      [-1, 1,-2], [-1, 1, 0], [-1, 1, 2],
      [ 1,-1,-2], [ 1,-1, 0], [ 1,-1, 2],
      [ 1, 1,-2], [ 1, 1, 0], [ 1, 1, 2]
    ]).map(V.make),

    faces: I.fromJS([
      [  6,  7,  8,  2,  1,  0],
      [  3,  4,  5, 11, 10,  9],
      [  1,  2,  8,  7, 10, 11,  5,  4],
      [  7,  6,  0,  1,  4,  3,  9, 10]
    ]),

    isFixed: I.Range(0, 12).map(i => true)
  };

  const normals = faceNormals(cube.pos, cube.faces);

  console.log(normals);

  console.log(vertexNormals(cube.pos, cube.faces, normals));

  console.log(subD(cube));
  console.log(smooth(cube));
  console.log(withFlattenedCenterFaces(cds));
}
<|endoftext|>


<commit_before>$.fn.alchemyPageSelect = function(options) {
  var pageTemplate = HandlebarsTemplates.page

  this.select2({
    placeholder: options.placeholder,
    minimumInputLength: 3,
    initSelection: function (_$el, callback) {
      if (options.initialSelection) {
        callback(options.initialSelection)
      }
    },
    ajax: {
      url: options.url,
      datatype: 'json',
      quietMillis: 300,
      data: function (term, page) {
        return {
          q: $.extend({
            name_cont: term
          }, options.query_params),
          page: page
        }
      },
      results: function (data) {
        var meta = data.meta

        return {
          results: data.pages,
          more: meta.page * meta.per_page < meta.total_count
        }
      }
    },
    formatSelection: function (page) {
      return page.text || page.name
    },
    formatResult: function(page) {
      return pageTemplate({page: page})
    }
  })
}
<commit_msg>Allow alchemyPageSelect to be chained<commit_after>$.fn.alchemyPageSelect = function(options) {
  var pageTemplate = HandlebarsTemplates.page

  return this.select2({
    placeholder: options.placeholder,
    minimumInputLength: 3,
    initSelection: function (_$el, callback) {
      if (options.initialSelection) {
        callback(options.initialSelection)
      }
    },
    ajax: {
      url: options.url,
      datatype: 'json',
      quietMillis: 300,
      data: function (term, page) {
        return {
          q: $.extend({
            name_cont: term
          }, options.query_params),
          page: page
        }
      },
      results: function (data) {
        var meta = data.meta

        return {
          results: data.pages,
          more: meta.page * meta.per_page < meta.total_count
        }
      }
    },
    formatSelection: function (page) {
      return page.text || page.name
    },
    formatResult: function(page) {
      return pageTemplate({page: page})
    }
  })
}
<|endoftext|>


<commit_before>import Phaser from 'phaser';

export default class extends Phaser.State {
  init() {

  }

  preload() {
    var cursors
  }

  create() {
    this.physics.startSystem(Phaser.Physics.ARCADE);

    this.map = this.add.tilemap('map');
    this.map.addTilesetImage('grass');

    this.layer = this.map.createLayer('Tile Layer 1');
    this.map.setCollisionBetween(1, 100, true, 'Tile Layer 1');

    this.dan = this.add.sprite(0, 0, 'dan');
    this.physics.enable(this.dan, Phaser.Physics.ARCADE);
    this.dan.body.collideWorldBounds = true;
    this.dan.body.gravity.set(0, 180);

    this.cursors = this.game.input.keyboard.createCursorKeys();
  }

  update() {
    game.physics.arcade.collide(this.dan, this.layer);

    if (this.cursors.up.isDown && this.dan.body.onFloor()) {
      this.dan.body.velocity.y = -150;
    } else if (this.cursors.right.isDown) {
      this.dan.body.velocity.x = 150;
    } else if (this.cursors.right.isUp) {
      this.dan.body.velocity.x = 0;
    } else if (this.cursors.left.isDown) {
      this.dan.body.velocity.x = -150;
    } else if (this.cursors.left.isUp) {
      this.dan.body.velocity.x = 0;
    }

  }

  render() {

  }
}<commit_msg>added movement<commit_after>import Phaser from 'phaser';

export default class extends Phaser.State {
  init() {
    var cursors
  }

  preload() {

  }

  create() {
    this.physics.startSystem(Phaser.Physics.ARCADE);

    this.map = this.add.tilemap('map');
    this.map.addTilesetImage('grass');

    this.layer = this.map.createLayer('Tile Layer 1');
    this.map.setCollisionBetween(1, 100, true, 'Tile Layer 1');

    this.dan = this.add.sprite(0, 0, 'dan');
    this.physics.enable(this.dan, Phaser.Physics.ARCADE);
    this.dan.body.collideWorldBounds = true;
    this.dan.body.gravity.set(0, 180);

    this.cursors = this.game.input.keyboard.createCursorKeys();
  }

  update() {
    game.physics.arcade.collide(this.dan, this.layer);
    this.dan.body.velocity.x = 0;

    if (this.cursors.up.isDown && this.dan.body.onFloor()) {
      this.dan.body.velocity.y = -150;
    } else if (this.cursors.right.isDown) {
      console.log("right down");
      this.dan.body.velocity.x = 150;
    } else if (this.cursors.left.isDown) {
      console.log("left down");
      this.dan.body.velocity.x = -150;
    }

  }

  render() {

  }
}<|endoftext|>


<commit_before>// https://developers.google.com/analytics/devguides/collection/analyticsjs/enhanced-ecommerce
(function () {
  "use strict";
  window.GOVUK = window.GOVUK || {};

  var DEFAULT_LIST_TITLE = 'Site search results';

  var Ecommerce = function (config) {
    this.init = function (element) {
      // Limiting to 100 characters to avoid noise from extra longs search queries
      // and to stop the size of the payload going over 8k limit.
      var searchQuery   = GOVUK.analytics.stripPII(element.attr('data-search-query')).substring(0, 100).toLowerCase();
      var ecommerceRows = element.find('[data-ecommerce-row]');
      var startPosition = parseInt(element.data('ecommerce-start-index'), 10);
      var listTitle     = element.data('list-title') || DEFAULT_LIST_TITLE;

      ecommerceRows.each(function(index, ecommerceRow) {
        var $ecommerceRow = $(ecommerceRow);

        var contentId = $ecommerceRow.attr('data-ecommerce-content-id'),
          path = $ecommerceRow.attr('data-ecommerce-path');

        addImpression(contentId, path, index + startPosition, searchQuery, listTitle);
        trackProductOnClick($ecommerceRow, contentId, path, index + startPosition, searchQuery, listTitle);
      });
    }

    function addImpression (contentId, path, position, searchQuery, listTitle) {
      // We only add the id to GA as additional product data is linked when it is uploaded.
      // This approach is taken to avoid the GA data packet exceeding the 8k limit
      ga('ec:addImpression', {
        id: contentId || path,
        position: position,
        list: listTitle,
        dimension71: searchQuery
      });
    }

    function trackProductOnClick (row, contentId, path, position, searchQuery, listTitle) {
      row.click(function(event) {
        ga('ec:addProduct', {
          id: contentId || path,
          position: position,
          dimension71: searchQuery
        });

        ga('ec:setAction', 'click', {list: listTitle});
        GOVUK.analytics.trackEvent('UX', 'click',
          GOVUK.CustomDimensions.getAndExtendDefaultTrackingOptions({label: 'Results'})
        );
      });
    }
  }

  Ecommerce.ecLoaded = false;
  Ecommerce.start = function (element) {
    element = element || $('[data-analytics-ecommerce]');
    if(element.length > 0) {
      if(!Ecommerce.ecLoaded) {
        ga('require', 'ec');
        Ecommerce.ecLoaded = true;
      }
      var ecommerce = new Ecommerce();
      ecommerce.init(element);
    }
  }

  GOVUK.Ecommerce = Ecommerce;
})()
<commit_msg>Guard against GA not being defined<commit_after>// https://developers.google.com/analytics/devguides/collection/analyticsjs/enhanced-ecommerce
(function () {
  "use strict";
  window.GOVUK = window.GOVUK || {};

  var DEFAULT_LIST_TITLE = 'Site search results';

  var Ecommerce = function (config) {
    this.init = function (element) {
      // Limiting to 100 characters to avoid noise from extra longs search queries
      // and to stop the size of the payload going over 8k limit.
      var searchQuery   = GOVUK.analytics.stripPII(element.attr('data-search-query')).substring(0, 100).toLowerCase();
      var ecommerceRows = element.find('[data-ecommerce-row]');
      var startPosition = parseInt(element.data('ecommerce-start-index'), 10);
      var listTitle     = element.data('list-title') || DEFAULT_LIST_TITLE;

      ecommerceRows.each(function(index, ecommerceRow) {
        var $ecommerceRow = $(ecommerceRow);

        var contentId = $ecommerceRow.attr('data-ecommerce-content-id'),
          path = $ecommerceRow.attr('data-ecommerce-path');

        addImpression(contentId, path, index + startPosition, searchQuery, listTitle);
        trackProductOnClick($ecommerceRow, contentId, path, index + startPosition, searchQuery, listTitle);
      });
    }

    function addImpression (contentId, path, position, searchQuery, listTitle) {
      // We only add the id to GA as additional product data is linked when it is uploaded.
      // This approach is taken to avoid the GA data packet exceeding the 8k limit
      ga('ec:addImpression', {
        id: contentId || path,
        position: position,
        list: listTitle,
        dimension71: searchQuery
      });
    }

    function trackProductOnClick (row, contentId, path, position, searchQuery, listTitle) {
      row.click(function(event) {
        ga('ec:addProduct', {
          id: contentId || path,
          position: position,
          dimension71: searchQuery
        });

        ga('ec:setAction', 'click', {list: listTitle});
        GOVUK.analytics.trackEvent('UX', 'click',
          GOVUK.CustomDimensions.getAndExtendDefaultTrackingOptions({label: 'Results'})
        );
      });
    }
  }

  Ecommerce.ecLoaded = false;
  Ecommerce.start = function (element) {
    if (!window.ga) { return }
    element = element || $('[data-analytics-ecommerce]');
    if(element.length > 0) {
      if(!Ecommerce.ecLoaded) {
        ga('require', 'ec');
        Ecommerce.ecLoaded = true;
      }
      var ecommerce = new Ecommerce();
      ecommerce.init(element);
    }
  }

  GOVUK.Ecommerce = Ecommerce;
})()
<|endoftext|>


<commit_before>import Phaser from 'phaser'
import WebFont from 'webfontloader'

class Boot extends Phaser.State {
  init () {
    this.fontsReady = false;
    this.fontsLoaded = this.fontsLoaded.bind(this);
  }

  preload () {
    WebFont.load({
      google: {
        families: ['Roboto']
      },
      active: this.fontsLoaded
    })

    let text = this.add.text(this.world.centerX, this.world.centerY, 'loading fonts', { font: '16px Arial', fill: '#ffffff', align: 'center' });
    text.anchor.set(0.5);

    this.game.load.image('loaderBg', './assets/images/loader-bg.png');
    this.game.load.image('loaderBar', './assets/images/loader-bar.png');

    // load game.config.json into game cache
    this.game.load.json('config','src/game.config.json');
  }

  render () {
    if (this.fontsReady) {
      this.game.state.start('Load');
    }
  }

  fontsLoaded () {
    this.fontsReady = true;
  }

}

export default Boot;
<commit_msg>fixed config file path error<commit_after>import Phaser from 'phaser'
import WebFont from 'webfontloader'

class Boot extends Phaser.State {
  init () {
    this.fontsReady = false;
    this.fontsLoaded = this.fontsLoaded.bind(this);
  }

  preload () {
    WebFont.load({
      google: {
        families: ['Roboto']
      },
      active: this.fontsLoaded
    })

    let text = this.add.text(this.world.centerX, this.world.centerY, 'loading fonts', { font: '16px Arial', fill: '#ffffff', align: 'center' });
    text.anchor.set(0.5);

    this.game.load.image('loaderBg', './assets/images/loader-bg.png');
    this.game.load.image('loaderBar', './assets/images/loader-bar.png');

    // load game.config.json into game cache
    this.game.load.json('config','./game.config.json');
  }

  render () {
    if (this.fontsReady) {
      this.game.state.start('Load');
    }
  }

  fontsLoaded () {
    this.fontsReady = true;
  }

}

export default Boot;
<|endoftext|>


<commit_before>import Spawner from '../objects/spawner';
import Player from '../objects/player';
import BlueGem from '../objects/items/blueGem';
import Bomb from '../objects/items/bomb';
import Boom from '../objects/items/explosion';
import dropRates from '../../assets/json/drop_rates.json';

require('../../assets/images/Back.png');
require('../../assets/images/bg_cave.png');
require('../../assets/images/track_str_sm.gif');
require('../../assets/images/cart_str.gif');
require('../../assets/images/blueGem.png');
require('../../assets/images/bomb.png');
require('../../assets/images/arrow.png');
require('../../assets/images/brake.png');

export default class PlayState extends Phaser.State {
    preload () {
        this.game.load.image('this.bgCave', '/assets/bg_cave.png');
        this.game.load.image('track_str', '/assets/track_str_sm.gif');
        this.game.load.image('cart_str', '/assets/cart_str.gif');
        this.game.load.image('back_button', '/assets/Back.png');
        this.game.load.image('bomb', '/assets/bomb.png');
        this.game.load.image('boom', '/assets/explosion.png');
        this.game.load.image('arrow', '/assets/arrow.png');
        this.game.load.image('brake', '/assets/brake.png');
        this.game.load.image('blueGem', '/assets/blueGem.png');
        this.booster = 0;
    }

    create () {
        this.game.dpad = this.game.input.keyboard.createCursorKeys();
        this.bgCave = this.game.add.tileSprite(0, 0, 800, 600, 'this.bgCave');
        this.tracks = this.game.add.group();
        this.tracks.enableBody = true;
        this.game.player = new Player(this.game);
        for (var i = 0, len = 100; i < len; i += 35) {
            this.t = this.tracks.create(i, this.game.height * 0.8, 'track_str');
            this.t.body.immovable = true;
        }
        this.cartType = this.game.add.group();
        this.cartType.enableBody = true;
        this.cart = this.cartType.create(50, 430, 'cart_str');
        this.game.physics.enable(this.cart, Phaser.Physics.ARCADE);
        this.cart.body.gravity.y = 200;
        this.cart.body.collideWorldBounds = true;
        this.cart.body.checkCollision.up = true;
        this.cart.body.checkCollision.down = true;
        this.game.backButton = this.game.add.button(0, 0, 'back_button', function () { this.game.state.start('MainMenu') }, this);
        this.game.boostButton = this.game.add.button(this.game.width - 100, 0, 'arrow', function(){if (this.booster < 700) { this.booster += 50; }}, this);
        this.game.brakeButton = this.game.add.button(this.game.width - 200, 0, 'brake', function(){if (this.booster > -100) { this.booster -= 50; }}, this);
        this.gemSpawner = new Spawner(this.game, this.game.width + 15, 200, this.game.width + 15, 600, [BlueGem]);
        this.bombSpawner = new Spawner(this.game, this.game.width + 15, 200, this.game.width + 15, 600, [Bomb]);
    }

    update () {
        //  Scroll the background relative to track speed
        this.bgCave.tilePosition.x -= -(this.t.body.velocity.x/100)

        if (this.t.body.x < 800) {
            this.spawn();
        }

        var firstAlive = this.tracks.getFirstAlive();
        if (firstAlive.x < -35) { // Cleanup as we go
            this.tracks.removeChild(firstAlive);
        }
        // Make sure collision with tracks happens correctly, may need to do a callback to make sure it goes up hill?
        this.game.physics.arcade.collide(this.cartType, this.tracks, null, null, null);
        this.syncCart(this.cart, this.tracks);
    }

    spawn () {
        var currentVelocity = this.t.body.velocity.x
        var currentX = this.t.body.x

        this.t = this.tracks.create(currentX + 35, this.game.height * 0.8, 'track_str');
        this.t.body.velocity.x = currentVelocity;
        this.t.body.immovable = true;

        var newGem = this.gemSpawner.spawnItem();
        if (newGem) {
            newGem.body.x = this.t.body.x;
            newGem.body.velocity.x = currentVelocity;
            this.game.add.existing(newGem);
        }

        var bomb = this.bombSpawner.spawnItem();
        if (bomb) {
            bomb.body.x = this.t.body.x;
            bomb.body.velocity.x = currentVelocity;
            this.game.add.existing(bomb);
        }
    }

    syncCart(myCart, trackGroup) {
        var modifier = 0;
        if (myCart.body.x > 150) {
            modifier = 20;
            this.fix_position = 1;
        } else if (myCart.body.x < 20) {
            modifier = -20;
            this.fix_position = 1;
        } else if (this.fix_position && (myCart.body.x >= 70 && myCart.body.x <= 80)) {
            // Move the cart until it gets up to full speed
            this.setTrackSpeed(trackGroup, -(myCart.body.velocity.x));
            this.fix_position = 0;
        } else {
            if (myCart.body.velocity.x < (300 + this.booster)) {
                myCart.body.velocity.x += 10;
            // Move the cart until it gets back close to full speed
            } else if (myCart.body.velocity.x > (200 + this.booster + 20)) {
                myCart.body.velocity.x -= 10;
            }
        }
        if (modifier) {
            this.setTrackSpeed(trackGroup, -(myCart.body.velocity.x + modifier));
        }
    }

    setTrackSpeed(trackGroup, speed) {
        trackGroup.setAll('body.velocity.x', (speed), 'true', 'false', 0);
    }
};
<commit_msg>explosions not ready for requiring yet<commit_after>import Spawner from '../objects/spawner';
import Player from '../objects/player';
import BlueGem from '../objects/items/blueGem';
import Bomb from '../objects/items/bomb';
import dropRates from '../../assets/json/drop_rates.json';

require('../../assets/images/Back.png');
require('../../assets/images/bg_cave.png');
require('../../assets/images/track_str_sm.gif');
require('../../assets/images/cart_str.gif');
require('../../assets/images/blueGem.png');
require('../../assets/images/bomb.png');
require('../../assets/images/arrow.png');
require('../../assets/images/brake.png');

export default class PlayState extends Phaser.State {
    preload () {
        this.game.load.image('this.bgCave', '/assets/bg_cave.png');
        this.game.load.image('track_str', '/assets/track_str_sm.gif');
        this.game.load.image('cart_str', '/assets/cart_str.gif');
        this.game.load.image('back_button', '/assets/Back.png');
        this.game.load.image('bomb', '/assets/bomb.png');
        this.game.load.image('boom', '/assets/explosion.png');
        this.game.load.image('arrow', '/assets/arrow.png');
        this.game.load.image('brake', '/assets/brake.png');
        this.game.load.image('blueGem', '/assets/blueGem.png');
        this.booster = 0;
    }

    create () {
        this.game.dpad = this.game.input.keyboard.createCursorKeys();
        this.bgCave = this.game.add.tileSprite(0, 0, 800, 600, 'this.bgCave');
        this.tracks = this.game.add.group();
        this.tracks.enableBody = true;
        this.game.player = new Player(this.game);
        for (var i = 0, len = 100; i < len; i += 35) {
            this.t = this.tracks.create(i, this.game.height * 0.8, 'track_str');
            this.t.body.immovable = true;
        }
        this.cartType = this.game.add.group();
        this.cartType.enableBody = true;
        this.cart = this.cartType.create(50, 430, 'cart_str');
        this.game.physics.enable(this.cart, Phaser.Physics.ARCADE);
        this.cart.body.gravity.y = 200;
        this.cart.body.collideWorldBounds = true;
        this.cart.body.checkCollision.up = true;
        this.cart.body.checkCollision.down = true;
        this.game.backButton = this.game.add.button(0, 0, 'back_button', function () { this.game.state.start('MainMenu') }, this);
        this.game.boostButton = this.game.add.button(this.game.width - 100, 0, 'arrow', function(){if (this.booster < 700) { this.booster += 50; }}, this);
        this.game.brakeButton = this.game.add.button(this.game.width - 200, 0, 'brake', function(){if (this.booster > -100) { this.booster -= 50; }}, this);
        this.gemSpawner = new Spawner(this.game, this.game.width + 15, 200, this.game.width + 15, 600, [BlueGem]);
        this.bombSpawner = new Spawner(this.game, this.game.width + 15, 200, this.game.width + 15, 600, [Bomb]);
    }

    update () {
        //  Scroll the background relative to track speed
        this.bgCave.tilePosition.x -= -(this.t.body.velocity.x/100)

        if (this.t.body.x < 800) {
            this.spawn();
        }

        var firstAlive = this.tracks.getFirstAlive();
        if (firstAlive.x < -35) { // Cleanup as we go
            this.tracks.removeChild(firstAlive);
        }
        // Make sure collision with tracks happens correctly, may need to do a callback to make sure it goes up hill?
        this.game.physics.arcade.collide(this.cartType, this.tracks, null, null, null);
        this.syncCart(this.cart, this.tracks);
    }

    spawn () {
        var currentVelocity = this.t.body.velocity.x
        var currentX = this.t.body.x

        this.t = this.tracks.create(currentX + 35, this.game.height * 0.8, 'track_str');
        this.t.body.velocity.x = currentVelocity;
        this.t.body.immovable = true;

        var newGem = this.gemSpawner.spawnItem();
        if (newGem) {
            newGem.body.x = this.t.body.x;
            newGem.body.velocity.x = currentVelocity;
            this.game.add.existing(newGem);
        }

        var bomb = this.bombSpawner.spawnItem();
        if (bomb) {
            bomb.body.x = this.t.body.x;
            bomb.body.velocity.x = currentVelocity;
            this.game.add.existing(bomb);
        }
    }

    syncCart(myCart, trackGroup) {
        var modifier = 0;
        if (myCart.body.x > 150) {
            modifier = 20;
            this.fix_position = 1;
        } else if (myCart.body.x < 20) {
            modifier = -20;
            this.fix_position = 1;
        } else if (this.fix_position && (myCart.body.x >= 70 && myCart.body.x <= 80)) {
            // Move the cart until it gets up to full speed
            this.setTrackSpeed(trackGroup, -(myCart.body.velocity.x));
            this.fix_position = 0;
        } else {
            if (myCart.body.velocity.x < (300 + this.booster)) {
                myCart.body.velocity.x += 10;
            // Move the cart until it gets back close to full speed
            } else if (myCart.body.velocity.x > (200 + this.booster + 20)) {
                myCart.body.velocity.x -= 10;
            }
        }
        if (modifier) {
            this.setTrackSpeed(trackGroup, -(myCart.body.velocity.x + modifier));
        }
    }

    setTrackSpeed(trackGroup, speed) {
        trackGroup.setAll('body.velocity.x', (speed), 'true', 'false', 0);
    }
};
<|endoftext|>


<commit_before>import { persistStore } from 'redux-persist';
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import logger from 'redux-logger';
import rootReducer from '../reducers';

const store = createStore(
  rootReducer,
  applyMiddleware(thunkMiddleware, logger),
);

persistStore(store);

export default store;
<commit_msg>Only add logger in production<commit_after>import { persistStore } from 'redux-persist';
import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';
import thunkMiddleware from 'redux-thunk';
import rootReducer from '../reducers';

const middleware = [thunkMiddleware];
if (process.env.NODE_ENV !== 'production') {
  middleware.push(logger);
}

const store = createStore(
  rootReducer,
  applyMiddleware(...middleware),
);

persistStore(store);

export default store;
<|endoftext|>


<commit_before>((global) => {

  gl.CycleAnalytics = class CycleAnalytics {
    constructor() {
      this.vue = new Vue({
        el: '#cycle-analytics',
        name: 'CycleAnalytics',
        created: this.fetchData(),
        data: this.getData({ isLoading: true })
      });
    }

    fetchData() {
      $.get('cycle_analytics.json')
        .done((data) => {
          this.vue.$data = this.getData(data);
          this.initDropdown();
        })
        .error((data) => {
          this.handleError(data);
        })
        .always(() => {
          this.vue.isLoading = false;
        })
    }

    getData(data) {
      return {
        notAvailable: data.notAvailable || false,
        isLoading: data.isLoading || false,
        analytics: {
          summary: [
            { desc: 'New Issues', value: data.issues  || '-' },
            { desc: 'Commits', value: data.commits || '-' },
            { desc: 'Deploys', value: data.deploys || '-' }
          ],
          data: [
            { title: 'Issue', desc: 'Time before an issue get scheduled', value: data.issue || '-' },
            { title: 'Plan', desc: 'Time before an issue starts implementation', value: data.plan || '-' },
            { title: 'Code', desc: 'Time until first merge request', value: data.code || '-' },
            { title: 'Test', desc: 'CI test time of the default branch', value: data.test || '-' },
            { title: 'Review', desc: 'Time between MR creation and merge/close', value: data.review || '-' },
            { title: 'Deploy', desc: 'Time for a new commit to land in one of the environments', value: data.deploy || '-' }
          ]
        }
      }
    }

    handleError(data) {
      // TODO: Make sure that this is the proper error handling
      new Flash('There was an error while fetching cycyle analytics data.', 'alert');
    }

    initDropdown() {
      const $dropdown = $('.js-ca-dropdown');
      const $label = $dropdown.find('.dropdown-label');

      $dropdown.find('li a').on('click', (e) => {
        e.preventDefault();
        const $target = $(e.currentTarget);
        $label.text($target.text().trim());
        value = $target.data('value');

        this.vue.isLoading = true;
      })
    }

  }

})(window.gl || (window.gl = {}));
<commit_msg>Implement Cycle Analytics frontend.<commit_after>((global) => {

  gl.CycleAnalytics = class CycleAnalytics {
    constructor() {
      this.vue = new Vue({
        el: '#cycle-analytics',
        name: 'CycleAnalytics',
        created: this.fetchData(),
        data: this.getData({ isLoading: true })
      });
    }

    fetchData() {
      $.get('cycle_analytics.json')
        .done((data) => {
          this.vue.$data = this.getData(data);
          this.initDropdown();
        })
        .error((data) => {
          this.handleError(data);
        })
        .always(() => {
          this.vue.isLoading = false;
        })
    }

    getData(data) {
      return {
        notAvailable: data.notAvailable || false,
        isLoading: data.isLoading || false,
        analytics: {
          summary: [
            { desc: 'New Issues', value: data.issues  || '-' },
            { desc: 'Commits', value: data.commits || '-' },
            { desc: 'Deploys', value: data.deploys || '-' }
          ],
          data: [
            { title: 'Issue', desc: 'Time before an issue get scheduled', value: data.issue || '-' },
            { title: 'Plan', desc: 'Time before an issue starts implementation', value: data.plan || '-' },
            { title: 'Code', desc: 'Time until first merge request', value: data.code || '-' },
            { title: 'Test', desc: 'CI test time of the default branch', value: data.test || '-' },
            { title: 'Review', desc: 'Time between MR creation and merge/close', value: data.review || '-' },
            { title: 'Deploy', desc: 'Time for a new commit to land in one of the environments', value: data.deploy || '-' }
          ]
        }
      }
    }

    handleError(data) {
      // TODO: Make sure that this is the proper error handling
      new Flash('There was an error while fetching cycyle analytics data.', 'alert');
    }

    initDropdown() {
      const $dropdown = $('.js-ca-dropdown');
      const $label = $dropdown.find('.dropdown-label');

      $dropdown.find('li a').on('click', (e) => {
        e.preventDefault();
        const $target = $(e.currentTarget);
        const value = $target.data('value');

        $label.text($target.text().trim());
        this.vue.isLoading = true;
      })
    }
  }

})(window.gl || (window.gl = {}));
<|endoftext|>