<commit_before>import {observable} from 'mobservable';

const store = observable({
    articles: {
        data: [],
        isFetching: false,
        errors: [],
        lastRequest: null
    },
    isFakeApi: true
});

class StoreAdapter {
    constructor() {
        if(this.create === undefined) { throw new TypeError('Must override create method'); }
        if(this.update === undefined) { throw new TypeError('Must override update method'); }
        if(this.read === undefined) { throw new TypeError('Must override read method'); }
        if(this.read_all === undefined) { throw new TypeError('Must override read method'); }
        if(this.delete === undefined) { throw new TypeError('Must override delete method'); }
    }
}

class RestApiStoreAdapter extends StoreAdapter {
    constructor(noun, url) {
        super();
        this.noun = noun;
        this.url = url;
    }

    create(item) {
        console.log('rest adapter create');
        const requestStartTime = (new Date()).getTime();
        this.post(requestStartTime, item);
    }

    update(item) {
        console.log('rest adapter update');

    }

    read(id) {
        console.log('rest adapter read');
    }

    read_all() {
        console.log('rest adapter read all');
        if(store[this.noun] == undefined || store[this.noun] == null) {
            store[this.noun] = Object.assign({}, store[this.noun], {
                data: [],
                isFetching: true,
                errors: [],
                lastRequest: null
            });
        } else {
            store[this.noun] = Object.assign({}, store[this.noun], {
                isFetching: true,
                lastRequest: null
            });
            // debugger;
            // if(store[this.noun].data == undefined) {
            //     store[this.noun].data = []
            // }
        }

        console.log('Fetching: ', this.url);
        const requestStartTime = (new Date()).getTime();
        this.get(requestStartTime);
    }

    post(requestStartTime, item) {
        var data = new FormData();
        data.append( this.noun, JSON.stringify( item ).toString() );

        fetch(this.url + '/' + this.noun,
        {
            method: "POST",
            body: data
        }).then(response => response.json())
        .then(json => {
            // do something
        })
        .catch((error) => {
            debugger;

            if(store[this.noun].lastRequest != null && requestStartTime < store[this.noun].lastRequest) {
                console.log('STALE ERROR RESPONSE', 'this response is older than another response! ', requestStartTime, store[this.noun].lastRequest);
                return;
            }

            // do something else
        });
    }

    put(requestStartTime, item) {

    }

    delete(requestStartTime, id) {

    }

    get(requestStartTime) {
        fetch(this.url + '/' + this.noun + '.json')
            .then(response => response.json())
            .then(json => {
                if(store[this.noun].lastRequest != null && requestStartTime < store[this.noun].lastRequest) {
                    console.log('STALE SUCCESS RESPONSE', 'this response is older than another response! ', requestStartTime, store[this.noun].lastRequest);
                    return;
                }
                console.log('success: ', json[this.noun]);

                if(json.error != null || json.error != undefined) {
                    throw new Error('Not Found');
                }

                store[this.noun] = {
                    data: json[this.noun],
                    errors: [],
                    isFetching: false,
                    lastRequest: requestStartTime
                };
            })
            .catch((error) => {
                debugger;

                if(store[this.noun].lastRequest != null && requestStartTime < store[this.noun].lastRequest) {
                    console.log('STALE ERROR RESPONSE', 'this response is older than another response! ', requestStartTime, store[this.noun].lastRequest);
                    return;
                }

                store[this.noun] = {
                    data: [],
                    errors: error,
                    isFetching: false
                };
            });
    }

    delete(id) {
        console.log('rest adapter delete');
    }
}

class LocalStoreAdapter extends StoreAdapter {
    constructor(noun) {
        super();
        this.noun = noun;
        this.global_count = 0
        // store[this.noun] = {
        //     isFetching: false,
        //     data: [],
        //     errors: []
        // }

        localStorage.setItem(this.noun, JSON.stringify([]));
    }

    create(item) {
        console.log('creating ', this.noun);
        var currentItems = JSON.parse(localStorage.getItem(this.noun));
        var insertItem = Object.assign({}, item, {id: this.global_count++});
        currentItems.push(insertItem);
        localStorage.setItem(this.noun, JSON.stringify(currentItems));
        return insertItem;
    }

    update(item) {
        var currentItems = JSON.parse(localStorage.getItem(this.noun));
        var currentItem = currentItems.filter(function(i) { return item.id == i.id })[0];

        Object.assign(currentItem, {}, item);
        localStorage.setItem(this.noun, JSON.stringify(currentItems));

        return currentItem;
    }

    read_all() {
        return JSON.parse(localStorage.getItem(this.noun));
    }

    read(id) {
        console.log('reading ', this.noun, ' with id ', id);
        var currentItems = JSON.parse(localStorage.getItem(this.noun));
        var currentItem = currentItems.filter(function(item) { return item.id == id })[0];

        if(currentItem == null) throw new Error('Item with id ' + id + ' does not exist!');
        return currentItem;
    }

    delete(id) {
        console.log('delete');
        var currentItems = JSON.parse(localStorage.getItem(this.noun));
        var deleteItem = currentItems.filter(function(item) { return id == item.id })[0];
        currentItems.splice(currentItems.indexOf(deleteItem), 1);
        localStorage.setItem(this.noun, JSON.stringify(currentItems));

        return currentItems;
    }
}

store.adapter = new LocalStoreAdapter('articles');

store.setFakeApi = function(useFakeApi) {
    if(useFakeApi) {
        console.log('setting api to localstoreadapter');
        store.adapter = new LocalStoreAdapter('articles');
        store.isFakeApi = true;
    } else {
        console.log('setting api to restapistoreadapter');
        store.adapter = new RestApiStoreAdapter('articles', 'http://localhost:3001/api');
        store.isFakeApi = false;
    }
    store.articles = {
        data: [],
        isFetching: false
    };
}

store.get = function(noun) {
    console.log(store[noun].data);
    // if(store[noun] == undefined || store[noun].data == null || store[noun].data == undefined || !Array.isArray(store[noun].data)) {
    //     store[noun].data = [];
    //     //     data: [],
    //     //     isFetching: false,
    //     //     errors: [],
    //     //     lastRequest: null
    //     // }
    // }

    return store[noun];
};

store.create = function(noun, item) {
    store.adapter.create(item);
    store[noun].data = store.adapter.read_all();
};

store.update = function(noun, item) {
    store.adapter.update(item);
    store[noun].data = store.adapter.read_all();
};

store.read_all = function(noun) {
    store.adapter.read_all();
}

store.delete = function(noun, id) {
    store.adapter.delete(id);
    store[noun].data = store.adapter.read_all();
};

store.read = function(noun, id) {
    store.adapter.read(id);
    store[noun].data = store.adapter.read_all();
};

store.apiRequest = function(noun, url, successFn=null, errorFn=null) {
    var namespace = noun;

    if(store[namespace] == undefined || store[namespace] == null) {
       store[namespace] = {
           data: [],
           isFetching: true,
           errors: [],
           lastRequest: null
       };
    } else {
        store[namespace].isFetching = true;
    }

    console.log('Fetching: ', url);
    const requestStartTime = (new Date()).getTime();
    fetch(url)
        .then(response => response.json())
        .then(json => {
            if(requestStartTime < store[namespace].lastRequest) {
                console.log('STALE SUCCESS RESPONSE', 'this response is older than another response! ', requestStartTime, store[namespace].lastRequest);
                return;
            }
            console.log('success: ', json);

            if(json.error != null || json.error != undefined) {
                throw new Error('Not Found');
            }

            if(successFn != null) {
                store[namespace].data = successFn(json);
            } else {
                store[namespace].data = json;
            }

            store[namespace].errors = [];
            store[namespace].isFetching = false;
            store[namespace].lastRequest = requestStartTime;
        })
        .catch((error) => {
            if(requestStartTime < store[namespace].lastRequest) {
                console.log('STALE ERROR RESPONSE', 'this response is older than another response! ', requestStartTime, store[namespace].lastRequest);
                return;
            }
            console.log('error: ', error);

            if(errorFn != null) {
                store[namespace].errors = errorFn(error);
            } else {
                store[namespace].errors = error;
            }
            store[namespace].data = [];
            store[namespace].isFetching = false;
        });
};

export default store;<commit_msg>fixing post<commit_after>import {observable} from 'mobservable';

const store = observable({
    articles: {
        data: [],
        isFetching: false,
        errors: [],
        lastRequest: null
    },
    isFakeApi: true
});

class StoreAdapter {
    constructor() {
        if(this.create === undefined) { throw new TypeError('Must override create method'); }
        if(this.update === undefined) { throw new TypeError('Must override update method'); }
        if(this.read === undefined) { throw new TypeError('Must override read method'); }
        if(this.read_all === undefined) { throw new TypeError('Must override read method'); }
        if(this.delete === undefined) { throw new TypeError('Must override delete method'); }
    }
}

class RestApiStoreAdapter extends StoreAdapter {
    constructor(noun, url) {
        super();
        this.noun = noun;
        this.url = url;
    }

    create(item) {
        console.log('rest adapter create');
        const requestStartTime = (new Date()).getTime();
        this.post(requestStartTime, item);
    }

    update(item) {
        console.log('rest adapter update');

    }

    read(id) {
        console.log('rest adapter read');
    }

    read_all() {
        console.log('rest adapter read all');
        if(store[this.noun] == undefined || store[this.noun] == null) {
            store[this.noun] = Object.assign({}, store[this.noun], {
                data: [],
                isFetching: true,
                errors: [],
                lastRequest: null
            });
        } else {
            store[this.noun] = Object.assign({}, store[this.noun], {
                isFetching: true,
                lastRequest: null
            });
            // debugger;
            // if(store[this.noun].data == undefined) {
            //     store[this.noun].data = []
            // }
        }

        console.log('Fetching: ', this.url);
        const requestStartTime = (new Date()).getTime();
        this.get(requestStartTime);
    }

    post(requestStartTime, item) {
        var headers = new Headers({"Content-type": "application/json"});
        const self = this;
        fetch(this.url + '/' + this.noun,
        {
            mode: 'cors',
            method: "POST",
            headers: headers,
            body: JSON.stringify({ article: item })
        }).then(response => response.json())
        .then(json => {
            self.read_all();
        })
        .catch((error) => {
            debugger;

            if(store[this.noun].lastRequest != null && requestStartTime < store[this.noun].lastRequest) {
                console.log('STALE ERROR RESPONSE', 'this response is older than another response! ', requestStartTime, store[this.noun].lastRequest);
                return;
            }

            // do something else
        });
    }

