<commit_before>Ext.define('MyApp.App', {
    requires: ['MyApp.Toggle', 'MyApp.BoardErrorMessage'],
    extend: 'Rally.app.App',
    componentCls: 'app',
    statics: {
        BUSINESS_VALUE_PROPERTY: 'c_BusinessValue'
    },
    items: [
    ],
    padding: '20 20 20 20',
    launch: function () {
        this._addHeader();
        this._addToggle();
        this.attributeName = 'PlanEstimate';
        this._addBoard();
    },
    _addToggle: function () {
        var container = this.add({
            xtype: 'container',
            layout: {type: 'hbox', pack: 'end'},
            items: [
                {
                    xtype: 'customtoggle',
                    businessValueProperty: MyApp.App.BUSINESS_VALUE_PROPERTY,
                    listeners: {
                        toggle: {fn: this._boardToggled, scope: this}
                    },
                    margin: '0 0 10 0'
                }
            ]
        });
    },
    _boardToggled: function (sender, attribute) {
        this.remove(this.board);
        this.remove(this.grid);
        this.remove(this.message);
        this.attributeName = attribute;

        if(this.attributeName != 'Ranking') {
            this._addBoard();
        }
        else {
            this._addRankingGrid();
        }
    },

    _addHeader: function () {
        this.header = this.add({xtype: 'component', tpl: '
<tpl if="img"></tpl>
{text}

', data: {text: 'HEADER'}, margin: '10 0 10 0'});
    },

    _addRankingGrid: function() {
        this.header.update({img: 'img/bang.jpg', text: 'Story Value per Cost'});

        Ext.create('Rally.data.wsapi.Store', {
            model: 'userstory',
            autoLoad: true,
            listeners: {
                load: this._onGridDataLoaded,
                scope: this
            },
            filters: [
                {
                    property: 'PlanEstimate',
                    operator: '!=',
                    value: null
                },
                {
                    property: MyApp.App.BUSINESS_VALUE_PROPERTY,
                    operator: '!=',
                    value: null
                },
                {
                    property: 'DirectChildrenCount',
                    operator: '=',
                    value: '0'
                }
            ],
            fetch: ['FormattedID', 'Name', 'PlanEstimate', MyApp.App.BUSINESS_VALUE_PROPERTY]
        });
    },

    _onGridDataLoaded: function (store, data) {
        var records = _.map(data, function (record) {
            return Ext.apply({
                Bang: (record.get(MyApp.App.BUSINESS_VALUE_PROPERTY) / record.get('PlanEstimate')).toFixed(2)
            }, record.getData());
        });

        this.grid = this.add({
            xtype: 'rallygrid',
            showPagingToolbar: false,
            showRowActionsColumn: false,
            editable: false,
            store: Ext.create('Rally.data.custom.Store', {
                data: records,
                sorters: [
                    {property: 'Bang', direction: 'DESC'}
                ]
            }),
            columnCfgs: [
                {
                    xtype: 'templatecolumn',
                    text: 'ID',
                    dataIndex: 'FormattedID',
                    width: 100,
                    tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate')
                },
                {
                    text: 'Bang',
                    dataIndex: 'Bang'
                },
                {
                    text: 'Name',
                    dataIndex: 'Name',
                    flex: 1
                },
                {
                    text: 'Business Value',
                    dataIndex: MyApp.App.BUSINESS_VALUE_PROPERTY
                },
                {
                    text: 'Plan Estimate',
                    dataIndex: 'PlanEstimate'
                }
            ]
        });
    },

    _addBoard: function () {
        var text = this.attributeName === 'PlanEstimate' ? "Plan Estimate for Stories" : "Business Value for Stories";
        this.header.update({text: text});

        Ext.create('Rally.data.wsapi.Store', {
            model: 'userstory',
            autoLoad: true,
            listeners: {
                load: this._onBoardDataLoaded,
                scope: this
            },
            filters: [
                {
                    property: 'Iteration',
                    operator: '=',
                    value: ''
                },
                {
                    property: 'DirectChildrenCount',
                    operator: '=',
                    value: '0'
                }
            ],
            fetch: ['FormattedID', 'Name', 'PlanEstimate', MyApp.App.BUSINESS_VALUE_PROPERTY]
        });
    },

    _onBoardDataLoaded: function(store, data) {
        var definedColumns = [0, 1, 2, 3, 5, 8, 13, 20];

        var valueAttributes = _.map(data, function(record) { return record.get(this.attributeName); }, this);

        var uniqueValues = _.uniq(valueAttributes);

        var uniqueValuesNoNull = _.filter(uniqueValues, function(value) { return value != null; });

        var unorderedColumns = _.union(definedColumns, uniqueValuesNoNull);

        var estimateValues = _.sortBy(unorderedColumns, function(num) { return num; });

        var columns = [
            {
                value: null,
                columnHeaderConfig: {
                    headerData: {value: 'Unestimated'}
                }
            }
        ];

        _.each(estimateValues, function (estimate) {
            var borderValue = 0;
            if(!_.contains(definedColumns, estimate)){
                borderValue = 1;
            }

            columns.push({
                value: estimate,
                columnHeaderConfig: {
                    headerData: {value: estimate}
                },
                border: borderValue,
                style: {
                    borderColor: 'red',
                    borderStyle: 'solid'
                }
            });
        });

        if(!this._supportsBusinessValue(data) && this.attributeName === MyApp.App.BUSINESS_VALUE_PROPERTY){
            this.message = this.add({
                xtype:'boarderrormessage',
                businessValueProperty: MyApp.App.BUSINESS_VALUE_PROPERTY
            });
        }
        else {
             this.board = this.add({
            xtype: 'rallycardboard',
            types: ['User Story'],
            attribute: this.attributeName,
            context: this.getContext(),
            margin: '10 0 0 0',
            columnConfig: {
                columnHeaderConfig: {
                    headerTpl: '{value}'
                }
            },
            storeConfig: {
                filters: [
                    {
                        property: 'Iteration',
                        operator: '=',
                        value: ''
                    },
                    {
                        property: 'DirectChildrenCount',
                        operator: '=',
                        value: '0'
                    }
                ]
            },
            columns: columns
        });

        }
    },
    _supportsBusinessValue: function(data){
       return data.length > 0 && _.has(data[0].data, MyApp.App.BUSINESS_VALUE_PROPERTY);
    }
});
<commit_msg>Added auto-rank option<commit_after>Ext.define('MyApp.App', {
    requires: ['MyApp.Toggle', 'MyApp.BoardErrorMessage'],
    extend: 'Rally.app.App',
    componentCls: 'app',
    statics: {
        BUSINESS_VALUE_PROPERTY: 'c_BusinessValue'
    },
    items: [
    ],
    padding: '20 20 20 20',
    launch: function () {
        this.attributeName = 'PlanEstimate';
        this._addHeader();
        this._addToggle();
        this._addBangButton();
        this._addBoard();
    },

    _addToggle: function () {
        var container = this.add({
            xtype: 'container',
            layout: {type: 'hbox', pack: 'end'},
            items: [
                {
                    xtype: 'customtoggle',
                    businessValueProperty: MyApp.App.BUSINESS_VALUE_PROPERTY,
                    listeners: {
                        toggle: {fn: this._boardToggled, scope: this}
                    },
                    margin: '0 0 10 0'
                }
            ]
        });
    },

    _addBangButton: function() {
        this.bangButtonContainer = this.add({xtype: 'container',
            layout: {type: 'hbox', pack: 'end'},
            items: [
                {
                    xtype: 'rallybutton',
                    text: 'Rank Stories By Bang',
                    handler: this._rankByBang,
                    margin: '0 0 10 0',
                    scope: this
                }
            ]
        });

        this.bangButtonContainer.hide();
    },

    _rankByBang: function(){
        this.storyToRankMap = {};

        this.sortedData = _.sortBy(this.gridData, 'Bang');

        this.iRank = 0;
        this._rankRelative();
    },

    _rankRelative: function() {
        if(this.iRank < this.sortedData.length -1)
        {
            var i = this.iRank;
            this.iRank++;

            Rally.data.Ranker.rankRelative({
                recordToRank: this.wsapiMap[this.sortedData[i+1].ObjectID],
                relativeRecord: this.wsapiMap[this.sortedData[i].ObjectID],
                position: 'before',
                notificationMessage: 'Moved {0} above {1}',
                saveOptions: {
                    callback: this._rankRelative,
                    scope:this
                }
            });
        }
    },

    _boardToggled: function (sender, attribute) {
        this.remove(this.board);
        this.remove(this.grid);
        this.remove(this.message);
        this.bangButtonContainer.hide();
        this.attributeName = attribute;

        if(this.attributeName != 'Ranking') {
            this._addBoard();
        }
        else {
            this._addRankingGrid();
        }
    },

    _addHeader: function () {
        this.header = this.add({xtype: 'component', tpl: '
<tpl if="img"></tpl>
{text}

', data: {text: 'HEADER'}, margin: '10 0 10 0'});
    },

    _addRankingGrid: function() {
        this.bangButtonContainer.show();
        this.header.update({img: 'img/bang.jpg', text: 'Story Value per Cost'});

        Ext.create('Rally.data.wsapi.Store', {
            model: 'userstory',
            autoLoad: true,
            listeners: {
                load: this._onGridDataLoaded,
                scope: this
            },
            filters: [
                {
                    property: 'PlanEstimate',
                    operator: '!=',
                    value: null
                },
                {
                    property: MyApp.App.BUSINESS_VALUE_PROPERTY,
                    operator: '!=',
                    value: null
                },
                {
                    property: 'DirectChildrenCount',
                    operator: '=',
                    value: '0'
                }
            ],
            fetch: ['FormattedID', 'Name', 'PlanEstimate', MyApp.App.BUSINESS_VALUE_PROPERTY, 'DragAndDropRank']
        });
    },

    _onGridDataLoaded: function (store, data) {
        this.wsapiMap = {};

        this.gridData = _.map(data, function (record) {
            this.wsapiMap[record.get('ObjectID')] = record;
            return Ext.apply({
                Bang: (record.get(MyApp.App.BUSINESS_VALUE_PROPERTY) / record.get('PlanEstimate')).toFixed(2)
            }, record.getData());
        }, this);

        this.grid = this.add({
            xtype: 'rallygrid',
            showPagingToolbar: false,
            showRowActionsColumn: false,
            editable: false,
            store: Ext.create('Rally.data.custom.Store', {
                data: this.gridData,
                sorters: [
                    {property: 'Bang', direction: 'DESC'}
                ]
            }),
            columnCfgs: [
                {
                    xtype: 'templatecolumn',
                    text: 'ID',
                    dataIndex: 'FormattedID',
                    width: 100,
                    tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate')
                },
                {
                    text: 'Bang',
                    dataIndex: 'Bang'
                },
                {
                    text: 'Name',
                    dataIndex: 'Name',
                    flex: 1
                },
                {
                    text: 'Business Value',
                    dataIndex: MyApp.App.BUSINESS_VALUE_PROPERTY
                },
                {
                    text: 'Plan Estimate',
                    dataIndex: 'PlanEstimate'
                }
            ]
        });
    },

    _addBoard: function () {
        var text = this.attributeName === 'PlanEstimate' ? "Plan Estimate for Stories" : "Business Value for Stories";
        this.header.update({text: text});

        Ext.create('Rally.data.wsapi.Store', {
            model: 'userstory',
            autoLoad: true,
            listeners: {
                load: this._onBoardDataLoaded,
                scope: this
            },
            filters: [
                {
                    property: 'Iteration',
                    operator: '=',
                    value: ''
                },
                {
                    property: 'DirectChildrenCount',
                    operator: '=',
                    value: '0'
                }
            ],
            fetch: ['FormattedID', 'Name', 'PlanEstimate', MyApp.App.BUSINESS_VALUE_PROPERTY]
        });
    },

    _onBoardDataLoaded: function(store, data) {
        var definedColumns = [1, 2, 3, 5, 8, 13, 20];

        var valueAttributes = _.map(data, function(record) { return record.get(this.attributeName); }, this);

        var uniqueValues = _.uniq(valueAttributes);

        var uniqueValuesNoNull = _.filter(uniqueValues, function(value) { return value != null; });

        var unorderedColumns = _.union(definedColumns, uniqueValuesNoNull);

        var estimateValues = _.sortBy(unorderedColumns, function(num) { return num; });

        var columns = [
            {
                value: null,
                columnHeaderConfig: {
                    headerData: {value: 'Unestimated'}
                }
            }
        ];

        _.each(estimateValues, function (estimate) {
            var borderValue = 0;
            if(!_.contains(definedColumns, estimate)){
                borderValue = 1;
            }

            columns.push({
                value: estimate,
                columnHeaderConfig: {
                    headerData: {value: estimate}
                },
                border: borderValue,
                style: {
                    borderColor: 'red',
                    borderStyle: 'solid'
                }
            });
        });

        if(!this._supportsBusinessValue(data) && this.attributeName === MyApp.App.BUSINESS_VALUE_PROPERTY){
            this.message = this.add({
                xtype:'boarderrormessage',
                businessValueProperty: MyApp.App.BUSINESS_VALUE_PROPERTY
            });
        }
        else {
             this.board = this.add({
            xtype: 'rallycardboard',
            types: ['User Story'],
            attribute: this.attributeName,
            context: this.getContext(),
            margin: '10 0 0 0',
            columnConfig: {
                columnHeaderConfig: {
                        headerTpl: '{value}'
                }
            },
            storeConfig: {
                filters: [
                    {
                        property: 'Iteration',
                        operator: '=',
                        value: ''
                    },
                    {
                        property: 'DirectChildrenCount',
                        operator: '=',
                        value: '0'
                    }
                ]
            },
            columns: columns
        });

        }
    },
    _supportsBusinessValue: function(data){
        if(!_.isUndefined(this.valueUnsupported)){
            return this.valueUnsupported;
        }
        else{
            this.valueUnsupported = data.length > 0 && _.has(data[0].data, MyApp.App.BUSINESS_VALUE_PROPERTY);
            return this.valueUnsupported;
        }
    }
});<|endoftext|>


<commit_before>var Bussholdeplass    = require('Bussholdeplass')
, Departure           = require('Departure')
, FavoriteHandler     = require('FavoriteHandler')
, Stops               = require('Stops');

var env               = require('FuseJS/Environment')
, Observable          = require('FuseJS/Observable')
, GeoLocation         = require('FuseJS/GeoLocation');

var departures        = Observable()
, favorites           = Observable()
, favorite_departures = Observable()
, filtered_view       = Observable()
, loading_indicator   = Observable(false)
, departures_active   = Observable(false)
, stop_info           = Observable()
, stop_search         = Observable('');

/* Mock data
-----------------------------------------------------------------------------*/
favorites.add(new Bussholdeplass('100268', '16011333', 'Gløshaugen Nord', 10.406111, 63.418309));
favorites.add(new Bussholdeplass('100295', '16010333', 'Gløshaugen Nord', 10.405967, 63.418184));
favorites.add(new Bussholdeplass('102714', '16011265', 'Gløshaugen Syd', 10.406111, 63.418309));
favorites.add(new Bussholdeplass('100268', '16011333', 'Gløshaugen Nord', 10.406111, 63.418309));

/* Func
-----------------------------------------------------------------------------*/
var ApiReq = {
  url: 'http://bybussen.api.tmn.io/',
  get: function (path, callback) {
    return fetch(ApiReq.url + path, {
      method: 'GET',
      headers: { 'Content-Type': 'application/json' }
    }).then(function (response) {
      return response.json();
    })
  }
};

var go_back = function () {
  departures_active.value = false;
  departures.clear();
};

var stop_clicked = function (args) {
  loading_indicator.value = true;

  stop_info.value = args.data;
  stop_info.value.name = stop_info.value.name.toUpperCase();

  ApiReq.get('rt/' + args.data.locationId).then(function (responseObject) {
    var newDepartures = responseObject['next'].map(function (e) {
      return new Departure(e.l, e.t, e.ts, e.rt, e.d);
    });

    departures.replaceAll(newDepartures);

    setTimeout(function () {
      loading_indicator.value = false;
      departures_active.value = true;
    }, 300);
  })
  .catch(function (err) {
    console.log('ERROR: ' + err.message);
  });
};

/* Load favorites
-----------------------------------------------------------------------------*/
function load_fav_data() {
    var favs = [];

    favorites.forEach(function (s) {
      var stop = new Bussholdeplass(s.id, s.locationId, s.name, s.latitude, s.longitude);

      var stopDep = {
        name: stop.name,
        direction: stop.direction,
        departures: new Observable()
      };

      load_fav_departures(stopDep.departures, s.locationId)

      favs.push(stopDep);
    });

    favorite_departures.replaceAll(favs);
}

function load_fav_departures(arr, id) {
  ApiReq.get('rt/' + id).then(function (responseObject) {
    var departures = responseObject.next.slice(0, 4).map(function (d) {
      return new Departure(d.l, d.t, d.ts, d.rt, d.d);
    });

    arr.replaceAll(departures);
  })
  .catch(function (err) {
    console.log('ERROR: ' + err.message);
  });
}

function reload_favs() {
  // load_fav_data();
}

/* Geolocation + nearest stops
-----------------------------------------------------------------------------*/
function update_nearest_stop(location) {
  if (!env.mobile) {
    return;
  }

  if (location === undefined) {
    if (GeoLocation.location !== null) {
      location = GeoLocation.location;
    }
    else {
      return;
    }
  }

  ApiReq.get('stops/nearest/' + location.latitude + '/' + location.longitude).then(function (responseObject) {
    var convertedStops = responseObject.map(function (e) {
      return new Bussholdeplass(e.busStopId, e.locationId, e.name, e.longitude, e.latitude, e.distance);
    });

    filtered_view.replaceAll(convertedStops);
  })
  .catch(function (err) {
    console.log('ERROR: ' + err.message);
  });
}

/* Search typing handler
-----------------------------------------------------------------------------*/
stop_search.addSubscriber(function () {
  var search_string = stop_search.value;

  if (search_string.length < 3) {
    if (search_string.length === 0) {
      filtered_view.clear();
      update_nearest_stop();
    }

    return;
  }

  filtered_view.replaceAll(Stops.filter(function (e) {
    return e.name.toUpperCase().indexOf(search_string.toUpperCase()) > -1;
  }));
});

/* Init
-----------------------------------------------------------------------------*/
load_fav_data();

/* Exports
-----------------------------------------------------------------------------*/
module.exports = {
  departures: departures,
  departures_active: departures_active,
  favorites: favorites,
  favorite_departures: favorite_departures,
  filtered_view: filtered_view,
  go_back: go_back,
  loading_indicator: loading_indicator,
  reload_favs: reload_favs,
  stop_clicked: stop_clicked,
  stop_info: stop_info,
  stop_search: stop_search
};
<commit_msg>Add method for deleting favorite<commit_after>var Bussholdeplass    = require('Bussholdeplass')
, Departure           = require('Departure')
, FavoriteHandler     = require('FavoriteHandler')
, Stops               = require('Stops');

var env               = require('FuseJS/Environment')
, Observable          = require('FuseJS/Observable')
, GeoLocation         = require('FuseJS/GeoLocation');

var departures        = Observable()
, favorites           = Observable()
, favorite_departures = Observable()
, filtered_view       = Observable()
, loading_indicator   = Observable(false)
, departures_active   = Observable(false)
, stop_info           = Observable()
, stop_search         = Observable('');

/* Mock data
-----------------------------------------------------------------------------*/
favorites.add(new Bussholdeplass('100268', '16011333', 'Gløshaugen Nord', 10.406111, 63.418309));
favorites.add(new Bussholdeplass('100295', '16010333', 'Gløshaugen Nord', 10.405967, 63.418184));
favorites.add(new Bussholdeplass('102714', '16011265', 'Gløshaugen Syd', 10.406111, 63.418309));
favorites.add(new Bussholdeplass('100268', '16011333', 'Gløshaugen Nord', 10.406111, 63.418309));

/* Func
-----------------------------------------------------------------------------*/
var ApiReq = {
  url: 'http://bybussen.api.tmn.io/',
  get: function (path, callback) {
    return fetch(ApiReq.url + path, {
      method: 'GET',
      headers: { 'Content-Type': 'application/json' }
    }).then(function (response) {
      return response.json();
    })
  }
};

var go_back = function () {
  departures_active.value = false;
  departures.clear();
};

var stop_clicked = function (args) {
  loading_indicator.value = true;

  stop_info.value = args.data;
  stop_info.value.name = stop_info.value.name.toUpperCase();

  ApiReq.get('rt/' + args.data.locationId).then(function (responseObject) {
    var newDepartures = responseObject['next'].map(function (e) {
      return new Departure(e.l, e.t, e.ts, e.rt, e.d);
    });

    departures.replaceAll(newDepartures);

    setTimeout(function () {
      loading_indicator.value = false;
      departures_active.value = true;
    }, 300);
  })
  .catch(function (err) {
    console.log('ERROR: ' + err.message);
  });
};

/* Load favorites
-----------------------------------------------------------------------------*/
function load_fav_data() {
    var favs = [];

    favorites.forEach(function (s) {
      var stop = new Bussholdeplass(s.id, s.locationId, s.name, s.latitude, s.longitude);

      var stopDep = {
        name: stop.name,
        direction: stop.direction,
        departures: new Observable()
      };

      load_fav_departures(stopDep.departures, s.locationId)

      favs.push(stopDep);
    });

    favorite_departures.replaceAll(favs);
}

function load_fav_departures(arr, id) {
  ApiReq.get('rt/' + id).then(function (responseObject) {
    var departures = responseObject.next.slice(0, 4).map(function (d) {
      return new Departure(d.l, d.t, d.ts, d.rt, d.d);
    });

    arr.replaceAll(departures);
  })
  .catch(function (err) {
    console.log('ERROR: ' + err.message);
  });
}

function delete_favorite(args) {
  favorites.remove(args.data);

  setTimeout(function () {
    FavoriteHandler.deleteFavorite(args.data.id);
    load_fav_data();
  }, 980);
}

function reload_favs() {
  // load_fav_data();
}

/* Geolocation + nearest stops
-----------------------------------------------------------------------------*/
function update_nearest_stop(location) {
  if (!env.mobile) {
    return;
  }

  if (location === undefined) {
    if (GeoLocation.location !== null) {
      location = GeoLocation.location;
    }
    else {
      return;
    }
  }

  ApiReq.get('stops/nearest/' + location.latitude + '/' + location.longitude).then(function (responseObject) {
    var convertedStops = responseObject.map(function (e) {
      return new Bussholdeplass(e.busStopId, e.locationId, e.name, e.longitude, e.latitude, e.distance);
    });

    filtered_view.replaceAll(convertedStops);
  })
  .catch(function (err) {
    console.log('ERROR: ' + err.message);
  });
}

/* Search typing handler
-----------------------------------------------------------------------------*/
stop_search.addSubscriber(function () {
  var search_string = stop_search.value;

  if (search_string.length < 3) {
    if (search_string.length === 0) {
      filtered_view.clear();
      update_nearest_stop();
    }

    return;
  }

  filtered_view.replaceAll(Stops.filter(function (e) {
    return e.name.toUpperCase().indexOf(search_string.toUpperCase()) > -1;
  }));
});

/* Init
-----------------------------------------------------------------------------*/
load_fav_data();
favorites.replaceAll(FavoriteHandler.getFavoriteList());

/* Exports
-----------------------------------------------------------------------------*/
module.exports = {
  departures: departures,
  departures_active: departures_active,
  favorites: favorites,
  favorite_departures: favorite_departures,
  favorite_delete: delete_favorite,
  filtered_view: filtered_view,
  go_back: go_back,
  loading_indicator: loading_indicator,
  reload_favs: reload_favs,
  stop_clicked: stop_clicked,
  stop_info: stop_info,
  stop_search: stop_search
};
<|endoftext|>


<commit_before>/**
 * TOYOSHIMA-HOUSE Library for JavaScript
 */

/**
 * Log prototype
 *
 * This prototype provide common log interfaces.
 * @author Takashi Toyoshima <toyoshim@gmail.com>
 *
 */

/**
 * Log prototype function. This prototype provide three kinds of Log
 * mechanisms. User can specify its type by id argument.
 * @param id Log type
 *     undefined: Use native console.log if it's available.
 *     null: Eliminate all logs.
 *     <string>: Output as pre element under DOM object which has <string> id.
 * @param reverse logging order
 *     true: Newer logs will be added to tail.
 *     false: Newer logs will be added to head.
 */
function Log (id, reverse) {
    this.lastLevel = "";
    this.reverse = reverse;

    // Set default log scheme.
    this.print = function (object) { /* Do nothing. */ };

    if (id == undefined) {
        // Try to use native console.
        if (window.console != undefined) {
            this.print = function (object) {
                console.log(object);
            }
        }
    } else if (id != null) {
        // Try to output under specified DOM object.
        this.frameDiv = document.getElementById(id);
        if (this.frameDiv == undefined)
            return;
        this.framePre = document.createElement('pre');
        this.frameDiv.appendChild(this.framePre);

        this.print = function (object) {
            if (window.console != undefined) {
                console.log(object);
            }
            var element;
            if (object instanceof Object) {
                element = document.createElement('pre');
                var text = object.toString();
                var textNode = document.createTextNode(text);
                element.appendChild(textNode);
                var title = "";
                for (var item in object) {
                    title += item + ":" + object[item] + "; \n";
                }
                element.setAttribute('title', title);
            } else {
                element = document.createTextNode(object + "\n");
            }
            if (this.reverse && this.framePre.firstChild)
                this.framePre.insertBefore(element, this.framePre.firstChild);
            else
                this.framePre.appendChild(element);
        }
    }
}

Log.log = new Log();

/**
 * Set default log instance.
 * @param newLog Log instance to set
 */
Log.setLog = function (newLog) {
    Log.log = newLog;
};

/**
 * Get default log instance.
 * @return default Log instance
 */
Log.getLog = function () {
    return Log.log;
};

/**
 * Convert to hex string.
 * @param number number to convert
 * @param digit result value's digit
 */
Log.toHex = function (number, digit) {
    var sign = number & 0x80000000;
    var result;
    if (sign != 0) {
        result = "fffffff" + (number >> 16).toString(16) +
                (number & 0xffff).toString(16);
    } else {
        result = "0000000" + (number >> 16).toString(16) +
                (number & 0xffff).toString(16);

    }
    return result.slice(-digit);
};

/**
 * Convert to oct string.
 * @param number number to convert
 * @param digit result value's digit
 */
Log.toOct = function (number, digit) {
    var result = "0000000000" + number.toString(8);
    return result.slice(-digit);
};

/**
 * Log fatal message.
 * @param message fatal message
 */
Log.prototype.fatal = function (message) {
    if (this.LastLevel != "FATAL") {
        this.LastLevel = "FATAL";
        this.print("*FATAL*");
    }
    this.print(message);
};

/**
 * Log error message.
 * @param message error message
 */
Log.prototype.error = function (message) {
    if (this.LastLevel != "ERROR") {
        this.LastLevel = "ERROR";
        this.print("*ERROR*");
    }
    this.print(message);
};

/**
 * Log warning message.
 * @param message warning message
 */
Log.prototype.warn = function (message) {
    if (this.LastLevel != "WARN") {
        this.LastLevel = "WARN";
        this.print("*WARN*");
    }
    this.print(message);
};

/**
 * Log information message.
 * @param message information message
 */
Log.prototype.info = function (message) {
    if (this.LastLevel != "INFO") {
        this.LastLevel = "INFO";
        this.print("*INFO*");
    }
    this.print(message);
};
<commit_msg>Implement continuous same string elimination<commit_after>/**
 * TOYOSHIMA-HOUSE Library for JavaScript
 */

/**
 * Log prototype
 *
 * This prototype provide common log interfaces.
 * @author Takashi Toyoshima <toyoshim@gmail.com>
 *
 */

/**
 * Log prototype function. This prototype provide three kinds of Log
 * mechanisms. User can specify its type by id argument.
 * @param id Log type
 *     undefined: Use native console.log if it's available.
 *     null: Eliminate all logs.
 *     <string>: Output as pre element under DOM object which has <string> id.
 * @param reverse logging order
 *     true: Newer logs will be added to tail.
 *     false: Newer logs will be added to head.
 */
function Log (id, reverse) {
    this.lastLevel = "";
    this.reverse = reverse;
    this.lastMessage = "";
    this.lastMessageCount = 0;

    // Set default log scheme.
    this.print = function (object) { /* Do nothing. */ };

    if (id == undefined) {
        // Try to use native console.
        if (window.console != undefined) {
            this.print = function (object) {
                console.log(object);
            }
        }
    } else if (id != null) {
        // Try to output under specified DOM object.
        this.frameDiv = document.getElementById(id);
        if (this.frameDiv == undefined)
            return;
        this.framePre = document.createElement('pre');
        this.frameDiv.appendChild(this.framePre);

        this.print = function (object) {
            if (window.console != undefined) {
                console.log(object);
            }
            var element;
            if (object instanceof Object) {
                element = document.createElement('pre');
                var text = object.toString();
                var textNode = document.createTextNode(text);
                element.appendChild(textNode);
                var title = "";
                for (var item in object) {
                    title += item + ":" + object[item] + "; \n";
                }
                element.setAttribute('title', title);
            } else {
                element = document.createTextNode(object + "\n");
            }
            if (this.reverse && this.framePre.firstChild)
                this.framePre.insertBefore(element, this.framePre.firstChild);
            else
                this.framePre.appendChild(element);
        }
    }
}

Log.log = new Log();

/**
 * Set default log instance.
 * @param newLog Log instance to set
 */
Log.setLog = function (newLog) {
    Log.log = newLog;
};

/**
 * Get default log instance.
 * @return default Log instance
 */
Log.getLog = function () {
    return Log.log;
};

/**
 * Convert to hex string.
 * @param number number to convert
 * @param digit result value's digit
 */
Log.toHex = function (number, digit) {
    var sign = number & 0x80000000;
    var result;
    if (sign != 0) {
        result = "fffffff" + (number >> 16).toString(16) +
                (number & 0xffff).toString(16);
    } else {
        result = "0000000" + (number >> 16).toString(16) +
                (number & 0xffff).toString(16);

    }
    return result.slice(-digit);
};

/**
 * Convert to oct string.
 * @param number number to convert
 * @param digit result value's digit
 */
Log.toOct = function (number, digit) {
    var result = "0000000000" + number.toString(8);
    return result.slice(-digit);
};

/**
 * Filter print message.
 * @param message message to print
 */
Log.prototype.prettyPrint = function (message) {
    if (this.lastMessage == message) {
        this.lastMessageCount++;
        return;
    }
    if (this.lastMessageCount != 0) {
        this.print("... repeated " + this.lastMessageCount + "times");
        this.lastMessageCount = 0;
    }
    this.lastMessage = message;
    this.print(message);
};

/**
 * Log fatal message.
 * @param message fatal message
 */
Log.prototype.fatal = function (message) {
    if (this.LastLevel != "FATAL") {
        this.LastLevel = "FATAL";
        this.prettyPrint("*FATAL*");
    }
    this.prettyPrint(message);
};

/**
 * Log error message.
 * @param message error message
 */
Log.prototype.error = function (message) {
    if (this.LastLevel != "ERROR") {
        this.LastLevel = "ERROR";
        this.prettyPrint("*ERROR*");
    }
    this.prettyPrint(message);
};

/**
 * Log warning message.
 * @param message warning message
 */
Log.prototype.warn = function (message) {
    if (this.LastLevel != "WARN") {
        this.LastLevel = "WARN";
        this.prettyPrint("*WARN*");
    }
    this.prettyPrint(message);
};

/**
 * Log information message.
 * @param message information message
 */
Log.prototype.info = function (message) {
    if (this.LastLevel != "INFO") {
        this.LastLevel = "INFO";
        this.prettyPrint("*INFO*");
    }
    this.prettyPrint(message);
};
<|endoftext|>


<commit_before>/*/////////////////////////////////////////////////////////////////////////////////

 MO5.js - JavaScript Library For Building Modern DOM And Canvas Applications

 Copyright (c) 2013 Jonathan Steinbeck
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

 * Neither the name MO5.js nor the names of its contributors
   may be used to endorse or promote products derived from this software
   without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/////////////////////////////////////////////////////////////////////////////////*/

/* global window, require, process, document, console */

if (typeof window !== "undefined") {
    // If the browser doesn't support requestAnimationFrame, use a fallback.
    window.requestAnimationFrame = (function ()
    {
        "use strict";

        return window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            window.msRequestAnimationFrame ||
            function (callback) {
                window.setTimeout(callback, 1000 / 60);
            };
    }());
}

// [].forEach() shim
(function () {
    if (Array.prototype.forEach) {
        return;
    }

    Array.prototype.forEach = function (callback) {
        for (var i = 0, len = this.length; i < len; i += 1) {
            callback(this[i], i, this);
        }
    };
}());

if (typeof console === "undefined") {
    this.console = {};
}

if (!console.log) {
    console.log = function () {};
}

if (!console.dir) {
    console.dir = console.log;
}

if (!console.error) {
    console.error = console.log;
}

if (!console.warn) {
    console.warn = console.log;
}

var MO5 = (function () {

    "use strict";

    var modules = {}, loadedScripts = {};

    /**
     * Inner class representing a Module with a state and dependencies.
     * There can be only one module with a specific name. If another one
     * with the same name is created, the existing one is returned instead.
     */
    function Module (name, callback, dependencies) {

        if (Module.moduleIsReady(name)) {
            return modules[name];
        }

        /** @var The module's name. */
        this.name = name;

        /**
         * @var A callback that genererates the module's contents after
         * all dependencies are ready.
         */
        this.callback = callback;

        /** @var Names of modules this module depends on. */
        this.dependencies = dependencies || [];

        /** @var The current state of the module. Should be one of the "class constants". */
        this.state = Module.STATE_UNINITIALIZED;

        /** @var A List of callbacks to be executed once the module's state is STATE_READY. */
        this.observers = [];

        /** @var The module's content. Only available when the module's state is STATE_READY. */
        this.content = undefined;

        modules[name] = this;
    }

    /** @var State when the loading of the module has not been started yet. */
    Module.STATE_UNINITIALIZED = "unitialized";
    Module.STATE_READY = "ready";

    /**
     * Is the module specified by the moduleName parameter ready to be used?
     */
    Module.moduleIsReady = function (moduleName) {

        if (!(moduleName in modules)) {
            return false;
        }

        return typeof modules[moduleName].isReady === "undefined" ||
            modules[moduleName].isReady();
    };

    /**
     * Are the modules in the moduleNames parameter ready to be used?
     * @param moduleNames Array of module names.
     */
    Module.modulesAreReady = function (moduleNames) {

        var i, len;

        for (i = 0, len = moduleNames.length; i < len; i += 1) {
            if (!Module.moduleIsReady(moduleNames[i])) {
                return false;
            }
        }

        return true;
    };

    /**
     * Gather the contents of all the modules specified in parameter moduleNames.
     * @moduleNames An array with module names.
     */
    Module.gatherDependencies = function (moduleNames) {

        var dependencies = [];

        moduleNames.forEach(function (moduleName) {
            if (modules[moduleName] && typeof modules[moduleName].content === "undefined") {
                dependencies.push(modules[moduleName]);
            }
            else {
                dependencies.push(modules[moduleName].content);
            }
        });

        return dependencies;

    };

    /**
     * Is this module ready to be used?
     */
    Module.prototype.isReady = function () {
        return (this.state === Module.STATE_READY);
    };

    /**
     * Are the dependencies loaded yet?
     */
    Module.prototype.dependenciesReady = function () {
        return Module.modulesAreReady(this.dependencies);
    };

    Module.prototype.getDependenciesNotReady = function () {

        var dependenciesNotReady = [];

        this.dependencies.forEach(function (moduleName) {
            if (modules[moduleName] && !modules[moduleName].isReady()) {
                dependenciesNotReady.push(modules[moduleName]);
            }
        });

        return dependenciesNotReady;
    };

    Module.prototype.addObserverToDependenciesNotReady = function (callback) {
        this.getDependenciesNotReady().forEach(function (module) {
            module.addObserver(callback);
        });
    };

    /**
     * Registers an observer callback with this module which will be called
     * when the module is ready. If the module already is ready, the observer
     * will be called immediately.
     */
    Module.prototype.addObserver = function (observer) {

        if (this.isReady()) {
            observer(this.content);
            return;
        }

        this.observers.push(observer);
    };

    /**
     * Marks this module as ready and calls all observers.
     */
    Module.prototype.finish = function () {

        var dependencies = [], content, self = this;

        if (this.isReady()) {
            return;
        }

        if (!this.dependenciesReady()) {
            this.addObserverToDependenciesNotReady(function () { self.finish(); });
            return;
        }

        dependencies = Module.gatherDependencies(this.dependencies);
        content = this.callback.apply(undefined, dependencies);

        if (typeof content === "undefined") {
            throw new Error("Module definition callback returned undefined!");
        }

        this.content = content;
        this.state = Module.STATE_READY;

        this.observers.forEach(function (observer) {
            observer(content);
        });

        this.observers = []; // remove references to aid the garbage collector
    };

    function MO5 (/* module names */) {

        var moduleNames, runCallbacks = [], defineCallbacks = [], dependencies = [];
        var modulesLoaded = 0, done = false, modulesLoading = false, capabilityObject;

        moduleNames = [].slice.call(arguments);

        capabilityObject = {
            run: run,
            define: define
        };

        return capabilityObject;

        ///////////////////////////////////
        // Helper functions
        ///////////////////////////////////

        function loadModules () {

            var moduleOffset = 0;

            modulesLoading = true;

            moduleNames.forEach(function (moduleName) {

                var currentOffset = moduleOffset;

                moduleOffset += 1;

                if (moduleName.match(/^ajax:/)) {
                    MO5.ajax(MO5.ajax.HTTP_METHOD_GET, moduleName.replace(/^ajax:/, ""),
                        null, ajaxResourceSuccessFn, ajaxResourceSuccessFn);
                }
                else {
                    loadModule(moduleName, loadModuleSuccessFn, function (e) {
                        console.error(e);
                    });
                }

                function ajaxResourceSuccessFn (request) {
                    modules[moduleName] = request;
                    loadModuleSuccessFn(request);
                }

                function loadModuleSuccessFn (module) {

                    modulesLoaded += 1;

                    dependencies[currentOffset] = module;

                    if (modulesLoaded === moduleNames.length) {

                        done = true;

                        defineCallbacks.forEach(function (callback) {
                            try {
                                callback();
                            }
                            catch (e) {
                                console.error("Error while loading module '" + moduleName +
                                    "':", e.stack, callback);
                            }
                        });

                        runCallbacks.forEach(function (callback) {
                            try {
                                callback.apply(undefined, dependencies);
                            }
                            catch (e) {
                                console.error(e.message, e.stack);
                                console.dir(callback);
                            }
                        });
                    }
                }
            });
        }

        function run (callback) {

            if (done) {
                return callback.apply(undefined, dependencies);
            }

            runCallbacks.push(callback);

            if (!modulesLoading) {
                loadModules();
            }

            return capabilityObject;
        }

        function define (moduleName, callback) {

            var module = new Module(moduleName, callback, moduleNames);

            if (module.isReady()) {
                return capabilityObject;
            }

            if (done) {
                module.finish();
                return capabilityObject;
            }

            defineCallbacks.push(finishModule);

            if (!modulesLoading) {
                loadModules();
            }

            return capabilityObject;

            function finishModule () {
                module.finish();
            }
        }
    }

    MO5.path = "";

    (function () {
        var scripts = document.getElementsByTagName("script");

        MO5.path = scripts[scripts.length - 1].src.replace(/MO5\.js$/, "");

    }());

    MO5.modules = {
        "MO5.ajax": MO5.path + "ajax.js",
        "MO5.assert": MO5.path + "assert.js",
        "MO5.Exception": MO5.path + "Exception.js",
        "MO5.fail": MO5.path + "fail.js",
        "MO5.EventBus": MO5.path + "EventBus.js",
        "MO5.CoreObject": MO5.path + "CoreObject.js",
        "MO5.List": MO5.path + "List.js",
        "MO5.Queue": MO5.path + "Queue.js",
        "MO5.Map": MO5.path + "Map.js",
        "MO5.Result": MO5.path + "Result.js", // deprecated - use MO5.Promise instead!
        "MO5.Promise": MO5.path + "Promise.js",
        "MO5.Timer": MO5.path + "Timer.js",
        "MO5.TimerWatcher": MO5.path + "TimerWatcher.js",
        "MO5.easing": MO5.path + "easing.js",
        "MO5.transform": MO5.path + "transform.js",
        "MO5.tools": MO5.path + "tools.js",
        "MO5.Point": MO5.path + "Point.js",
        "MO5.Size": MO5.path + "Size.js",
        "MO5.Animation": MO5.path + "Animation.js",
        "MO5.dom.effects.typewriter": MO5.path + "dom.effects.typewriter.js",
        "MO5.dom.Element": MO5.path + "dom.Element.js",
        "MO5.dom.escape": MO5.path + "dom.escape.js",
        "MO5.types": MO5.path + "types.js"
    };

    function loadModule (moduleName, onSuccess, onError) {

        onError = onError || function (e) { console.error(e.message, e.stack); };

        if (!(moduleName in MO5.modules)) {
            onError(new Error("Unknown module '" + moduleName + "'."));
            return;
        }

        if (Module.moduleIsReady(moduleName)) {
            onScriptLoadSuccess();
        }
        else {
            MO5.loadScript(MO5.modules[moduleName], onScriptLoadSuccess, onError);
        }

        function onScriptLoadSuccess () {

            if (!modules[moduleName] || !modules[moduleName].addObserver) {
                throw new Error("MO5: No module definition for module '" + moduleName +
                    "' found in specified source file '" + MO5.modules[moduleName] + "'.");
            }

            modules[moduleName].addObserver(onSuccess);

            if (modules[moduleName].dependenciesReady()) {
                modules[moduleName].finish();
            }
        }

    }

    MO5.loadScript = function (url, onSuccess, onError) {

        var script = document.createElement("script");

        if (loadedScripts[url]) {
            onSuccess();
            return;
        }

        try {
            script.onload = onload;
            script.onreadystatechange = onload;
            script.src = url;
            document.body.appendChild(script);
        }
        catch (e) {
            onError(e);
        }

        function onload () {
            if (!script.readyState || script.readyState === "loaded" || script.readyState === "complete") {
                loadedScripts[url] = true;
                onSuccess();
            }
        }
    };

    MO5.defaults = {
        fps: 30,
        debug: true,
        canvas: {
            width: 640, // default width for canvas elements
            height: 480 // default height for canvas elements
        }
    };

    return MO5;

}());

/* global MO5, XMLHttpRequest, ActiveXObject */

MO5.ajax = (function () {

    var HTTP_STATUS_OK = 200;
    var READY_STATE_UNSENT = 0;
    var READY_STATE_OPENED = 1;
    var READY_STATE_HEADERS_RECEIVED = 2;
    var READY_STATE_LOADING = 3;
    var READY_STATE_DONE = 4;

    function ajax (method, url, data, onSuccess, onError) {

        var requestObject = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");

        requestObject.open(method, url + "?random=" + Math.random(), true);

        requestObject.onreadystatechange = function() {
            var done, statusOk;

            done = requestObject.readyState === READY_STATE_DONE;
            statusOk = requestObject.status === HTTP_STATUS_OK;

            if (done) {
                if (statusOk) {
                    onSuccess(requestObject);
                }
                else {
                    onError(requestObject);
                }
            }
        };

        if (data) {
            requestObject.send(data);
        }
        else {
            requestObject.send();
        }

        return requestObject;
    }

    ajax.HTTP_STATUS_OK = HTTP_STATUS_OK;

    ajax.READY_STATE_UNSENT = READY_STATE_UNSENT;
    ajax.READY_STATE_OPENED = READY_STATE_OPENED;
    ajax.READY_STATE_HEADERS_RECEIVED = READY_STATE_HEADERS_RECEIVED;
    ajax.READY_STATE_LOADING = READY_STATE_LOADING;
    ajax.READY_STATE_DONE = READY_STATE_DONE;

    ajax.HTTP_METHOD_GET = "GET";
    ajax.HTTP_METHOD_POST = "POST";
    ajax.HTTP_METHOD_PUT = "PUT";
    ajax.HTTP_METHOD_DELETE = "DELETE";
    ajax.HTTP_METHOD_HEAD = "HEAD";

    return ajax;
}());<commit_msg>Added new globals modules to the MO5 default paths.<commit_after>/*/////////////////////////////////////////////////////////////////////////////////

 MO5.js - JavaScript Library For Building Modern DOM And Canvas Applications

 Copyright (c) 2013 Jonathan Steinbeck
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

 * Neither the name MO5.js nor the names of its contributors
   may be used to endorse or promote products derived from this software
   without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/////////////////////////////////////////////////////////////////////////////////*/

/* global window, require, process, document, console */

if (typeof window !== "undefined") {
    // If the browser doesn't support requestAnimationFrame, use a fallback.
    window.requestAnimationFrame = (function ()
    {
        "use strict";

        return window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            window.msRequestAnimationFrame ||
            function (callback) {
                window.setTimeout(callback, 1000 / 60);
            };
    }());
}

// [].forEach() shim
(function () {
    if (Array.prototype.forEach) {
        return;
    }

    Array.prototype.forEach = function (callback) {
        for (var i = 0, len = this.length; i < len; i += 1) {
            callback(this[i], i, this);
        }
    };
}());

if (typeof console === "undefined") {
    this.console = {};
}

if (!console.log) {
    console.log = function () {};
}

if (!console.dir) {
    console.dir = console.log;
}

if (!console.error) {
    console.error = console.log;
}

if (!console.warn) {
    console.warn = console.log;
}

var MO5 = (function () {

    "use strict";

    var modules = {}, loadedScripts = {};

    /**
     * Inner class representing a Module with a state and dependencies.
     * There can be only one module with a specific name. If another one
     * with the same name is created, the existing one is returned instead.
     */
    function Module (name, callback, dependencies) {

        if (Module.moduleIsReady(name)) {
            return modules[name];
        }

        /** @var The module's name. */
        this.name = name;

        /**
         * @var A callback that genererates the module's contents after
         * all dependencies are ready.
         */
        this.callback = callback;

        /** @var Names of modules this module depends on. */
        this.dependencies = dependencies || [];

        /** @var The current state of the module. Should be one of the "class constants". */
        this.state = Module.STATE_UNINITIALIZED;

        /** @var A List of callbacks to be executed once the module's state is STATE_READY. */
        this.observers = [];

        /** @var The module's content. Only available when the module's state is STATE_READY. */
        this.content = undefined;

        modules[name] = this;
    }

    /** @var State when the loading of the module has not been started yet. */
    Module.STATE_UNINITIALIZED = "unitialized";
    Module.STATE_READY = "ready";

    /**
     * Is the module specified by the moduleName parameter ready to be used?
     */
    Module.moduleIsReady = function (moduleName) {

        if (!(moduleName in modules)) {
            return false;
        }

        return typeof modules[moduleName].isReady === "undefined" ||
            modules[moduleName].isReady();
    };

    /**
     * Are the modules in the moduleNames parameter ready to be used?
     * @param moduleNames Array of module names.
     */
    Module.modulesAreReady = function (moduleNames) {

        var i, len;

        for (i = 0, len = moduleNames.length; i < len; i += 1) {
            if (!Module.moduleIsReady(moduleNames[i])) {
                return false;
            }
        }

        return true;
    };

    /**
     * Gather the contents of all the modules specified in parameter moduleNames.
     * @moduleNames An array with module names.
     */
    Module.gatherDependencies = function (moduleNames) {

        var dependencies = [];

        moduleNames.forEach(function (moduleName) {
            if (modules[moduleName] && typeof modules[moduleName].content === "undefined") {
                dependencies.push(modules[moduleName]);
            }
            else {
                dependencies.push(modules[moduleName].content);
            }
        });

        return dependencies;

    };

    /**
     * Is this module ready to be used?
     */
    Module.prototype.isReady = function () {
        return (this.state === Module.STATE_READY);
    };

    /**
     * Are the dependencies loaded yet?
     */
    Module.prototype.dependenciesReady = function () {
        return Module.modulesAreReady(this.dependencies);
    };

    Module.prototype.getDependenciesNotReady = function () {

        var dependenciesNotReady = [];

        this.dependencies.forEach(function (moduleName) {
            if (modules[moduleName] && !modules[moduleName].isReady()) {
                dependenciesNotReady.push(modules[moduleName]);
            }
        });

        return dependenciesNotReady;
    };

    Module.prototype.addObserverToDependenciesNotReady = function (callback) {
        this.getDependenciesNotReady().forEach(function (module) {
            module.addObserver(callback);
        });
    };

    /**
     * Registers an observer callback with this module which will be called
     * when the module is ready. If the module already is ready, the observer
     * will be called immediately.
     */
    Module.prototype.addObserver = function (observer) {

        if (this.isReady()) {
            observer(this.content);
            return;
        }

        this.observers.push(observer);
    };

    /**
     * Marks this module as ready and calls all observers.
     */
    Module.prototype.finish = function () {

        var dependencies = [], content, self = this;

        if (this.isReady()) {
            return;
        }

        if (!this.dependenciesReady()) {
            this.addObserverToDependenciesNotReady(function () { self.finish(); });
            return;
        }

        dependencies = Module.gatherDependencies(this.dependencies);
        content = this.callback.apply(undefined, dependencies);

        if (typeof content === "undefined") {
            throw new Error("Module definition callback returned undefined!");
        }

        this.content = content;
        this.state = Module.STATE_READY;

        this.observers.forEach(function (observer) {
            observer(content);
        });

        this.observers = []; // remove references to aid the garbage collector
    };

    function MO5 (/* module names */) {

        var moduleNames, runCallbacks = [], defineCallbacks = [], dependencies = [];
        var modulesLoaded = 0, done = false, modulesLoading = false, capabilityObject;

        moduleNames = [].slice.call(arguments);

        capabilityObject = {
            run: run,
            define: define
        };

        return capabilityObject;

        ///////////////////////////////////
        // Helper functions
        ///////////////////////////////////

        function loadModules () {

            var moduleOffset = 0;

            modulesLoading = true;

            moduleNames.forEach(function (moduleName) {

                var currentOffset = moduleOffset;

                moduleOffset += 1;

                if (moduleName.match(/^ajax:/)) {
                    MO5.ajax(MO5.ajax.HTTP_METHOD_GET, moduleName.replace(/^ajax:/, ""),
                        null, ajaxResourceSuccessFn, ajaxResourceSuccessFn);
                }
                else {
                    loadModule(moduleName, loadModuleSuccessFn, function (e) {
                        console.error(e);
                    });
                }

                function ajaxResourceSuccessFn (request) {
                    modules[moduleName] = request;
                    loadModuleSuccessFn(request);
                }

                function loadModuleSuccessFn (module) {

                    modulesLoaded += 1;

                    dependencies[currentOffset] = module;

                    if (modulesLoaded === moduleNames.length) {

                        done = true;

                        defineCallbacks.forEach(function (callback) {
                            try {
                                callback();
                            }
                            catch (e) {
                                console.error("Error while loading module '" + moduleName +
                                    "':", e.stack, callback);
                            }
                        });

                        runCallbacks.forEach(function (callback) {
                            try {
                                callback.apply(undefined, dependencies);
                            }
                            catch (e) {
                                console.error(e.message, e.stack);
                                console.dir(callback);
                            }
                        });
                    }
                }
            });
        }

        function run (callback) {

            if (done) {
                return callback.apply(undefined, dependencies);
            }

            runCallbacks.push(callback);

            if (!modulesLoading) {
                loadModules();
            }

            return capabilityObject;
        }

        function define (moduleName, callback) {

            var module = new Module(moduleName, callback, moduleNames);

            if (module.isReady()) {
                return capabilityObject;
            }

            if (done) {
                module.finish();
                return capabilityObject;
            }

            defineCallbacks.push(finishModule);

            if (!modulesLoading) {
                loadModules();
            }

            return capabilityObject;

            function finishModule () {
                module.finish();
            }
        }
    }

    MO5.path = "";

    (function () {
        var scripts = document.getElementsByTagName("script");

        MO5.path = scripts[scripts.length - 1].src.replace(/MO5\.js$/, "");

    }());

    MO5.modules = {
        "MO5.ajax": MO5.path + "ajax.js",
        "MO5.assert": MO5.path + "assert.js",
        "MO5.Exception": MO5.path + "Exception.js",
        "MO5.fail": MO5.path + "fail.js",
        "MO5.EventBus": MO5.path + "EventBus.js",
        "MO5.CoreObject": MO5.path + "CoreObject.js",
        "MO5.List": MO5.path + "List.js",
        "MO5.Queue": MO5.path + "Queue.js",
        "MO5.Map": MO5.path + "Map.js",
        "MO5.Result": MO5.path + "Result.js", // deprecated - use MO5.Promise instead!
        "MO5.Promise": MO5.path + "Promise.js",
        "MO5.Timer": MO5.path + "Timer.js",
        "MO5.TimerWatcher": MO5.path + "TimerWatcher.js",
        "MO5.easing": MO5.path + "easing.js",
        "MO5.transform": MO5.path + "transform.js",
        "MO5.tools": MO5.path + "tools.js",
        "MO5.Point": MO5.path + "Point.js",
        "MO5.Size": MO5.path + "Size.js",
        "MO5.Animation": MO5.path + "Animation.js",
        "MO5.dom.effects.typewriter": MO5.path + "dom.effects.typewriter.js",
        "MO5.dom.Element": MO5.path + "dom.Element.js",
        "MO5.dom.escape": MO5.path + "dom.escape.js",
        "MO5.globals.document": MO5.path + "globals.document.js",
        "MO5.globals.window": MO5.path + "globals.window.js",
        "MO5.types": MO5.path + "types.js"
    };

    function loadModule (moduleName, onSuccess, onError) {

        onError = onError || function (e) { console.error(e.message, e.stack); };

        if (!(moduleName in MO5.modules)) {
            onError(new Error("Unknown module '" + moduleName + "'."));
            return;
        }

        if (Module.moduleIsReady(moduleName)) {
            onScriptLoadSuccess();
        }
        else {
            MO5.loadScript(MO5.modules[moduleName], onScriptLoadSuccess, onError);
        }

        function onScriptLoadSuccess () {

            if (!modules[moduleName] || !modules[moduleName].addObserver) {
                throw new Error("MO5: No module definition for module '" + moduleName +
                    "' found in specified source file '" + MO5.modules[moduleName] + "'.");
            }

            modules[moduleName].addObserver(onSuccess);

            if (modules[moduleName].dependenciesReady()) {
                modules[moduleName].finish();
            }
        }

    }

    MO5.loadScript = function (url, onSuccess, onError) {

        var script = document.createElement("script");

        if (loadedScripts[url]) {
            onSuccess();
            return;
        }

        try {
            script.onload = onload;
            script.onreadystatechange = onload;
            script.src = url;
            document.body.appendChild(script);
        }
        catch (e) {
            onError(e);
        }

        function onload () {
            if (!script.readyState || script.readyState === "loaded" || script.readyState === "complete") {
                loadedScripts[url] = true;
                onSuccess();
            }
        }
    };

    MO5.defaults = {
        fps: 30,
        debug: true,
        canvas: {
            width: 640, // default width for canvas elements
            height: 480 // default height for canvas elements
        }
    };

    return MO5;

}());

/* global MO5, XMLHttpRequest, ActiveXObject */

MO5.ajax = (function () {

    var HTTP_STATUS_OK = 200;
    var READY_STATE_UNSENT = 0;
    var READY_STATE_OPENED = 1;
    var READY_STATE_HEADERS_RECEIVED = 2;
    var READY_STATE_LOADING = 3;
    var READY_STATE_DONE = 4;

    function ajax (method, url, data, onSuccess, onError) {

        var requestObject = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");

        requestObject.open(method, url + "?random=" + Math.random(), true);

        requestObject.onreadystatechange = function() {
            var done, statusOk;

            done = requestObject.readyState === READY_STATE_DONE;
            statusOk = requestObject.status === HTTP_STATUS_OK;

            if (done) {
                if (statusOk) {
                    onSuccess(requestObject);
                }
                else {
                    onError(requestObject);
                }
            }
        };

        if (data) {
            requestObject.send(data);
        }
        else {
            requestObject.send();
        }

        return requestObject;
    }

    ajax.HTTP_STATUS_OK = HTTP_STATUS_OK;

    ajax.READY_STATE_UNSENT = READY_STATE_UNSENT;
    ajax.READY_STATE_OPENED = READY_STATE_OPENED;
    ajax.READY_STATE_HEADERS_RECEIVED = READY_STATE_HEADERS_RECEIVED;
    ajax.READY_STATE_LOADING = READY_STATE_LOADING;
    ajax.READY_STATE_DONE = READY_STATE_DONE;

    ajax.HTTP_METHOD_GET = "GET";
    ajax.HTTP_METHOD_POST = "POST";
    ajax.HTTP_METHOD_PUT = "PUT";
    ajax.HTTP_METHOD_DELETE = "DELETE";
    ajax.HTTP_METHOD_HEAD = "HEAD";

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


<commit_before>(function($)
{
  var router = new $.mobile.Router( [
   {"#page-authorize": {handler: "pageAuthorize",
         events: "s", // do when we show the page
         argsre: true
       } },

        {"#home": {handler: "home",
          events: "s", // do when we show the page
          argsre: true
        } },

        {"#listing": {handler: "listing",
          events: "s", // do when we show the page
          argsre: true
        } },
        {"#registering-ruleset": {handler: "registeringRuleset",
          events: "s", // do when we show the page
          argsre: true
        } },
        {"#confirming-deletion": {handler: "confirmingDeletion",
          events: "s", // do when we show the page
          argsre: true
        } },
        {"#updating-url": {handler: "updatingUrl",
          events: "s", // do when we show the page
          argsre: true
        } },
        {"#page-picologging": {handler: "picologging",
          events: "s", // do when we show the page
          argsre: true
        } }
        ],
        {
          pageAuthorize: function(type, match, ui, page) {
            console.log("manage fuse: authorize page");
            $.mobile.loading("hide");
          },

          home: function(type, match, ui, page) {
            console.log("home Handler");
          },

          listing: function(type, match, ui, page) {
            console.log("listing Handler");

              Devtools.getRulesets(function(rids_json){ //the callback/function is where we need to have all of our code
              console.log(rids_json);

              //this is for a table
              /*
              var len = rids_json.length;
              var txt = "";
              if(len > 0){
                for(var i=0;i<len;i++){
                    txt += "
"+rids_json[i].rid+"	"+rids_json[i].uri+"	button
";

                  }
                if(txt !== ""){
                        $("#ruleset-list").html(txt);
                        $("#ruleset-list").listview('refresh');
                  }
                else{
                    $("#ruleset-list").html("
 NONE 	 NONE 	");
                    $("#ruleset-list").listview('refresh');
                }
              } */

              //trying for a list

              console.log("attempting rough listview");

             $.each(rids_json, function(key, value){
               $.each(value, function(key, value){
                  console.log(key, value);
                 });
              });

              var keys = rids_json.sort(sortBy("rid_index"));
              console.log("keys: " + keys);
              $.each(rids_json, paint_item);
              $.each(keys, paint_item);

              console.log("refreshing manage-list listview.")

              $('#manage-list').listview('refresh');
                });

          // document.getElementById("List-Rulesets").innerHTML = obj;

            /*var frm = "#ruleset-form";
            $(frm)[0].reset();
            var owner_eci = CloudOS.defaultECI; //from pageUpdateProfile

              $("#RID", frm).val(ruleset_obj.rid);
              $("#source-URL", frm).val(ruleset_obj.uri);*/

          },
          registeringRuleset: function(type, match, ui, page) {
            console.log("registering Ruleset Handler");
          },
          confirmingDeletion: function(type, match, ui, page) {
            console.log("confirming Deletion Handler");
          },
          updatingUrl: function(type, match, ui, page) {
            console.log("updating Url Handler");
          },
          picologging: function(type, match, ui, page) {
            console.log("pico logging page");
            $.mobile.loading("hide");
          }
        },
      {
        defaultHandler: function(type, ui, page) {
          console.log("Default handler called due to unknown route (" + type + ", " + ui + ", " + page + ")");
        },
        defaultHandlerEvents: "s",
        defaultArgsRe: true

      });
      // Handlebar templates compiled at load time to create functions
      // templates are included to index.html from Templates directory.
      window['snippets'] = {
        list_rulesets_template: Handlebars.compile($("#list-rulesets-template").html() || ""),
      };

      function plant_authorize_button()
      {
        //Oauth through kynetx
        console.log("plant authorize button");
        var OAuth_kynetx_URL = CloudOS.getOAuthURL();
        $('#authorize-link').attr('href', OAuth_kynetx_URL);
        var OAuth_kynetx_newuser_URL = CloudOS.getOAuthNewAccountURL();
        $('#create-link').attr('href', OAuth_kynetx_newuser_URL);
      }

      function onMobileInit() {
       console.log("mobile init");
       $.mobile.autoInitialize = false;
     }

    function onPageLoad() {// Document.Ready
    	console.log("document ready");
	CloudOS.retrieveSession();
	// only put static stuff here...
	plant_authorize_button();

	$('.logout').off("tap").on("tap", function(event)
	   {
	       CloudOS.removeSession(true); // true for hard reset (log out of login server too)
	       $.mobile.changePage('#page-authorize', {
		   transition: 'slide'
	       }); // this will go to the authorization page.
	   });

	console.log("Choose page to show");

	try {
	    var authd = CloudOS.authenticatedSession();
	    if(authd) {
		console.log("Authorized");
		document.location.hash = "#home";
	    } else {
		console.log("Asking for authorization");
		document.location.hash = "#page-authorize";
	    }
	} catch (exception) {

	} finally {
	    $.mobile.initializePage();
	    $.mobile.loading("hide");
	}

    };

    /////////////////////////////////////////////////////////////////////
    // this is the actual code that runs and sets everything off
    // pull the session out of the cookie.
    $(document).bind("mobileinit", onMobileInit);
    $(document).ready(onPageLoad);
  })(jQuery);

    function sortBy(prop){
              return function(a,b){
            if( a[prop]  b[prop] ){
                return -1;
            }
            return 0;
              };
          };
    function paint_item(id, rids) {//(key,value)

          /*if (typeof vehicle === "undefined") {
        return;
          }*/
          var status = "no status"; // place holder for description
         console.log("in paint_item");
         console.log(id, rids);

        $("#manage-list li:nth-child(1)" ).after( //was #manage-fleet prior
            snippets.list_rulesets_template(
              {"rid": rids.rid,
               "uri": rids.uri,
               "description": status
              }));
    };

<commit_msg>paint<commit_after>(function($)
{
  var router = new $.mobile.Router( [
   {"#page-authorize": {handler: "pageAuthorize",
         events: "s", // do when we show the page
         argsre: true
       } },

        {"#home": {handler: "home",
          events: "s", // do when we show the page
          argsre: true
        } },

        {"#listing": {handler: "listing",
          events: "s", // do when we show the page
          argsre: true
        } },
        {"#registering-ruleset": {handler: "registeringRuleset",
          events: "s", // do when we show the page
          argsre: true
        } },
        {"#confirming-deletion": {handler: "confirmingDeletion",
          events: "s", // do when we show the page
          argsre: true
        } },
        {"#updating-url": {handler: "updatingUrl",
          events: "s", // do when we show the page
          argsre: true
        } },
        {"#page-picologging": {handler: "picologging",
          events: "s", // do when we show the page
          argsre: true
        } }
        ],
        {
          pageAuthorize: function(type, match, ui, page) {
            console.log("manage fuse: authorize page");
            $.mobile.loading("hide");
          },

          home: function(type, match, ui, page) {
            console.log("home Handler");
          },

          listing: function(type, match, ui, page) {
            console.log("listing Handler");

              Devtools.getRulesets(function(rids_json){ //the callback/function is where we need to have all of our code
              console.log(rids_json);

              //this is for a table
              /*
              var len = rids_json.length;
              var txt = "";
              if(len > 0){
                for(var i=0;i<len;i++){
                    txt += "
"+rids_json[i].rid+"	"+rids_json[i].uri+"	button
";

                  }
                if(txt !== ""){
                        $("#ruleset-list").html(txt);
                        $("#ruleset-list").listview('refresh');
                  }
                else{
                    $("#ruleset-list").html("
 NONE 	 NONE 	");
                    $("#ruleset-list").listview('refresh');
                }
              } */

              //trying for a list

              console.log("attempting rough listview");

             $.each(rids_json, function(key, value){
               $.each(value, function(key, value){
                  console.log(key, value);
                 });
              });

              var keys = rids_json.sort(sortBy("rid_index"));
              console.log("keys: " + keys);
              $.each(rids_json, paint_item);
            //  $.each(keys, paint_item);

              console.log("refreshing manage-list listview.")

              $('#manage-list').listview('refresh');
                });

          // document.getElementById("List-Rulesets").innerHTML = obj;

            /*var frm = "#ruleset-form";
            $(frm)[0].reset();
            var owner_eci = CloudOS.defaultECI; //from pageUpdateProfile

              $("#RID", frm).val(ruleset_obj.rid);
              $("#source-URL", frm).val(ruleset_obj.uri);*/

          },
          registeringRuleset: function(type, match, ui, page) {
            console.log("registering Ruleset Handler");
          },
          confirmingDeletion: function(type, match, ui, page) {
            console.log("confirming Deletion Handler");
          },
          updatingUrl: function(type, match, ui, page) {
            console.log("updating Url Handler");
          },
          picologging: function(type, match, ui, page) {
            console.log("pico logging page");
            $.mobile.loading("hide");
          }
        },
      {
        defaultHandler: function(type, ui, page) {
          console.log("Default handler called due to unknown route (" + type + ", " + ui + ", " + page + ")");
        },
        defaultHandlerEvents: "s",
        defaultArgsRe: true

      });
      // Handlebar templates compiled at load time to create functions
      // templates are included to index.html from Templates directory.
      window['snippets'] = {
        list_rulesets_template: Handlebars.compile($("#list-rulesets-template").html() || ""),
      };

      function plant_authorize_button()
      {
        //Oauth through kynetx
        console.log("plant authorize button");
        var OAuth_kynetx_URL = CloudOS.getOAuthURL();
        $('#authorize-link').attr('href', OAuth_kynetx_URL);
        var OAuth_kynetx_newuser_URL = CloudOS.getOAuthNewAccountURL();
        $('#create-link').attr('href', OAuth_kynetx_newuser_URL);
      }

      function onMobileInit() {
       console.log("mobile init");
       $.mobile.autoInitialize = false;
     }

    function onPageLoad() {// Document.Ready
    	console.log("document ready");
	CloudOS.retrieveSession();
	// only put static stuff here...
	plant_authorize_button();

	$('.logout').off("tap").on("tap", function(event)
	   {
	       CloudOS.removeSession(true); // true for hard reset (log out of login server too)
	       $.mobile.changePage('#page-authorize', {
		   transition: 'slide'
	       }); // this will go to the authorization page.
	   });

	console.log("Choose page to show");

	try {
	    var authd = CloudOS.authenticatedSession();
	    if(authd) {
		console.log("Authorized");
		document.location.hash = "#home";
	    } else {
		console.log("Asking for authorization");
		document.location.hash = "#page-authorize";
	    }
	} catch (exception) {

	} finally {
	    $.mobile.initializePage();
	    $.mobile.loading("hide");
	}

    };

    /////////////////////////////////////////////////////////////////////
    // this is the actual code that runs and sets everything off
    // pull the session out of the cookie.
    $(document).bind("mobileinit", onMobileInit);
    $(document).ready(onPageLoad);
  })(jQuery);

    function sortBy(prop){
              return function(a,b){
            if( a[prop]  b[prop] ){
                return -1;
            }
            return 0;
              };
          };
    function paint_item(id, rids) {//(key,value)

          /*if (typeof vehicle === "undefined") {
        return;
          }*/
          var status = "no status"; // place holder for description
         console.log("in paint_item");
         console.log(id, rids);

        $("#manage-list li:nth-child(1)" ).after( //was #manage-fleet prior
            snippets.list_rulesets_template(
              {"rid": rids.rid,
               "uri": rids.uri,
               "description": status
              }));
    };

<|endoftext|>


<commit_before>//Licensed under the MIT license
$(document).ready(function(){
	//Testing data
	//var cookieData = {playAudio: true, showShootCountdown: false, targets: "5", color: "btn-primary", setupTime: "5", timeBefore: "10"};

	var cookieAsString = Cookies.get('TableSoccerSettings');
	//var cookieData = Cookies.getJSON('TableSoccerSettings');

	var training = new TrainingClass(cookieData);

	if(typeof cookieData != 'undefined'){
		$('#runSetup').hide();
		$('#startTraining').show();
		$('#startTraining').click(function(){
			training.start();
		});
	}

	$('#stopTraining').click(function(){
		training.stop();
	});

	$('#hit').click(function(){
		training.hit++;
		$('#hitInfo').html(training.hit + '/' +training.shoot + ' (' +(Math.round(training.hit/training.shoot*100)) + '%)');
	});
});

function TrainingClass(cookieData){
	this.isRunning = false;
	this.cookie = cookieData;

	this.shoot = 0;
	this.hit = 0;
	this.percentage = 0;
	this.$targets = {};

	this.start = function(){
		$('#'+this.cookie.targets+'-targets').show();
		$('#startTraining').hide();

		this.shoot = 0;
		this.hit = 0;
		this.percentage = 0;
		this.$targets = {};

		for(var i = 1; i <= this.cookie.targets; i++){
			this.$targets[this.cookie.targets + '-target-' + i] = $('#'+this.cookie.targets+'-target-'+i);
		}
		$('#stopTraining').show();
		$('#hitInfo').html('0/0 (0%)');

		if(!this.cookie.showShootCountdown){
			$('#shootCountdown').hide();
		}

		this.isRunning = true;
		this.setupCountdown();
	};

	this.stop = function(){
		this.isRunning = false;
		$('#startTraining').show();
		$('#setupContainer').hide();
		$('#shootContainer').hide();
		$('#stopTraining').hide();
		this.hit = 0;
		this.shoot = 0;
		clearInterval(this.interval);
		for(var key in this.$targets){
			this.$targets[key].removeClass(this.color);
		}
	};

	this.setupCountdown = function(){
		$('#setupContainer').show();
		var $setupCountdown = $('#setupCountdown');
		var counter = parseInt(this.cookie.setupTime, 10);
		if(this.shoot > 0){
			$('#hitInfo').html(this.hit + '/' +this.shoot + ' (' +Math.round((this.hit/this.shoot*100)) + '%)');
		}
		$setupCountdown.html(counter);
		var self = this;
		self.interval = setInterval(function(){
			counter--;
			if(counter >= 0) {
				$setupCountdown.html(counter);
				for(var key in self.$targets){
					self.$targets[key].removeClass(self.cookie.color);
				}

			}
			if(counter === 0){
				$('#setupContainer').hide();
				clearInterval(self.interval);
				if(self.isRunning === true){
					self.shootCountdown();
				}
			}
		}, 1000);
	};

	this.shootCountdown = function(){
		$('#shootContainer').show();
		var $shootCountdown = $('#shootCountdown');
		var counter = this.rand(1, parseInt(this.cookie.timeBefore, 10));

		$shootCountdown.html(counter);
		var self = this;
		self.interval = setInterval(function(){
			counter--;
			if(counter >= 0) {
				$shootCountdown.html(counter);
			}
			if(counter === 0){
				//Set target
				var numberOfTargets = parseInt(self.cookie.targets, 10);
				var targetNo = self.rand(1, numberOfTargets);
				self.$targets[numberOfTargets+'-target-'+targetNo].addClass(self.cookie.color);
				if(self.cookie.playAudio === true){
					document.getElementById('beep').play();
				}

				$('#shootContainer').hide();
				clearInterval(self.interval);
				self.shoot++;
				if(self.isRunning === true){
					self.setupCountdown();
				}
			}
		}, 1000);
	};

	this.rand = function(min, max){
		max = max + 1;
		return parseInt((Math.random() * (max - min) + min), 10);
	};
}
<commit_msg>Add cookie support<commit_after>//Licensed under the MIT license
$(document).ready(function(){
	//Testing data
	//var cookieData = {playAudio: true, showShootCountdown: false, targets: "5", color: "btn-primary", setupTime: "5", timeBefore: "10"};

	var cookieAsString = Cookies.get('TableSoccerSettings');
	var cookieData = Cookies.getJSON('TableSoccerSettings');

	var training = new TrainingClass(cookieData);

	if(typeof cookieData != 'undefined'){
		$('#runSetup').hide();
		$('#startTraining').show();
		$('#startTraining').click(function(){
			training.start();
		});
	}

	$('#stopTraining').click(function(){
		training.stop();
	});

	$('#hit').click(function(){
		training.hit++;
		$('#hitInfo').html(training.hit + '/' +training.shoot + ' (' +(Math.round(training.hit/training.shoot*100)) + '%)');
	});
});

function TrainingClass(cookieData){
	this.isRunning = false;
	this.cookie = cookieData;

	this.shoot = 0;
	this.hit = 0;
	this.percentage = 0;
	this.$targets = {};

	this.start = function(){
		$('#'+this.cookie.targets+'-targets').show();
		$('#startTraining').hide();

		this.shoot = 0;
		this.hit = 0;
		this.percentage = 0;
		this.$targets = {};

		for(var i = 1; i <= this.cookie.targets; i++){
			this.$targets[this.cookie.targets + '-target-' + i] = $('#'+this.cookie.targets+'-target-'+i);
		}
		$('#stopTraining').show();
		$('#hitInfo').html('0/0 (0%)');

		if(!this.cookie.showShootCountdown){
			$('#shootCountdown').hide();
		}

		this.isRunning = true;
		this.setupCountdown();
	};

	this.stop = function(){
		this.isRunning = false;
		$('#startTraining').show();
		$('#setupContainer').hide();
		$('#shootContainer').hide();
		$('#stopTraining').hide();
		this.hit = 0;
		this.shoot = 0;
		clearInterval(this.interval);
		for(var key in this.$targets){
			this.$targets[key].removeClass(this.color);
		}
	};

	this.setupCountdown = function(){
		$('#setupContainer').show();
		var $setupCountdown = $('#setupCountdown');
		var counter = parseInt(this.cookie.setupTime, 10);
		if(this.shoot > 0){
			$('#hitInfo').html(this.hit + '/' +this.shoot + ' (' +Math.round((this.hit/this.shoot*100)) + '%)');
		}
		$setupCountdown.html(counter);
		var self = this;
		self.interval = setInterval(function(){
			counter--;
			if(counter >= 0) {
				$setupCountdown.html(counter);
				for(var key in self.$targets){
					self.$targets[key].removeClass(self.cookie.color);
				}

			}
			if(counter === 0){
				$('#setupContainer').hide();
				clearInterval(self.interval);
				if(self.isRunning === true){
					self.shootCountdown();
				}
			}
		}, 1000);
	};

	this.shootCountdown = function(){
		$('#shootContainer').show();
		var $shootCountdown = $('#shootCountdown');
		var counter = this.rand(1, parseInt(this.cookie.timeBefore, 10));

		$shootCountdown.html(counter);
		var self = this;
		self.interval = setInterval(function(){
			counter--;
			if(counter >= 0) {
				$shootCountdown.html(counter);
			}
			if(counter === 0){
				//Set target
				var numberOfTargets = parseInt(self.cookie.targets, 10);
				var targetNo = self.rand(1, numberOfTargets);
				self.$targets[numberOfTargets+'-target-'+targetNo].addClass(self.cookie.color);
				if(self.cookie.playAudio === true){
					document.getElementById('beep').play();
				}

				$('#shootContainer').hide();
				clearInterval(self.interval);
				self.shoot++;
				if(self.isRunning === true){
					self.setupCountdown();
				}
			}
		}, 1000);
	};

	this.rand = function(min, max){
		max = max + 1;
		return parseInt((Math.random() * (max - min) + min), 10);
	};
}
<|endoftext|>