    put(requestStartTime, item) {

    }

    delete(requestStartTime, id) {

    }

    get(requestStartTime) {
        fetch(this.url + '/' + this.noun + '.json')
            .then(response => response.json())
            .then(json => {
                if(store[this.noun].lastRequest != null && requestStartTime < store[this.noun].lastRequest) {
                    console.log('STALE SUCCESS RESPONSE', 'this response is older than another response! ', requestStartTime, store[this.noun].lastRequest);
                    return;
                }
                console.log('success: ', json[this.noun]);

                if(json.error != null || json.error != undefined) {
                    throw new Error('Not Found');
                }

                store[this.noun] = {
                    data: json[this.noun],
                    errors: [],
                    isFetching: false,
                    lastRequest: requestStartTime
                };
            })
            .catch((error) => {
                debugger;

                if(store[this.noun].lastRequest != null && requestStartTime < store[this.noun].lastRequest) {
                    console.log('STALE ERROR RESPONSE', 'this response is older than another response! ', requestStartTime, store[this.noun].lastRequest);
                    return;
                }

                store[this.noun] = {
                    data: [],
                    errors: error,
                    isFetching: false
                };
            });
    }

    delete(id) {
        console.log('rest adapter delete');
    }
}

class LocalStoreAdapter extends StoreAdapter {
    constructor(noun) {
        super();
        this.noun = noun;
        this.global_count = 0
        // store[this.noun] = {
        //     isFetching: false,
        //     data: [],
        //     errors: []
        // }

        localStorage.setItem(this.noun, JSON.stringify([]));
    }

    create(item) {
        console.log('creating ', this.noun);
        var currentItems = JSON.parse(localStorage.getItem(this.noun));
        var insertItem = Object.assign({}, item, {id: this.global_count++});
        currentItems.push(insertItem);
        localStorage.setItem(this.noun, JSON.stringify(currentItems));
        return insertItem;
    }

    update(item) {
        var currentItems = JSON.parse(localStorage.getItem(this.noun));
        var currentItem = currentItems.filter(function(i) { return item.id == i.id })[0];

        Object.assign(currentItem, {}, item);
        localStorage.setItem(this.noun, JSON.stringify(currentItems));

        return currentItem;
    }

    read_all() {
        return JSON.parse(localStorage.getItem(this.noun));
    }

    read(id) {
        console.log('reading ', this.noun, ' with id ', id);
        var currentItems = JSON.parse(localStorage.getItem(this.noun));
        var currentItem = currentItems.filter(function(item) { return item.id == id })[0];

        if(currentItem == null) throw new Error('Item with id ' + id + ' does not exist!');
        return currentItem;
    }

    delete(id) {
        console.log('delete');
        var currentItems = JSON.parse(localStorage.getItem(this.noun));
        var deleteItem = currentItems.filter(function(item) { return id == item.id })[0];
        currentItems.splice(currentItems.indexOf(deleteItem), 1);
        localStorage.setItem(this.noun, JSON.stringify(currentItems));

        return currentItems;
    }
}

store.adapter = new LocalStoreAdapter('articles');

store.setFakeApi = function(useFakeApi) {
    if(useFakeApi) {
        console.log('setting api to localstoreadapter');
        store.adapter = new LocalStoreAdapter('articles');
        store.isFakeApi = true;
    } else {
        console.log('setting api to restapistoreadapter');
        store.adapter = new RestApiStoreAdapter('articles', 'http://localhost:3001/api');
        store.isFakeApi = false;
    }
    store.articles = {
        data: [],
        isFetching: false
    };
}

store.get = function(noun) {
    console.log(store[noun].data);
    // if(store[noun] == undefined || store[noun].data == null || store[noun].data == undefined || !Array.isArray(store[noun].data)) {
    //     store[noun].data = [];
    //     //     data: [],
    //     //     isFetching: false,
    //     //     errors: [],
    //     //     lastRequest: null
    //     // }
    // }

    return store[noun];
};

store.create = function(noun, item) {
    store.adapter.create(item);
    store[noun].data = store.adapter.read_all();
};

store.update = function(noun, item) {
    store.adapter.update(item);
    store[noun].data = store.adapter.read_all();
};

store.read_all = function(noun) {
    store.adapter.read_all();
}

store.delete = function(noun, id) {
    store.adapter.delete(id);
    store[noun].data = store.adapter.read_all();
};

store.read = function(noun, id) {
    store.adapter.read(id);
    store[noun].data = store.adapter.read_all();
};

store.apiRequest = function(noun, url, successFn=null, errorFn=null) {
    var namespace = noun;

    if(store[namespace] == undefined || store[namespace] == null) {
       store[namespace] = {
           data: [],
           isFetching: true,
           errors: [],
           lastRequest: null
       };
    } else {
        store[namespace].isFetching = true;
    }

    console.log('Fetching: ', url);
    const requestStartTime = (new Date()).getTime();
    fetch(url)
        .then(response => response.json())
        .then(json => {
            if(requestStartTime < store[namespace].lastRequest) {
                console.log('STALE SUCCESS RESPONSE', 'this response is older than another response! ', requestStartTime, store[namespace].lastRequest);
                return;
            }
            console.log('success: ', json);

            if(json.error != null || json.error != undefined) {
                throw new Error('Not Found');
            }

            if(successFn != null) {
                store[namespace].data = successFn(json);
            } else {
                store[namespace].data = json;
            }

            store[namespace].errors = [];
            store[namespace].isFetching = false;
            store[namespace].lastRequest = requestStartTime;
        })
        .catch((error) => {
            if(requestStartTime < store[namespace].lastRequest) {
                console.log('STALE ERROR RESPONSE', 'this response is older than another response! ', requestStartTime, store[namespace].lastRequest);
                return;
            }
            console.log('error: ', error);

            if(errorFn != null) {
                store[namespace].errors = errorFn(error);
            } else {
                store[namespace].errors = error;
            }
            store[namespace].data = [];
            store[namespace].isFetching = false;
        });
};

export default store;<|endoftext|>


<commit_before>/**
 * @file A simple module for creating desktop notifications on race
 * invitations.
 * @author Daniil Filippov <filippovdaniil@gmail.com>
 */
function RaceInvitations () {
    this._init();
    var defaultSettings = {
        notifyRaceInvitations: true,
    };
    this._storageId = 'race_invitations_settings';
    this._settings = kango.storage.getItem(this._storageId) || defaultSettings;
}

// Adding the teardown() and addMessageListener() methods to the prototype:
RaceInvitations.prototype.__proto__ = MutableModule.prototype;

/**
 * Returns a hash object with module settings.
 * @returns {Object}
 */
RaceInvitations.prototype.getParams = function () {
    return this._settings;
};

/**
 * Saves new settings to LocalStorage.
 * @param {Object} params A hash object with changed settings
 */
RaceInvitations.prototype.setParams = function (params) {
    for (var setting in params) {
        this._settings[setting] = params[setting];
    }

    kango.storage.setItem(this._storageId, this._settings);
};

/**
 * Creates a race notification.
 * @param {Object} game A hash object with game data.
 * @private
 */
RaceInvitations.prototype._createNotification = function (game) {
    var icon = game.invited_by.avatar.replace('.gif', '_big.gif');
    var body = game.invited_by.login + ' приглашает вас в ' +
        (game.type === 'private' ? 'игру с друзьями' : 'игру') +
        ' ' + game.gametype_html.replace(/<(?:.|\n)*?>/gm, '');

    var notification = new Notification('Приглашение в игру', {
        body: body,
        icon: icon,
        tag: 'raceInvite' + game.game_id,
    });

    notification.onclick = function () {
        var raceUrl = 'http://klavogonki.ru/g/?gmid=' + game.game_id;
        kango.browser.tabs.getCurrent(function (tab) {
            // Using private _tab property check because kango .getUrl() method is awful:
            if (!tab._tab || tab.getUrl().search(/klavogonki.ru\/g\/\?gmid/) === -1) {
                kango.browser.tabs.create({ url: raceUrl });
            } else {
                // We are at the race page — navigate to the new one:
                tab.navigate(raceUrl);
            }
        });
        notification.close();
    };
};

/**
 * Processes a race invitation.
 * @param {Object} game A hash object with game data.
 * @throws TypeError
 * @private
 */
RaceInvitations.prototype._processInvite = function (game) {
    if (!this._settings.notifyRaceInvitations) {
        return false;
    }

    if (!game || !game.invited_by || !game.gametype_html ||
        !game.invited_by.avatar || !game.game_id) {
        throw new TypeError('Wrong data for the _processInvite method');
    }

    kango.browser.tabs.getAll(function (tabs) {
        var re = new RegExp('klavogonki.ru/g/\\?gmid=' + game.game_id + '$');
        // Check if there is already opened tab with this URL:
        var found = tabs.some(function (tab) {
            return tab._tab && tab.getUrl().search(re) !== -1
        });

        if (!found) {
            this._createNotification(game);
        }
    }.bind(this));
};

/**
 * Sets a handler for AuthStateChanged events and listens for race invites.
 * @listens Auth#AuthStateChanged
 * @listens Socket#SocketConnected
 * @fires SocketSubscribe
 * @listens Socket#gameInvite:{userId}
 * @private
 */
RaceInvitations.prototype._init = function () {
    this.addMessageListener('AuthStateChanged', function (event) {
        var authId = event.data.id;
        if (authId) {
            this.setMessageListener('SocketConnected', function (event) {
                var subscriber = {};
                subscriber['gameInvite:' + authId] =
                    this._processInvite.bind(this);
                event.target.dispatchMessage('SocketSubscribe', subscriber);
            }.bind(this));
        }
    }.bind(this));
};
<commit_msg>(f) Fixed a quotes issue with race invitations<commit_after>/**
 * @file A simple module for creating desktop notifications on race
 * invitations.
 * @author Daniil Filippov <filippovdaniil@gmail.com>
 */
function RaceInvitations () {
    this._init();
    var defaultSettings = {
        notifyRaceInvitations: true,
    };
    this._storageId = 'race_invitations_settings';
    this._settings = kango.storage.getItem(this._storageId) || defaultSettings;
}

// Adding the teardown() and addMessageListener() methods to the prototype:
RaceInvitations.prototype.__proto__ = MutableModule.prototype;

/**
 * Returns a hash object with module settings.
 * @returns {Object}
 */
RaceInvitations.prototype.getParams = function () {
    return this._settings;
};

/**
 * Saves new settings to LocalStorage.
 * @param {Object} params A hash object with changed settings
 */
RaceInvitations.prototype.setParams = function (params) {
    for (var setting in params) {
        this._settings[setting] = params[setting];
    }

    kango.storage.setItem(this._storageId, this._settings);
};

/**
 * Creates a race notification.
 * @param {Object} game A hash object with game data.
 * @private
 */
RaceInvitations.prototype._createNotification = function (game) {
    var icon = game.invited_by.avatar.replace('.gif', '_big.gif');
    var body = game.invited_by.login + ' приглашает вас в ' +
        (game.type === 'private' ? 'игру с друзьями' : 'игру') +
        ' ' + game.gametype_html.replace(/<(?:.|\n)*?>/gm, '')
                .replace(/«/g, '«')
                .replace(/»/g, '»');

    var notification = new Notification('Приглашение в игру', {
        body: body,
        icon: icon,
        tag: 'raceInvite' + game.game_id,
    });

    notification.onclick = function () {
        var raceUrl = 'http://klavogonki.ru/g/?gmid=' + game.game_id;
        kango.browser.tabs.getCurrent(function (tab) {
            // Using private _tab property check because kango .getUrl() method is awful:
            if (!tab._tab || tab.getUrl().search(/klavogonki.ru\/g\/\?gmid/) === -1) {
                kango.browser.tabs.create({ url: raceUrl });
            } else {
                // We are at the race page — navigate to the new one:
                tab.navigate(raceUrl);
            }
        });
        notification.close();
    };
};

/**
 * Processes a race invitation.
 * @param {Object} game A hash object with game data.
 * @throws TypeError
 * @private
 */
RaceInvitations.prototype._processInvite = function (game) {
    if (!this._settings.notifyRaceInvitations) {
        return false;
    }

    if (!game || !game.invited_by || !game.gametype_html ||
        !game.invited_by.avatar || !game.game_id) {
        throw new TypeError('Wrong data for the _processInvite method');
    }

    kango.browser.tabs.getAll(function (tabs) {
        var re = new RegExp('klavogonki.ru/g/\\?gmid=' + game.game_id + '$');
        // Check if there is already opened tab with this URL:
        var found = tabs.some(function (tab) {
            return tab._tab && tab.getUrl().search(re) !== -1
        });

        if (!found) {
            this._createNotification(game);
        }
    }.bind(this));
};

/**
 * Sets a handler for AuthStateChanged events and listens for race invites.
 * @listens Auth#AuthStateChanged
 * @listens Socket#SocketConnected
 * @fires SocketSubscribe
 * @listens Socket#gameInvite:{userId}
 * @private
 */
RaceInvitations.prototype._init = function () {
    this.addMessageListener('AuthStateChanged', function (event) {
        var authId = event.data.id;
        if (authId) {
            this.setMessageListener('SocketConnected', function (event) {
                var subscriber = {};
                subscriber['gameInvite:' + authId] =
                    this._processInvite.bind(this);
                event.target.dispatchMessage('SocketSubscribe', subscriber);
            }.bind(this));
        }
    }.bind(this));
};
<|endoftext|>


<commit_before>// AJAX Plugin
// Docs Here:
// http://jquery.com/docs/ajax/

if ( typeof XMLHttpRequest == 'undefined' && typeof window.ActiveXObject == 'function') {
	var XMLHttpRequest = function() {
		return new ActiveXObject((navigator.userAgent.toLowerCase().indexOf('msie 5') >= 0) ?
			"Microsoft.XMLHTTP" : "Msxml2.XMLHTTP");
	};
}

$.xml = function( type, url, data, ret ) {
	var xml = new XMLHttpRequest();

	if ( xml ) {
		xml.open(type || "GET", url, true);

		if ( data )
			xml.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

		xml.onreadystatechange = function() {
			if ( xml.readyState == 4 ) {
				if ( ret ) ret(xml);
				$.triggerAJAX( $.httpData(xml) );
			}
		};

		xml.send(data)
	}
};

$.httpData = function(r,type) {
	return r.getResponseHeader("content-type").indexOf("xml") > 0 || type == "xml" ?
		r.responseXML : r.responseText;
};

$.get = function( url, ret, type ) {
	$.xml( "GET", url, null, function(r) {
		if ( ret ) ret( $.httpData(r,type) );
	});
};

$.getXML = function( url, ret ) {
	$.get( url, ret, "xml" );
};

$.post = function( url, data, ret, type ) {
	$.xml( "POST", url, $.param(data), function(r) {
		if ( ret ) ret( $.httpData(r,type) );
	});
};

$.postXML = function( url, data, ret ) {
	$.post( url, data, ret, "xml" );
};

// Global AJAX Event Binding
// Requested here:
// http://jquery.com/discuss/2006-March/000415/

$.fn.handleAJAX = function( callback ) {
	$.ajaxHandles = $.merge( $.ajaxHandles, this.cur );
	return this.bind( 'ajax', callback );
};

$.ajaxHandles = [];
$.triggerAJAX = function(data){
	for ( var i = 0; i < $.ajaxHandles.length; i++ )
		triggerEvent( $.ajaxHandles[i], 'ajax', [data] );
};

// Dynamic Form Submission
// Based upon the mailing list post at:
// http://jquery.com/discuss/2006-March/000424/

$.fn.serialize = function(callback) {
	return this.each(function(){
		var a = {};
		$(this)
			.find("input:checked,hidden,text,option[@selected],textarea")
			.filter(":enabled").each(function() {
				a[ this.name || this.id || this.parentNode.name || this.parentNode.id ] = this.value;
			});
		$.xml( this.method || "GET", this.action || "", $.param(a), callback );
	});
};

$.param = function(a) {
	var s = [];
	for ( var i in a )
	s[s.length] = i + "=" + encodeURIComponent( a[i] );
	return s.join("&");
};

$.fn.load = function(a,o,f) {
	// Arrrrghhhhhhhh!!
	// I overwrote the event plugin's .load
	// this won't happen again, I hope -John
	if ( a && a.constructor == Function )
		return this.bind("load", a);

	var t = "GET";
	if ( o && o.constructor == Function ) {
		f = o;
		o = null;
	}
	if (o != null) {
		o = $.param(o);
		t = "POST";
	}
	var self = this;
	$.xml(t,a,o,function(h){
		var h = h.responseText;
		self.html(h).find("script").each(function(){
			try {
				eval( this.text || this.textContent || this.innerHTML );
			} catch(e){}
		});
		if(f)f(h);
	});
	return this;
};
<commit_msg>Added my bugfixes and removed the triggerAjax and handleAjax functions since they are no longer needed afaik :)<commit_after>// AJAX Plugin
// Docs Here:
// http://jquery.com/docs/ajax/

if ( typeof XMLHttpRequest == 'undefined' && typeof window.ActiveXObject == 'function') {
	var XMLHttpRequest = function() {
		return new ActiveXObject((navigator.userAgent.toLowerCase().indexOf('msie 5') >= 0) ?
			"Microsoft.XMLHTTP" : "Msxml2.XMLHTTP");
	};
}

//
// Counter for holding the active query's
$.xmlActive=0;

$.xml = function( type, url, data, ret ) {
	var xml = new XMLHttpRequest();

	if ( xml ) {
		//
		// Increase the query counter
		$.xmlActive++;

		//
		// Show loader if needed
		if ($.xmlCreate)
			$.xmlCreate();

		//
		// Open the socket
		xml.open(type || "GET", url, true);

		if ( data )
			xml.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

		//
		// Set header so calling script knows that it's an XMLHttpRequest
		xml.setRequestHeader('X-Requested-With', 'XMLHttpRequest');

		/* Force "Connection: close" for Mozilla browsers to work around
		 * a bug where XMLHttpReqeuest sends an incorrect Content-length
		 * header. See Mozilla Bugzilla #246651.
		 */
		if ( xml.overrideMimeType )
			xml.setRequestHeader('Connection', 'close');

		xml.onreadystatechange = function() {
			if ( xml.readyState == 4 ) {
				if ( ret ) ret(xml);

				//
				// Decrease counter
				$.xmlActive--;

				//
				// Hide loader if needed
				if ($.xmlActive <= 0) {
					if ($.xmlDestroy)
						$.xmlDestroy();
				}
			}
		};

		xml.send(data)
	}
};

$.httpData = function(r,type) {
	return r.getResponseHeader("content-type").indexOf("xml") > 0 || type == "xml" ?
		r.responseXML : r.responseText;
};

$.get = function( url, ret, type ) {
	$.xml( "GET", url, null, function(r) {
		if ( ret ) ret( $.httpData(r,type) );
	});
};

$.getXML = function( url, ret ) {
	$.get( url, ret, "xml" );
};

$.post = function( url, data, ret, type ) {
	$.xml( "POST", url, $.param(data), function(r) {
		if ( ret ) ret( $.httpData(r,type) );
	});
};

$.postXML = function( url, data, ret ) {
	$.post( url, data, ret, "xml" );
};

// Dynamic Form Submission
// Based upon the mailing list post at:
// http://jquery.com/discuss/2006-March/000424/

$.fn.serialize = function(callback) {
	return this.each(function(){
		var a = {};
		$(this)
			.find("input:checked,hidden,text,option[@selected],textarea")
			.filter(":enabled").each(function() {
				a[ this.name || this.id || this.parentNode.name || this.parentNode.id ] = this.value;
			});
		$.xml( this.method || "GET", this.action || "", $.param(a), callback );
	});
};

$.param = function(a) {
	var s = [];
	if (a && typeof a == 'object' && a.constructor == Array) {
		for ( var i=0; i < a.length; i++ )
			s[s.length] = a[i]['name'] + "=" + encodeURIComponent( a[i]['value'] );
	} else {
		for ( var i in a )
			s[s.length] = i + "=" + encodeURIComponent( a[i] );
	}
	return s.join("&");
};

$.fn.load = function(a,o,f) {
	// Arrrrghhhhhhhh!!
	// I overwrote the event plugin's .load
	// this won't happen again, I hope -John
	if ( a && a.constructor == Function )
		return this.bind("load", a);

	var t = "GET";
	if ( o && o.constructor == Function ) {
		f = o;
		o = null;
	}
	if (o != null) {
		o = $.param(o);
		t = "POST";
	}
	var self = this;
	$.xml(t,a,o,function(h){
		var h = h.responseText;
		self.html(h).find("script").each(function(){
			try {
				eval( this.text || this.textContent || this.innerHTML );
			} catch(e){}
		});
		if(f)f(h);
	});
	return this;
};

/**
 * function:	$.fn.formValues
 * usage: 		$('#frmLogin').formValues()
 * docs:			Gets the form values and creates a key=>value array of the found values (only for ENABLED elements!)
 */
$.fn.formValues = function() {
	var a = new Array();
	this.find("input[@type='submit'],input[@type='hidden'],textarea,input[@checked],input[@type='password'],input[@type='text'],option[@selected]")
		.filter(":enabled").each(function() {
			o = {};
			o['name'] = this.name || this.id || this.parentNode.name || this.parentNode.id;
			o['value'] = this.value;
			a.push(o);
		});
	return a;
};

/**
 * function:	$.update
 * usage:		$.update('someJQueryObject', 'someurl', 'array');
 * docs:			Mimics the ajaxUpdater from prototype. Posts the key=>value array to the url and
 *					puts the results from that call in the jQuery object specified.
 *					--> If you set the blnNoEval to true, the script tags are NOT evaluated.
 */
$.update = function(objElement, strURL, arrValues, fncCallback) {
	$.post(strURL, arrValues, function(strHTML) {
		//
		// Update the element with the new HTML
		objElement.html(strHTML);

		//
		// Evaluate the scripts
		objElement.html(strHTML).find("script").each(function(){
			try { eval( this.text || this.textContent || this.innerHTML ); } catch(e){}
		});

		//
		// Callback handler
		if (fncCallback) fncCallback();
	});
};
<|endoftext|>


<commit_before>/* -*- mode: javascript; tab-width: 4; insert-tabs-mode: nil; indent-tabs-mode: nil -*- */

var slice = [].slice;
var pow = Math.pow;
var fromCharCode = String.fromCharCode;
var max = Math.max;
var splice = [].splice;
var isArray = Array.isArray;
var keys = Object.keys;
var push = [].push;
var defineProperty = Object.defineProperty;
var create = Object.create;

function fail(msg, context) {
  throw new Error((context ? context + ': ' : '') + msg);
}
function assert(cond, msg, context) {
  if (!cond)
    fail(msg, context);
}
<commit_msg>add min to utils<commit_after>/* -*- mode: javascript; tab-width: 4; insert-tabs-mode: nil; indent-tabs-mode: nil -*- */

var slice = [].slice;
var pow = Math.pow;
var fromCharCode = String.fromCharCode;
var min = Math.min;
var max = Math.max;
var splice = [].splice;
var isArray = Array.isArray;
var keys = Object.keys;
var push = [].push;
var defineProperty = Object.defineProperty;
var create = Object.create;

function fail(msg, context) {
  throw new Error((context ? context + ': ' : '') + msg);
}
function assert(cond, msg, context) {
  if (!cond)
    fail(msg, context);
}
<|endoftext|>


<commit_before>var fetch = require('node-fetch');
var request = require('request');

var types = ["shirt", "jacket", "pants", "shoes"];
var occassions = ["casual", "business", "summer", "winter", "sport"];
var colors = ["black", "white", "grey", "gray", "red", "orange", "yellow", "green", "blue", "violet", "pink", "purple", "brown"];
var styles = [["button", "v-neck", "fullsleeve", "t-shirt"],
        ["flannel", "windbreaker", "sports", "hoodie"],
        ["jeans", "slacks", "shorts", "khaki", "sweatpant"],
        ["tennis", "flat", "skate", "fashion"]];
var fabrics = ["cotton", "denim", "leather", "nylon", "polyster"];
var input = {"type": 'shirt',
            "occassion": 'casual',
            "color": 'black',
            "style": 't-shirt',
            "fabrics": 'cotton'};

var shirtInput = true;
//var inputAsList = goodShirts();

//var matches = allMatches();

readMongo();

function readMongo() {
  var myHeaders = new fetch.Headers();

  var myInit = { method: 'GET', headers: myHeaders, };

  fetch('http://localhost:5000/shirts', myInit).then(function(response) {
    //console.log(response.body);
    console.log(request)
  });
}

function goodShirts() {
  if (input["type"] === "shirt") return [input];
  shirtInput = false;
  ret = [];
  for (i = 0; i < shirts.length; i++) {
    if (checker(shirts[i], input)) ret.append(shirts[i])
  }
  return ret;
}

function allMatches() {
  ret = [];
  for (i = 0; i < types.length; i++) {
    curr = [];
    if (input["type"] === types[i] || (!shirtInput && types[i] === "shirt")) curr = inputAsList;
    else {
      for (k = 0; k < wardrobe[i].length; i++) {
        for (z = 0; z < inputAsList.length; z++) {
          if (checker(inputAsList[z], wardrobe[i, k])) {
            curr.append(wardrobe[i, k]);
            break;
          }
        }
      }
    }
    ret.append(curr);
  }
  return ret;
}

function checker(shirt, other) {
  return occasionChecker(shirt, other) && colorChecker(shirt, other) &&
    styleChecker(shirt, other) && fabricChecker(shirt, other);
}

function occasionChecker(shirt, other) {
  return shirt["occassion"] == other["occassion"];
}

function colorChecker(shirt, other) {
  var index = 1 ? (["black", "white", "grey", "gray"].indexOf(shirt["color"]) != -1) :
  (2 ? ["yellow", "brown"].indexOf(shirt["color"]) : 3);

  var dict = {1: [],
  2: ["red", "orange", "green", "blue", "violet", "pink", "purple"],
  3: ["red", "orange", "green", "blue", "violet", "pink", "purple"]};

  return dict[index].indexOf(other['colors']) == -1;
}

function styleChecker(shirt, other) {
  var dict = {'t-shirt': ['slacks'],
              'fullsleeve': ['flannel', 'slacks'],
              'v-neck': ['flannel', 'slacks', 'sports'],
              'button': ['flannel', 'hoodie', 'sports', 'sweatpant', 'tennis']};
  return dict[shirt["style"]].indexOf(other["style"]) == -1;

}

function fabricChecker(shirt, other) {
  var dict = { 'cotton': ['leather'],
  'denim':['cotton', 'leather', 'denim', 'nylon', 'polyster'],
  'leather': ['cotton', 'leather', 'denim', 'nylon', 'polyster'],
  'nylon': ['cotton', 'denim', 'leather'],
  'polyster': ['cotton', 'denim', 'leather']};
  return dict[shirt['fabrics']].indexOf(other["fabrics"]) == -1;

}
<commit_msg>hopefully the end<commit_after>var fetch = require('node-fetch');
var request = require('request');

var types = ["shirt", "jacket", "pants", "shoes"];
var occassions = ["casual", "business", "summer", "winter", "sport"];
var colors = ["black", "white", "grey", "gray", "red", "orange", "yellow", "green", "blue", "violet", "pink", "purple", "brown"];
var styles = [["button", "v-neck", "fullsleeve", "t-shirt"],
        ["flannel", "windbreaker", "sports", "hoodie"],
        ["jeans", "slacks", "shorts", "khaki", "sweatpant"],
        ["tennis", "flat", "skate", "fashion"]];
var fabrics = ["cotton", "denim", "leather", "nylon", "polyster"];
var input = {"type": 'shirt',
            "occassion": 'casual',
            "color": 'black',
            "style": 't-shirt',
            "fabrics": 'cotton'};

var shirtInput = true;
var inputAsList = goodShirts();

var matches = allMatches();

cp = Combinatorics.cartesianProduct(matches[0], matches[1], matches[2], matches[3]);
console.log(cp.toArray());

readMongo();

function readMongo() {
  var myHeaders = new fetch.Headers();

  var myInit = { method: 'GET', headers: myHeaders, };

  fetch('http://localhost:5000/shirts', myInit).then(function(response) {
    //console.log(response.body);
    console.log(request)
  });
}

function goodShirts() {
  if (input["type"] === "shirt") return [input];
  shirtInput = false;
  ret = [];
  for (i = 0; i < shirts.length; i++) {
    if (checker(shirts[i], input)) ret.append(shirts[i])
  }
  return ret;
}

function allMatches() {
  ret = [];
  for (i = 0; i < types.length; i++) {
    curr = [];
    if (input["type"] === types[i] || (!shirtInput && types[i] === "shirt")) curr = inputAsList;
    else {
      for (k = 0; k < wardrobe[i].length; i++) {
        for (z = 0; z < inputAsList.length; z++) {
          if (checker(inputAsList[z], wardrobe[i, k])) {
            curr.append(wardrobe[i, k]);
            break;
          }
        }
      }
    }
    ret.append(curr);
  }
  return ret;
}

function checker(shirt, other) {
  return occasionChecker(shirt, other) && colorChecker(shirt, other) &&
    styleChecker(shirt, other) && fabricChecker(shirt, other);
}

function occasionChecker(shirt, other) {
  return shirt["occassion"] == other["occassion"];
}

function colorChecker(shirt, other) {
  var index = 1 ? (["black", "white", "grey", "gray"].indexOf(shirt["color"]) != -1) :
  (2 ? ["yellow", "brown"].indexOf(shirt["color"]) : 3);

  var dict = {1: [],
  2: ["red", "orange", "green", "blue", "violet", "pink", "purple"],
  3: ["red", "orange", "green", "blue", "violet", "pink", "purple"]};

  return dict[index].indexOf(other['colors']) == -1;
}

function styleChecker(shirt, other) {
  var dict = {'t-shirt': ['slacks'],
              'fullsleeve': ['flannel', 'slacks'],
              'v-neck': ['flannel', 'slacks', 'sports'],
              'button': ['flannel', 'hoodie', 'sports', 'sweatpant', 'tennis']};
  return dict[shirt["style"]].indexOf(other["style"]) == -1;

}

function fabricChecker(shirt, other) {
  var dict = { 'cotton': ['leather'],
  'denim':[ 'leather', 'denim', 'nylon', 'polyster'],
  'leather': [ 'leather', 'denim', 'nylon', 'polyster'],
  'nylon': ['denim', 'leather'],
  'polyster': ['denim', 'leather']};
  return dict[shirt['fabrics']].indexOf(other["fabrics"]) == -1;

}
<|endoftext|>


<commit_before>import { vec3, quat } from 'gl-matrix';
import { quatToEuler, eulerToQuat } from 'webglue/lib/util/euler';
import * as bezier from '../util/bezier';
let tmpVec3 = vec3.create();
let tmpQuat = quat.create();
let useEuler = false;
let eulerData = null;

function createSetPosition(system, index) {
  return (entity, value) => {
    // Interpolate! Sort of.
    vec3.copy(tmpVec3, entity.transform.position);
    if (tmpVec3[index] === value) return;
    tmpVec3[index] = value;
    system.engine.actions.transform.setPosition(entity, tmpVec3);
  };
}

function createSetScale(system, index) {
  return (entity, value) => {
    // Interpolate! Sort of.
    vec3.copy(tmpVec3, entity.transform.scale);
    if (tmpVec3[index] === value) return;
    tmpVec3[index] = value;
    system.engine.actions.transform.setScale(entity, tmpVec3);
  };
}

function createSetRotation(system, index) {
  return (entity, value) => {
    quat.copy(tmpQuat, entity.transform.rotation);
    if (tmpQuat[index] === value) return;
    tmpQuat[index] = value;
    system.engine.actions.transform.setRotation(entity, tmpQuat);
  };
}

function createSetEulerRotation(system, index) {
  return (entity, value) => {
    // AnimationSystem will handle this :)
    useEuler = true;
    eulerData[index] = value;
  };
}

export default class AnimationSystem {
  constructor() {
    this.hooks = {
      'external.update!': () => {
        this.update();
      }
    };
    // Why can't we generalize it? Because COLLADA format requires
    // 'absolute' position for intangent / outtangent
    this.interpolators = {
      'bezier': (offset, channel, prevIndex, index) => {
        let x = channel.input[index];
        let y = channel.output[index];
        let xPrev = channel.input[prevIndex];
        let yPrev = channel.output[prevIndex];
        let xIn = channel.inTangent[index * 2];
        let yIn = channel.inTangent[index * 2 + 1];
        let xOut = channel.outTangent[prevIndex * 2];
        let yOut = channel.outTangent[prevIndex * 2 + 1];
        if (x === xPrev) return y;
        // Ugh...
        let time = offset;
        if (time < xPrev) return yPrev;
        if (time > x) return y;
        return bezier.YfromX(time, xPrev, yPrev, xOut, yOut, xIn, yIn, x, y);
      },
      'linear': (offset, channel, prevIndex, index) => {
        let input = channel.input[index];
        let prevInput = channel.input[prevIndex];
        let output = channel.output[index];
        let prevOutput = channel.output[prevIndex];
        if (prevInput === input) prevInput = input + 1;
        // INTERPOLATE!!!!
        let time = (offset - prevInput) / (input - prevInput);
        if (offset > input) time = 1;
        return prevOutput + (output - prevOutput) * time;
      }
    };
    this.channels = {
      'transform.position.x': createSetPosition(this, 0),
      'transform.position.y': createSetPosition(this, 1),
      'transform.position.z': createSetPosition(this, 2),
      'transform.scale.x': createSetScale(this, 0),
      'transform.scale.y': createSetScale(this, 1),
      'transform.scale.z': createSetScale(this, 2),
      'transform.rotation.x': createSetRotation(this, 0),
      'transform.rotation.y': createSetRotation(this, 1),
      'transform.rotation.z': createSetRotation(this, 2),
      'transform.rotation.w': createSetRotation(this, 3),
      'transform.rotation.eulerX': createSetEulerRotation(this, 0),
      'transform.rotation.eulerY': createSetEulerRotation(this, 1),
      'transform.rotation.eulerZ': createSetEulerRotation(this, 2),
    };
  }
  attach(engine) {
    this.engine = engine;
    this.family = engine.systems.family.get('animation');
  }
  update() {
    // Update all entities :(
    this.family.entities.forEach(entity => {
      let animation = entity.animation;
      if (animation == null || !animation.playing) return;
      let offset = this.engine.state.global.time - animation.start;
      let loops = offset / animation.duration;
      offset %= animation.duration;
      if (animation.repeat > 0 && loops >= animation.repeat) return;
      // Pre-handle Euler rotation
      // Why do we need this? Because the engine only uses quaternion,
      // we have to convert it to Euler degrees / and convert it back.
      // But doing it for each channel is just bad.
      useEuler = false;
      eulerData = [null, null, null];
      let handleChannel = channel => {
        // TODO Implement interpolator
        // Find first one that is bigger than current offset
        let index = channel.input.findIndex(v => v > offset);
        if (index === -1) index = channel.input.length - 1;
        let prevIndex = index - 1;
        if (prevIndex < 0) prevIndex = 0;
        let interpolator = this.interpolators[channel.interpolation[prevIndex]];
        if (interpolator == null) interpolator = this.interpolators.linear;
        this.channels[channel.channel](entity,
          interpolator(offset, channel, prevIndex, index));
      };
      // Update every channel....
      // If parent is available, use them. :)
      // (Actually parent is just a method to copy animation frames.)
      if (animation.parent) {
        let parentEntity = this.engine.state.entities[animation.parent];
        if (parentEntity != null && parentEntity.animation) {
          parentEntity.animation.channels.forEach(handleChannel);
        }
      }
      if (animation.channels != null) animation.channels.forEach(handleChannel);
      // Now, process the Euler degrees.
      if (useEuler) {
        quatToEuler(tmpVec3, entity.transform.rotation);
        vec3.scale(tmpVec3, tmpVec3, 180 / Math.PI);
        // Apply the set value.
        if (eulerData[0] != null) tmpVec3[0] = eulerData[0];
        if (eulerData[1] != null) tmpVec3[1] = eulerData[1];
        if (eulerData[2] != null) tmpVec3[2] = eulerData[2];
        // Revert it back
        vec3.scale(tmpVec3, tmpVec3, Math.PI / 180);
        eulerToQuat(tmpQuat, tmpVec3);
        this.engine.actions.transform.setRotation(entity, tmpQuat);
      }
    });
  }
}
<commit_msg>Add more interpolators<commit_after>import { vec3, quat } from 'gl-matrix';
import { quatToEuler, eulerToQuat } from 'webglue/lib/util/euler';
import * as bezier from '../util/bezier';
let tmpVec3 = vec3.create();
let tmpQuat = quat.create();
let useEuler = false;
let eulerData = null;

function createSetPosition(system, index) {
  return (entity, value) => {
    // Interpolate! Sort of.
    vec3.copy(tmpVec3, entity.transform.position);
    if (tmpVec3[index] === value) return;
    tmpVec3[index] = value;
    system.engine.actions.transform.setPosition(entity, tmpVec3);
  };
}

function createSetScale(system, index) {
  return (entity, value) => {
    // Interpolate! Sort of.
    vec3.copy(tmpVec3, entity.transform.scale);
    if (tmpVec3[index] === value) return;
    tmpVec3[index] = value;
    system.engine.actions.transform.setScale(entity, tmpVec3);
  };
}

function createSetRotation(system, index) {
  return (entity, value) => {
    quat.copy(tmpQuat, entity.transform.rotation);
    if (tmpQuat[index] === value) return;
    tmpQuat[index] = value;
    system.engine.actions.transform.setRotation(entity, tmpQuat);
  };
}

function createSetEulerRotation(system, index) {
  return (entity, value) => {
    // AnimationSystem will handle this :)
    useEuler = true;
    eulerData[index] = value;
  };
}

function createInterpolator(getTime) {
  return (offset, channel, prevIndex, index) => {
    let input = channel.input[index];
    let prevInput = channel.input[prevIndex];
    let output = channel.output[index];
    let prevOutput = channel.output[prevIndex];
    if (prevInput === input) prevInput = input + 1;
    // INTERPOLATE!!!!
    let time = (offset - prevInput) / (input - prevInput);
    if (offset > input) time = 1;
    time = getTime(time);
    return prevOutput + (output - prevOutput) * time;
  };
}

export default class AnimationSystem {
  constructor() {
    this.hooks = {
      'external.update!': () => {
        this.update();
      }
    };
    // Why can't we generalize it? Because COLLADA format requires
    // 'absolute' position for intangent / outtangent
    this.interpolators = {
      'bezier': (offset, channel, prevIndex, index) => {
        let x = channel.input[index];
        let y = channel.output[index];
        let xPrev = channel.input[prevIndex];
        let yPrev = channel.output[prevIndex];
        let xIn = channel.inTangent[index * 2];
        let yIn = channel.inTangent[index * 2 + 1];
        let xOut = channel.outTangent[prevIndex * 2];
        let yOut = channel.outTangent[prevIndex * 2 + 1];
        if (x === xPrev) return y;
        // Ugh...
        let time = offset;
        if (time < xPrev) return yPrev;
        if (time > x) return y;
        return bezier.YfromX(time, xPrev, yPrev, xOut, yOut, xIn, yIn, x, y);
      },
      'linear': createInterpolator(x => x),
      'easeIn': createInterpolator(t => t*t*t),
      'easeOut': createInterpolator(t => (--t)*t*t+1),
      'easeInOut': createInterpolator(t => (t < 0.5) ? 4*t*t*t :
        (t-1) * (2*t-2) * (2*t-2) + 1),
    };
    this.channels = {
      'transform.position.x': createSetPosition(this, 0),
      'transform.position.y': createSetPosition(this, 1),
      'transform.position.z': createSetPosition(this, 2),
      'transform.scale.x': createSetScale(this, 0),
      'transform.scale.y': createSetScale(this, 1),
      'transform.scale.z': createSetScale(this, 2),
      'transform.rotation.x': createSetRotation(this, 0),
      'transform.rotation.y': createSetRotation(this, 1),
      'transform.rotation.z': createSetRotation(this, 2),
      'transform.rotation.w': createSetRotation(this, 3),
      'transform.rotation.eulerX': createSetEulerRotation(this, 0),
      'transform.rotation.eulerY': createSetEulerRotation(this, 1),
      'transform.rotation.eulerZ': createSetEulerRotation(this, 2),
    };
  }
  attach(engine) {
    this.engine = engine;
    this.family = engine.systems.family.get('animation');
  }
  update() {
    // Update all entities :(
    this.family.entities.forEach(entity => {
      let animation = entity.animation;
      if (animation == null || !animation.playing) return;
      let offset = this.engine.state.global.time - animation.start;
      let loops = offset / animation.duration;
      offset %= animation.duration;
      if (animation.repeat > 0 && loops >= animation.repeat) return;
      // Pre-handle Euler rotation
      // Why do we need this? Because the engine only uses quaternion,
      // we have to convert it to Euler degrees / and convert it back.
      // But doing it for each channel is just bad.
      useEuler = false;
      eulerData = [null, null, null];
      let handleChannel = channel => {
        // TODO Implement interpolator
        // Find first one that is bigger than current offset
        let index = channel.input.findIndex(v => v > offset);
        if (index === -1) index = channel.input.length - 1;
        let prevIndex = index - 1;
        if (prevIndex < 0) prevIndex = 0;
        let interpolator;
        if (channel.interpolation != null) {
          if (Array.isArray(channel.interpolation)) {
            interpolator = this.interpolators[channel.interpolation[prevIndex]];
          } else {
            interpolator = this.interpolators[channel.interpolation];
          }
        }
        if (interpolator == null) interpolator = this.interpolators.linear;
        this.channels[channel.channel](entity,
          interpolator(offset, channel, prevIndex, index));
      };
      // Update every channel....
      // If parent is available, use them. :)
      // (Actually parent is just a method to copy animation frames.)
      if (animation.parent) {
        let parentEntity = this.engine.state.entities[animation.parent];
        if (parentEntity != null && parentEntity.animation) {
          parentEntity.animation.channels.forEach(handleChannel);
        }
      }
      if (animation.channels != null) animation.channels.forEach(handleChannel);
      // Now, process the Euler degrees.
      if (useEuler) {
        quatToEuler(tmpVec3, entity.transform.rotation);
        vec3.scale(tmpVec3, tmpVec3, 180 / Math.PI);
        // Apply the set value.
        if (eulerData[0] != null) tmpVec3[0] = eulerData[0];
        if (eulerData[1] != null) tmpVec3[1] = eulerData[1];
        if (eulerData[2] != null) tmpVec3[2] = eulerData[2];
        // Revert it back
        vec3.scale(tmpVec3, tmpVec3, Math.PI / 180);
        eulerToQuat(tmpQuat, tmpVec3);
        this.engine.actions.transform.setRotation(entity, tmpQuat);
      }
    });
  }
}
<|endoftext|>


<commit_before>var path = require('path');
var express = require('express');
var Sequelize = require('sequelize');
var bodyParser = require('body-parser');
var auth = require('http-auth');
var config = require('histograph-config');
var request = require('request');
var md5 = require('md5');

var app = express();
app.use(bodyParser.json());

var basic = auth.basic({
  realm: 'Flags',
  file: __dirname + '/.htpasswd',
});

var sequelize = new Sequelize('sqlite://database', {
  logging: false,
  storage: path.join(__dirname, 'database.sqlite'),
});

var Flag = sequelize.define('flag', {
  type: { type: Sequelize.STRING, allowNull: false },
  value: { type: Sequelize.STRING, allowNull: false },
  synced: { type: Sequelize.BOOLEAN, defaultValue: false },
  author: { type: Sequelize.STRING, allowNull: false },
});

var Concept = sequelize.define('concept', {
  id: { type: Sequelize.STRING, primaryKey: true },
  type: { type: Sequelize.STRING },
  name: { type: Sequelize.STRING },
  datasets: { type: Sequelize.STRING },
}, {
  setterMethods: {
    datasets: function (value) {
      this.setDataValue('datasets', value.join(','));
    },
  },
  getterMethods: {
    datasets: function () {
      return (this.getDataValue('datasets') || '').split(',');
    },
  },
});

var Origin = Flag.belongsTo(Concept, { as: 'origin' });
var Target = Flag.belongsTo(Concept, { as: 'target' });

sequelize.sync({ force: false }).then(function () {});

app.get('/flags', function (req, res) {
  var query = req.query;
  var params = {
    synced: false,
  };

  if (query.concept) {
    params.$or = [
      { originId: decodeURIComponent(query.concept) },
      { targetId: decodeURIComponent(query.concept) },
    ];
  }

  Flag.findAll({
    where: params,
    include: [Origin, Target],
    order: [['createdAt', 'DESC']],
  }).then(function (rows) {
    res.json(rows);
  });
});

app.delete('/flags', auth.connect(basic), function (req, res) {
  var query = req.query;
  var params = {};

  if (query.id) {
    params.id = query.id.split(',');
  }

  Flag.destroy({
    where: params,
  }).then(function () {
    res.status(204).send();
  });
});

app.get('/flags/relations.ndjson', auth.connect(basic), function (req, res) {
  Flag.findAll({
    include: [Origin, Target],
  }).then(function (rows) {
    res.send(rows.map(function (row) {
      var isWrongType = row.type === 'wrong-type';
      var from = isWrongType ? ('urn:hgid:z_corrections_/' + md5(row.createdAt)) : row.originId;
      var type = isWrongType ? 'tnl:same' : row.value;
      var to = isWrongType ? row.originId : row.targetId;

      return JSON.stringify({
        from: from,
        type: type,
        to: to,
      });
    }).join('\n'));
  });
});

app.get('/flags/pits.ndjson', auth.connect(basic), function (req, res) {
  Flag.findAll({
    where: {
      $or: [{ type: 'wrong-type' }],
    },
    include: [Origin, Target],
  }).then(function (rows) {
    res.send(rows.map(function (row) {
      return JSON.stringify({
        id: ('urn:hgid:z_corrections_/' + md5(row.createdAt)),
        type: row.value,
      });
    }).join('\n'));
  });
});

app.post('/flags', auth.connect(basic), function (req, res) {
  var data = req.body;
  var origin = data.concept;
  var type = data.type;
  var value = data.value.type;
  var target = data.value.concept;
  var user = req.user;

  Concept
    .findOrCreate({
      where: { id: origin.id },
      defaults: origin,
    })
    .then(function () {
      return Concept.findOrCreate({
        where: { id: target.id },
        defaults: target,
      });
    })
    .then(function () {
      return Flag.create({
        type: type,
        value: value,
        author: user,
        originId: origin.id,
        targetId: target.id,
      });
    })
    .then(function (flag) {
      return res.status(201).json(flag);
    });
});

app.put('/flags/:id/approve', auth.connect(basic), function (req, res) {
  Flag.find({
    where: {
      id: req.params.id,
    },
    include: [Origin, Target],
  }).then(function (row) {
    if (row) {
      var type = row.type === 'wrong-type' ? 'pits' : 'relations';
      var url = config.api.baseUrl + '/' + path.join('datasets', 'corrections', type);
      var data = {};

      if (type === 'pits') {
        data = {
          id: row.originId,
          type: row.value,
          _correction_id: md5(row.createdAt),
        };
      } else {
        data = {
          from: row.originId,
          type: row.value,
          to: row.targetId,
        };
      }

      request(url, {
        method: 'PUT',
        auth: {
          user: config.api.admin.name,
          pass: config.api.admin.password,
        },
        json: data,
      }, function (error, response, body) {
        if (error) {
          return res.status(500).send(error);
        }
        row.update({
          synced: true,
        }).then(function () {
          res.send(body);
        }).catch(function (err) {
          res.status(500).send(err);
        });
      });
    } else {
      res.status(404).send('Not found');
    }
  }).catch(function () {
    res.status(500).send('Error');
  });
});

module.exports = app;
<commit_msg>Remove pits namespacing<commit_after>var path = require('path');
var express = require('express');
var Sequelize = require('sequelize');
var bodyParser = require('body-parser');
var auth = require('http-auth');
var config = require('histograph-config');
var request = require('request');
var md5 = require('md5');

var app = express();
app.use(bodyParser.json());

var basic = auth.basic({
  realm: 'Flags',
  file: __dirname + '/.htpasswd',
});

var sequelize = new Sequelize('sqlite://database', {
  logging: false,
  storage: path.join(__dirname, 'database.sqlite'),
});

var Flag = sequelize.define('flag', {
  type: { type: Sequelize.STRING, allowNull: false },
  value: { type: Sequelize.STRING, allowNull: false },
  synced: { type: Sequelize.BOOLEAN, defaultValue: false },
  author: { type: Sequelize.STRING, allowNull: false },
});

var Concept = sequelize.define('concept', {
  id: { type: Sequelize.STRING, primaryKey: true },
  type: { type: Sequelize.STRING },
  name: { type: Sequelize.STRING },
  datasets: { type: Sequelize.STRING },
}, {
  setterMethods: {
    datasets: function (value) {
      this.setDataValue('datasets', value.join(','));
    },
  },
  getterMethods: {
    datasets: function () {
      return (this.getDataValue('datasets') || '').split(',');
    },
  },
});

var Origin = Flag.belongsTo(Concept, { as: 'origin' });
var Target = Flag.belongsTo(Concept, { as: 'target' });

sequelize.sync({ force: false }).then(function () {});

app.get('/flags', function (req, res) {
  var query = req.query;
  var params = {
    synced: false,
  };

  if (query.concept) {
    params.$or = [
      { originId: decodeURIComponent(query.concept) },
      { targetId: decodeURIComponent(query.concept) },
    ];
  }

  Flag.findAll({
    where: params,
    include: [Origin, Target],
    order: [['createdAt', 'DESC']],
  }).then(function (rows) {
    res.json(rows);
  });
});

app.delete('/flags', auth.connect(basic), function (req, res) {
  var query = req.query;
  var params = {};

  if (query.id) {
    params.id = query.id.split(',');
  }

  Flag.destroy({
    where: params,
  }).then(function () {
    res.status(204).send();
  });
});

app.get('/flags/relations.ndjson', auth.connect(basic), function (req, res) {
  Flag.findAll({
    include: [Origin, Target],
  }).then(function (rows) {
    res.send(rows.map(function (row) {
      var isWrongType = row.type === 'wrong-type';
      var from = isWrongType ? ('urn:hgid:z_corrections_/' + md5(row.createdAt)) : row.originId;
      var type = isWrongType ? 'tnl:same' : row.value;
      var to = isWrongType ? row.originId : row.targetId;

      return JSON.stringify({
        from: from,
        type: type,
        to: to,
      });
    }).join('\n'));
  });
});

app.get('/flags/pits.ndjson', auth.connect(basic), function (req, res) {
  Flag.findAll({
    where: {
      $or: [{ type: 'wrong-type' }],
    },
    include: [Origin, Target],
  }).then(function (rows) {
    res.send(rows.map(function (row) {
      return JSON.stringify({
        id: md5(row.createdAt),
        type: row.value,
      });
    }).join('\n'));
  });
});

app.post('/flags', auth.connect(basic), function (req, res) {
  var data = req.body;
  var origin = data.concept;
  var type = data.type;
  var value = data.value.type;
  var target = data.value.concept;
  var user = req.user;

  Concept
    .findOrCreate({
      where: { id: origin.id },
      defaults: origin,
    })
    .then(function () {
      return Concept.findOrCreate({
        where: { id: target.id },
        defaults: target,
      });
    })
    .then(function () {
      return Flag.create({
        type: type,
        value: value,
        author: user,
        originId: origin.id,
        targetId: target.id,
      });
    })
    .then(function (flag) {
      return res.status(201).json(flag);
    });
});

app.put('/flags/:id/approve', auth.connect(basic), function (req, res) {
  Flag.find({
    where: {
      id: req.params.id,
    },
    include: [Origin, Target],
  }).then(function (row) {
    if (row) {
      var type = row.type === 'wrong-type' ? 'pits' : 'relations';
      var url = config.api.baseUrl + '/' + path.join('datasets', 'corrections', type);
      var data = {};

      if (type === 'pits') {
        data = {
          id: row.originId,
          type: row.value,
          _correction_id: md5(row.createdAt),
        };
      } else {
        data = {
          from: row.originId,
          type: row.value,
          to: row.targetId,
        };
      }

      request(url, {
        method: 'PUT',
        auth: {
          user: config.api.admin.name,
          pass: config.api.admin.password,
        },
        json: data,
      }, function (error, response, body) {
        if (error) {
          return res.status(500).send(error);
        }
        row.update({
          synced: true,
        }).then(function () {
          res.send(body);
        }).catch(function (err) {
          res.status(500).send(err);
        });
      });
    } else {
      res.status(404).send('Not found');
    }
  }).catch(function () {
    res.status(500).send('Error');
  });
});

module.exports = app;
<|endoftext|>


<commit_before>wwt.app.factory(
  'Localization',
  [
    '$http',
    '$q',
    'Util',

    function($http, $q, util) {
      var api = {
	setLanguage: setLanguage,
	getString: getString,
	getFromEn: getFromEn,
	getAvailableLanguages: getAvailableLanguages
      };
      var langCode,
	  englishData,
	  englishArray,
	  locData,
	  locArray,
	  lpacks/*,
		  unlocalized = {}*/;
      function getString(id, s) {
	return locArray && locArray[id] ? locArray[id] : s ? s : '';
      }
      /*
	setInterval(function () {
	var rawArray = [];
	$.each(unlocalized, function(k, v) {
	rawArray.push(k);
	});
	util.log('unlocalized', rawArray);
	}, 11111);
	to trap unlocalized
	uncomment unlocalized in this file
	the if ($.inArray in getFromEn below
	and the setInterval above

	in mainController, uncomment the first if in getFromEn
	open both desktop and mobile sites in debug
	open all dialogs, menus, tabs, etc.
	go to console after 10sec
	copy array to global
	run this
	var unloced = '';$.each(temp1, function(){unloced += this + '\n';}); console.log(unloced);
	copy/paste in mail to team
	revert this and maincontroller

	TODO:
	make all loc strings promise-based
	move maincontroller fn to uilibrary factory

      */

      function getFromEn(s) {
	if (langCode === 'EN') {
	  /*if ($.inArray(s, englishArray) == -1) {
	    unlocalized[s] = 'missing';
	    }*/
	  return s;
	} else {
	  return getString($.inArray(s,englishArray), s);
	}
      }

      function getAvailableLanguages() {
	var deferred = $q.defer();
	initPromise.then(function() {
	  var langArray = [];
	  lpacks.find('languagepack').each(function(i, pack) {
	    langArray.push({ label: $(pack).attr('name'), code: $(pack).attr('code') });
	  });

	  deferred.resolve(langArray);
	});
	return deferred.promise;
      }

      function setLanguage(code) {
	var deferred = $q.defer();
	initPromise.then(function () {
	  langCode = code;
	  if (code === 'EN') {
	    locData = englishData;
	    locArray = locData.split('\n');

	    deferred.resolve(true);
	    return;
	  }
	  var url = lpacks.find('languagepack[code=' + code + ']').attr('url');
	  util.log(url);
	  $http.get(url).
	    success(function(data) {
	      data = transformLanguagePack(data);
	      locData = data;
	      locArray = [];
	      $.each(data.split('\n'), function (i,item) {
		var spl = item.split('\t');
		var ind = parseInt(spl[0], 10);
		if (spl.length === 2 && !isNaN(ind)) {
		  locArray[ind] = spl[1];
		  //console.log(ind, item);
		}
	      });
	      deferred.resolve(true);
	    });
	});

	return deferred.promise;
      }
      var init = function () {
	var deferred = $q.defer();
	$q.all([
	  $http.get('//worldwidetelescope.org/wwtweb/catalog.aspx?X=Languages')
	    .success(function(data) {
	      lpacks = $(data);
	    })
	    .error(function(data, status, headers, config) {
	      util.log(data, status, headers, config);
	    }),
	  $http.get('//worldwidetelescope.org/wwtweb/catalog.aspx?Q=lang_en')
	    .success(function(data) {
	      data = transformLanguagePack(data);
	      englishData = data;
	      var dsplit = data.split('\n');

	      englishArray = [];
	      $.each(dsplit, function () {
		var s1 = this.split('\t')[1];
		if (s1) {
		  s1 = s1.split('\r')[0];
		}
		englishArray[parseInt(this.split('\t')[0])] = s1;
	      });

	    })
	]).then(function() {
	  deferred.resolve(true);
	});
	return deferred.promise;
      };

      var transformLanguagePack = function (data) {
	if (data.charAt(0) == 1) {
	  return data;
	}

	var re1 = new RegExp(data.charAt(0), "g");
	var re2 = new RegExp(data.charAt(3), "g");
	return data.replace(re1, '').replace(re2, '');
      };

      var initPromise = init();
      return api;
    }
  ]
);
<commit_msg>factories/Localization.js: reindent a bit<commit_after>wwt.app.factory(
  'Localization',
  [
    '$http',
    '$q',
    'Util',

    function($http, $q, util) {
      var api = {
	setLanguage: setLanguage,
	getString: getString,
	getFromEn: getFromEn,
	getAvailableLanguages: getAvailableLanguages
      };

      var langCode,
	  englishData,
	  englishArray,
	  locData,
	  locArray,
	  lpacks;

      function getString(id, s) {
	return locArray && locArray[id] ? locArray[id] : s ? s : '';
      }

      function getFromEn(s) {
	if (langCode === 'EN') {
	  return s;
	} else {
	  return getString($.inArray(s, englishArray), s);
	}
      }

      function getAvailableLanguages() {
	var deferred = $q.defer();

	initPromise.then(function() {
	  var langArray = [];

	  lpacks.find('languagepack').each(function(i, pack) {
	    langArray.push({
              label: $(pack).attr('name'),
              code: $(pack).attr('code')
            });
	  });

	  deferred.resolve(langArray);
	});

	return deferred.promise;
      }

      function setLanguage(code) {
	var deferred = $q.defer();

	initPromise.then(function () {
	  langCode = code;

	  if (code === 'EN') {
	    locData = englishData;
	    locArray = locData.split('\n');
	    deferred.resolve(true);
	    return;
	  }

	  var url = lpacks.find('languagepack[code=' + code + ']').attr('url');
	  util.log(url);

	  $http.get(url).
	    success(function(data) {
	      data = transformLanguagePack(data);
	      locData = data;
	      locArray = [];

	      $.each(data.split('\n'), function (i,item) {
		var spl = item.split('\t');
		var ind = parseInt(spl[0], 10);
		if (spl.length === 2 && !isNaN(ind)) {
		  locArray[ind] = spl[1];
		}
	      });

	      deferred.resolve(true);
	    });
	});

	return deferred.promise;
      }

      var init = function () {
	var deferred = $q.defer();

	$q.all([
	  $http.get('//worldwidetelescope.org/wwtweb/catalog.aspx?X=Languages')
	    .success(function(data) {
	      lpacks = $(data);
	    })
	    .error(function(data, status, headers, config) {
	      util.log(data, status, headers, config);
	    }),

	  $http.get('//worldwidetelescope.org/wwtweb/catalog.aspx?Q=lang_en')
	    .success(function(data) {
	      data = transformLanguagePack(data);
	      englishData = data;
	      var dsplit = data.split('\n');

	      englishArray = [];
	      $.each(dsplit, function () {
		var s1 = this.split('\t')[1];
		if (s1) {
		  s1 = s1.split('\r')[0];
		}
		englishArray[parseInt(this.split('\t')[0])] = s1;
	      });

	    })
	]).then(function() {
	  deferred.resolve(true);
	});

	return deferred.promise;
      };

      var transformLanguagePack = function (data) {
	if (data.charAt(0) == 1) {
	  return data;
	}

	var re1 = new RegExp(data.charAt(0), "g");
	var re2 = new RegExp(data.charAt(3), "g");
	return data.replace(re1, '').replace(re2, '');
      };

      var initPromise = init();
      return api;
    }
  ]
);
<|endoftext|>


<commit_before>'use strict';

var AbstractClientResource = require('./../abstract-client-resource');

/**
 * CaseInstance Resource
 * @class
 * @memberof CamSDK.client.resource
 * @augments CamSDK.client.AbstractClientResource
 */
var CaseInstance = AbstractClientResource.extend();

/**
 * Path used by the resource to perform HTTP queries
 * @type {String}
 */
CaseInstance.path = 'case-instance';

CaseInstance.list = function(params, done) {
  return this.http.get(this.path, {
    data: params,
    done: done
  });
};

CaseInstance.close = function(instanceId, params, done) {
  return this.http.post(this.path + '/' + instanceId + '/close', {
    data: params,
    done: done
  });
};

module.exports = CaseInstance;
<commit_msg>feat(rest): provide terminate method<commit_after>'use strict';

var AbstractClientResource = require('./../abstract-client-resource');

/**
 * CaseInstance Resource
 * @class
 * @memberof CamSDK.client.resource
 * @augments CamSDK.client.AbstractClientResource
 */
var CaseInstance = AbstractClientResource.extend();

/**
 * Path used by the resource to perform HTTP queries
 * @type {String}
 */
CaseInstance.path = 'case-instance';

CaseInstance.list = function(params, done) {
  return this.http.get(this.path, {
    data: params,
    done: done
  });
};

CaseInstance.close = function(instanceId, params, done) {
  return this.http.post(this.path + '/' + instanceId + '/close', {
    data: params,
    done: done
  });
};

CaseInstance.terminate = function(instanceId, params, done) {
  return this.http.post(this.path + '/' + instanceId + '/terminate', {
    data: params,
    done: done
  });
};

module.exports = CaseInstance;
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the MIT license
 * If a copy of the MIT license was not distributed with this file, you can
 * obtain one at http://www.mozillapopcorn.org/butter-license.txt */

define( [ "util/lang", "./scrubber" ], function( util, Scrubber ) {

  var CANVAS_CONTAINER_PADDING = 5;

  return function( butter, media, tracksContainer, hScrollbar ){

    var _element = document.createElement( "div" ),
        _canvas = document.createElement( "canvas" ),
        _canvasContainer = document.createElement( "div" ),
        _media = media,
        _tracksContainer = tracksContainer,
        _scrubber = new Scrubber( butter, _element, _media, _tracksContainer, hScrollbar ),
        _this = this,
        _lastZoom;

    _element.className = "time-bar";
    _canvasContainer.className = "time-bar-canvas-container";
    _canvasContainer.appendChild( _canvas );
    _element.appendChild( _canvasContainer );

    _canvas.addEventListener( "mousedown", _scrubber.onMouseDown, false );

    function drawTicks( zoom ) {
      var tracksContainerWidth = tracksContainer.container.getBoundingClientRect().width,
          width = Math.min( tracksContainerWidth, _tracksContainer.container.scrollWidth ),
          containerWidth = Math.min( width, _tracksContainer.element.offsetWidth - CANVAS_CONTAINER_PADDING );

      _canvasContainer.style.width = containerWidth + "px";

      var context = _canvas.getContext( "2d" );

      if ( _canvas.height != _canvas.offsetHeight ) {
        _canvas.height = _canvas.offsetHeight;
      }
      if ( _canvas.width != containerWidth ) {
        _canvas.width = containerWidth;
      }

      var inc = _tracksContainer.container.scrollWidth / _media.duration,
          textWidth = context.measureText( util.secondsToSMPTE( 5 ) ).width,
          padding = 20,
          lastPosition = 0,
          lastTimeDisplayed = -( ( textWidth + padding ) / 2 ),
          start = _tracksContainer.element.scrollLeft / inc,
          end = ( _tracksContainer.element.scrollLeft + containerWidth ) / inc;

      context.clearRect ( 0, 0, _canvas.width, _canvas.height );
      context.translate( -_tracksContainer.element.scrollLeft, 0 );
      context.beginPath();

      for ( var i = 1, l = _media.duration + 1; i < l; i++ ) {

        // If the current time is not in the viewport, just skip it
        if ( i + 1 < start ) {
          continue;
        }
        if ( i - 1 > end ) {
          break;
        }

        var position = i * inc;
        var spaceBetween = -~( position ) - -~( lastPosition );

        // ensure there is enough space to draw a seconds tick
        if ( spaceBetween > 3 ) {

          // ensure there is enough space to draw a half second tick
          if ( spaceBetween > 6 ) {

            context.moveTo( -~position - spaceBetween / 2, 0 );
            context.lineTo( -~position - spaceBetween / 2, 7 );

            // ensure there is enough space for quarter ticks
            if ( spaceBetween > 12 ) {

              context.moveTo( -~position - spaceBetween / 4 * 3, 0 );
              context.lineTo( -~position - spaceBetween / 4 * 3, 4 );

              context.moveTo( -~position - spaceBetween / 4, 0 );
              context.lineTo( -~position - spaceBetween / 4, 4 );

            }
          }
          context.moveTo( -~position, 0 );
          context.lineTo( -~position, 10 );

          if ( ( position - lastTimeDisplayed ) > textWidth + padding ) {

            lastTimeDisplayed = position;
            // text color
            context.fillStyle = "#999999";
            context.fillText( util.secondsToSMPTE( i ), -~position - ( textWidth / 2 ), 21 );
          }

          lastPosition = position;
        }
      }
      // stroke color
      context.strokeStyle = "#999999";
      context.stroke();
      context.translate( _tracksContainer.element.scrollLeft, 0 );

      _scrubber.update( containerWidth, zoom );
    }; //update

    _tracksContainer.element.addEventListener( "scroll", function() {
      drawTicks( _lastZoom );
    }, false );

    this.update = function( zoom ) {
      _lastZoom = zoom;
      drawTicks( zoom );
    };

    this.destroy = function(){
      _scrubber.destroy();
    }; //destroy

    Object.defineProperties( this, {
      element: {
        enumerable: true,
        get: function(){
          return _element;
        }
      }
    });

  }; //TimeBar

});
<commit_msg>Remove _lastZoom variable because the scrubber already stores the most current zoom level [#492]<commit_after>/* This Source Code Form is subject to the terms of the MIT license
 * If a copy of the MIT license was not distributed with this file, you can
 * obtain one at http://www.mozillapopcorn.org/butter-license.txt */

define( [ "util/lang", "./scrubber" ], function( util, Scrubber ) {

  var CANVAS_CONTAINER_PADDING = 5;

  return function( butter, media, tracksContainer, hScrollbar ){

    var _element = document.createElement( "div" ),
        _canvas = document.createElement( "canvas" ),
        _canvasContainer = document.createElement( "div" ),
        _media = media,
        _tracksContainer = tracksContainer,
        _scrubber = new Scrubber( butter, _element, _media, _tracksContainer, hScrollbar ),
        _this = this;

    _element.className = "time-bar";
    _canvasContainer.className = "time-bar-canvas-container";
    _canvasContainer.appendChild( _canvas );
    _element.appendChild( _canvasContainer );

    _canvas.addEventListener( "mousedown", _scrubber.onMouseDown, false );

    function drawTicks( zoom ) {
      var tracksContainerWidth = tracksContainer.container.getBoundingClientRect().width,
          width = Math.min( tracksContainerWidth, _tracksContainer.container.scrollWidth ),
          containerWidth = Math.min( width, _tracksContainer.element.offsetWidth - CANVAS_CONTAINER_PADDING );

      _canvasContainer.style.width = containerWidth + "px";

      var context = _canvas.getContext( "2d" );

      if ( _canvas.height != _canvas.offsetHeight ) {
        _canvas.height = _canvas.offsetHeight;
      }
      if ( _canvas.width != containerWidth ) {
        _canvas.width = containerWidth;
      }

      var inc = _tracksContainer.container.scrollWidth / _media.duration,
          textWidth = context.measureText( util.secondsToSMPTE( 5 ) ).width,
          padding = 20,
          lastPosition = 0,
          lastTimeDisplayed = -( ( textWidth + padding ) / 2 ),
          start = _tracksContainer.element.scrollLeft / inc,
          end = ( _tracksContainer.element.scrollLeft + containerWidth ) / inc;

      context.clearRect ( 0, 0, _canvas.width, _canvas.height );
      context.translate( -_tracksContainer.element.scrollLeft, 0 );
      context.beginPath();

      for ( var i = 1, l = _media.duration + 1; i < l; i++ ) {

        // If the current time is not in the viewport, just skip it
        if ( i + 1 < start ) {
          continue;
        }
        if ( i - 1 > end ) {
          break;
        }

        var position = i * inc;
        var spaceBetween = -~( position ) - -~( lastPosition );

        // ensure there is enough space to draw a seconds tick
        if ( spaceBetween > 3 ) {

          // ensure there is enough space to draw a half second tick
          if ( spaceBetween > 6 ) {

            context.moveTo( -~position - spaceBetween / 2, 0 );
            context.lineTo( -~position - spaceBetween / 2, 7 );

            // ensure there is enough space for quarter ticks
            if ( spaceBetween > 12 ) {

              context.moveTo( -~position - spaceBetween / 4 * 3, 0 );
              context.lineTo( -~position - spaceBetween / 4 * 3, 4 );

              context.moveTo( -~position - spaceBetween / 4, 0 );
              context.lineTo( -~position - spaceBetween / 4, 4 );

            }
          }
          context.moveTo( -~position, 0 );
          context.lineTo( -~position, 10 );

          if ( ( position - lastTimeDisplayed ) > textWidth + padding ) {

            lastTimeDisplayed = position;
            // text color
            context.fillStyle = "#999999";
            context.fillText( util.secondsToSMPTE( i ), -~position - ( textWidth / 2 ), 21 );
          }

          lastPosition = position;
        }
      }
      // stroke color
      context.strokeStyle = "#999999";
      context.stroke();
      context.translate( _tracksContainer.element.scrollLeft, 0 );

      _scrubber.update( containerWidth, zoom );
    }; //update

    _tracksContainer.element.addEventListener( "scroll", function() {
      drawTicks();
    }, false );

    this.update = function( zoom ) {
      drawTicks( zoom );
    };

    this.destroy = function(){
      _scrubber.destroy();
    }; //destroy

    Object.defineProperties( this, {
      element: {
        enumerable: true,
        get: function(){
          return _element;
        }
      }
    });

  }; //TimeBar

});
<|endoftext|>