<commit_before>
var venaclient = require('../venaclient.js')
, assert = require('assert')
, EventEmitter = require('events').EventEmitter
, _ = require('underscore')
, Backbone = require('backbone')
, MockSocket = require(__dirname + '/mocksocket').MockSocket
;

var randomId = function () {
    return 'test' + Math.floor(Math.random() * 1000000);
};

var newContext = function (options) {
    var name = 'test'
    , Model = Backbone.Model.extend({
	urlRoot: name
    })
    , socket = new MockSocket()
    , client = new venaclient.Client(socket)
    , name = randomId();
    ;

    return {
	Model: Model
	, name: name
	, socket: socket
	, client: client
	, service: new client.Service(name, Model, options)
    };
}
;

describe('venaclient', function () {

    describe('#model', function () {

	it('should be constructable', function () {
	    assert(newContext().service);
	});

	describe('#get', function () {

	    it('should exist', function () {
		assert.equal(typeof newContext().service.get, 'function');
	    });

	    it('should provide instances', function () {
		assert(newContext().service.get(randomId()))
	    });

	    it('should have the service name', function () {
		var context = newContext();
		assert.equal(context.service.name, context.name);
	    });

	    describe(':instance', function () {

		it('should have the instance id', function () {
		    var id = randomId();
		    assert.equal(newContext().service.get(id).id, id);
		});

		it('should have the instance channel', function () {
		    var id = randomId()
		    , service = newContext().service
		    assert.equal(service.get(id).channel, service.name + '/' + id);
		});

		it('should always be the same object for the same id', function () {
		    var context = newContext()
		    , id = randomId()
		    , instance = context.service.get(id)
		    , otherInstance = context.service.get(id)
		    ;
		    instance.x = 1;
		    otherInstance.x = 2;
		    assert.equal(otherInstance.x, instance.x);
		});

		describe('#socket', function () {
		    it('should exist', function () {
			var context = newContext();
			assert(_.isObject(context.service.get(randomId()).socket));
		    });

		    it('should be the service socket', function () {
			var context = newContext();
			assert.equal(context.service.get(randomId()).socket, context.socket);
		    });
		});

		describe('#model', function () {

		    it('should exist', function () {
			var context = newContext();
			assert(_.isObject(context.service.get(randomId()).model));
		    });

		    it('should be of the expected type', function () {
			var context = newContext();
			assert(context.service.get(randomId()).model instanceof context.Model);
		    });

		});

		describe('#subscribe', function () {
		    it('should exist', function () {
			var context = newContext();
			assert.equal(typeof context.service.get(randomId()).subscribe, 'function');
		    });

		    it('should trigger "set" updates on the model', function (done) {
			var context = newContext()
			, id = randomId()
			, instance = context.service.get(id)
			;
			instance.subscribe();
			instance.model.on('change:x', function () {
			    assert.equal(instance.model.get('x'), 1);
			    done();
			});
			context.socket._receive(instance.channel, {
			    subject: 'set'
			    , body: {
				x: 1
			    }
			});
		    });

		    it('should trigger "unset" updates on the model', function (done) {
			var context = newContext()
			, id = randomId()
			, instance = context.service.get(id)
			;
			instance.subscribe();
			instance.model.set('x', 1);
			instance.model.on('change:x', function () {
			    assert(!instance.model.has('x'));
			    done();
			})
			context.socket._receive(instance.channel, {
			    subject: 'unset'
			    , body: {
				x: 1
			    }
			});
		    });

		});

		describe('#unsubscribe', function () {
		    it('should exist', function () {
			var context = newContext();
			assert.equal(typeof context.service.get(randomId()).subscribe, 'function');
		    });

		    it('should not trigger "set" updates on the model afterward', function () {
			var context = newContext()
			, id = randomId()
			, instance = context.service.get(id)
			, called = 0
			;
			instance.subscribe();
			instance.model.on('change:x', function () {
			    called = called + 1
			});
			context.socket._receive(instance.channel, {
			    subject: 'set'
			    , body: {
				x: 1
			    }
			});
			instance.unsubscribe();
			context.socket._receive(instance.channel, {
			    subject: 'set'
			    , body: {
				x: 2
			    }
			});
			assert.equal(called, 1);
		    });
		});

		describe(':methods', function () {

		    it('should exist', function () {
			var context = newContext({
			    methods: ['method']
			});
			assert.equal(typeof context.service.get(randomId()).method, 'function');
		    });

		    it('should transmit the method over the socket', function (done) {
			var context = newContext({
			    methods: ['method']
			})
			, instance = context.service.get(randomId())
			;
			context.socket._emit(context.service.name, function (msg) {
			    assert(msg);
			    assert.equal(msg.id, instance.id);
			    assert.equal(msg.method, 'method');
			    assert(msg.hasOwnProperty('data'), 'service method invocation msg did not have a data property.')
			    assert.equal(msg.data.x, 1);
			    done()
			});
			instance.method({
			    x: 1
			});
		    });

		    it('should transmit "subscribe" over the socket as if it was a method', function (done) {
			var context = newContext()
			, instance = context.service.get(randomId())
			;
			context.socket._emit(context.service.name, function (msg) {
			    assert(msg);
			    assert.equal(msg.id, instance.id);
			    assert.equal(msg.method, 'subscribe');
			    done();
			});
			instance.subscribe();
		    });

		    it('should transmit "unsubscribe" over the socket as if it was a method', function (done) {
			var context = newContext()
			, instance = context.service.get(randomId())
			;
			context.socket._emit(context.service.name, function (msg) {
			    assert(msg);
			    assert.equal(msg.id, instance.id);
			    if (msg.method === 'unsubscribe') {
				return done();
			    }
			});
			instance.subscribe();
			instance.unsubscribe();
		    });

		});

		describe('#on', function () {

		    it('should be triggered by socket events for the target channel', function (done) {
			var context = newContext({
			    methods: ['method']
			})
			, instance = context.service.get(randomId())
			;
			instance.subscribe();
			instance.model.on('trigger', function (data) {
			    done();
			});

			context.socket._receive(instance.channel, {
			    subject: 'trigger'
			    , trigger: 'trigger'
			});
		    });

		    it('should be triggered with data', function (done) {
			var context = newContext({
			    methods: ['method']
			})
			, instance = context.service.get(randomId())
			;
			instance.subscribe();
			instance.model.on('trigger', function (data) {
			    assert.equal(data.x, 1);
			    done();
			});

			context.socket._receive(instance.channel, {
			    subject: 'trigger'
			    , trigger: 'trigger'
			    , data: {
				x: 1
			    }
			});
		    });

		    it('should not be triggered by socket events for other channels', function () {
			var context = newContext({
			    methods: ['method']
			})
			, instance = context.service.get(randomId())
			, called = 0
			;
			instance.subscribe();
			instance.model.on('trigger', function (data) {
			    called = called + 1;
			});

			context.socket._receive(randomId(), {
			    subject: 'trigger'
			    , trigger: 'trigger'
			});

			context.socket._receive(instance.channel, {
			    subject: 'trigger'
			    , trigger: 'trigger'
			});

		    });

		});

	    });

	});

    });

});
<commit_msg>Add tests that the client model will resubscribe on reconnection.<commit_after>
var venaclient = require('../venaclient.js')
, assert = require('assert')
, EventEmitter = require('events').EventEmitter
, _ = require('underscore')
, Backbone = require('backbone')
, MockSocket = require(__dirname + '/mocksocket').MockSocket
;

var randomId = function () {
    return 'test' + Math.floor(Math.random() * 1000000);
};

var newContext = function (options) {
    var name = 'test'
    , Model = Backbone.Model.extend({
	urlRoot: name
    })
    , socket = new MockSocket()
    , client = new venaclient.Client(socket)
    , name = randomId();
    ;

    return {
	Model: Model
	, name: name
	, socket: socket
	, client: client
	, service: new client.Service(name, Model, options)
    };
}
;

describe('venaclient', function () {

    describe('#model', function () {

	it('should be constructable', function () {
	    assert(newContext().service);
	});

	describe('#get', function () {

	    it('should exist', function () {
		assert.equal(typeof newContext().service.get, 'function');
	    });

	    it('should provide instances', function () {
		assert(newContext().service.get(randomId()))
	    });

	    it('should have the service name', function () {
		var context = newContext();
		assert.equal(context.service.name, context.name);
	    });

	    describe(':instance', function () {

		it('should have the instance id', function () {
		    var id = randomId();
		    assert.equal(newContext().service.get(id).id, id);
		});

		it('should have the instance channel', function () {
		    var id = randomId()
		    , service = newContext().service
		    assert.equal(service.get(id).channel, service.name + '/' + id);
		});

		it('should always be the same object for the same id', function () {
		    var context = newContext()
		    , id = randomId()
		    , instance = context.service.get(id)
		    , otherInstance = context.service.get(id)
		    ;
		    instance.x = 1;
		    otherInstance.x = 2;
		    assert.equal(otherInstance.x, instance.x);
		});

		describe('#socket', function () {
		    it('should exist', function () {
			var context = newContext();
			assert(_.isObject(context.service.get(randomId()).socket));
		    });

		    it('should be the service socket', function () {
			var context = newContext();
			assert.equal(context.service.get(randomId()).socket, context.socket);
		    });
		});

		describe('#model', function () {

		    it('should exist', function () {
			var context = newContext();
			assert(_.isObject(context.service.get(randomId()).model));
		    });

		    it('should be of the expected type', function () {
			var context = newContext();
			assert(context.service.get(randomId()).model instanceof context.Model);
		    });

		});

		describe('#subscribe', function () {
		    it('should exist', function () {
			var context = newContext();
			assert.equal(typeof context.service.get(randomId()).subscribe, 'function');
		    });

		    it('should emit a subscribe event on the socket', function (done) {
			var context = newContext()
			, instance = context.service.get(randomId())
			;
			context.socket._emit(context.name, function (msg) {
			    assert.equal(msg.method, 'subscribe');
			    assert.equal(msg.id, instance.id);
			    done();
			});
			instance.subscribe();
		    });

		    it('should re-emit a subscribe event when the socket reconnects', function () {
			var context = newContext()
			, instance = context.service.get(randomId())
			, called = 0
			;
			context.socket._emit(context.name, function (msg) {
			    if (msg.method === 'subscribe') {
				called = 1 + called;
			    }
			});
			instance.subscribe();
			assert.equal(1, called);
			context.socket._receive('reconnect');
			assert.equal(2, called);
		    });

		    it('should trigger "set" updates on the model', function (done) {
			var context = newContext()
			, id = randomId()
			, instance = context.service.get(id)
			;
			instance.subscribe();
			instance.model.on('change:x', function () {
			    assert.equal(instance.model.get('x'), 1);
			    done();
			});
			context.socket._receive(instance.channel, {
			    subject: 'set'
			    , body: {
				x: 1
			    }
			});
		    });

		    it('should trigger "unset" updates on the model', function (done) {
			var context = newContext()
			, id = randomId()
			, instance = context.service.get(id)
			;
			instance.subscribe();
			instance.model.set('x', 1);
			instance.model.on('change:x', function () {
			    assert(!instance.model.has('x'));
			    done();
			})
			context.socket._receive(instance.channel, {
			    subject: 'unset'
			    , body: {
				x: 1
			    }
			});
		    });

		});

		describe('#unsubscribe', function () {
		    it('should exist', function () {
			var context = newContext();
			assert.equal(typeof context.service.get(randomId()).subscribe, 'function');
		    });

		    it('should not trigger "set" updates on the model afterward', function () {
			var context = newContext()
			, id = randomId()
			, instance = context.service.get(id)
			, called = 0
			;
			instance.subscribe();
			instance.model.on('change:x', function () {
			    called = called + 1
			});
			context.socket._receive(instance.channel, {
			    subject: 'set'
			    , body: {
				x: 1
			    }
			});
			instance.unsubscribe();
			context.socket._receive(instance.channel, {
			    subject: 'set'
			    , body: {
				x: 2
			    }
			});
			assert.equal(called, 1);
		    });

		    it('should not re-emit a subscribe event when the socket reconnects after unsubscribe', function () {
			var context = newContext()
			, instance = context.service.get(randomId())
			, called = 0
			;
			context.socket._emit(context.name, function (msg) {
			    if (msg.method === 'subscribe') {
				called = 1 + called;
			    }
			});
			instance.subscribe();
			assert.equal(1, called);
			instance.unsubscribe();
			context.socket._receive('reconnect');
			assert.equal(1, called);

		    });
		});

		describe(':methods', function () {

		    it('should exist', function () {
			var context = newContext({
			    methods: ['method']
			});
			assert.equal(typeof context.service.get(randomId()).method, 'function');
		    });

		    it('should transmit the method over the socket', function (done) {
			var context = newContext({
			    methods: ['method']
			})
			, instance = context.service.get(randomId())
			;
			context.socket._emit(context.service.name, function (msg) {
			    assert(msg);
			    assert.equal(msg.id, instance.id);
			    assert.equal(msg.method, 'method');
			    assert(msg.hasOwnProperty('data'), 'service method invocation msg did not have a data property.')
			    assert.equal(msg.data.x, 1);
			    done()
			});
			instance.method({
			    x: 1
			});
		    });

		    it('should transmit "subscribe" over the socket as if it was a method', function (done) {
			var context = newContext()
			, instance = context.service.get(randomId())
			;
			context.socket._emit(context.service.name, function (msg) {
			    assert(msg);
			    assert.equal(msg.id, instance.id);
			    assert.equal(msg.method, 'subscribe');
			    done();
			});
			instance.subscribe();
		    });

		    it('should transmit "unsubscribe" over the socket as if it was a method', function (done) {
			var context = newContext()
			, instance = context.service.get(randomId())
			;
			context.socket._emit(context.service.name, function (msg) {
			    assert(msg);
			    assert.equal(msg.id, instance.id);
			    if (msg.method === 'unsubscribe') {
				return done();
			    }
			});
			instance.subscribe();
			instance.unsubscribe();
		    });

		});

		describe('#on', function () {

		    it('should be triggered by socket events for the target channel', function (done) {
			var context = newContext({
			    methods: ['method']
			})
			, instance = context.service.get(randomId())
			;
			instance.subscribe();
			instance.model.on('trigger', function (data) {
			    done();
			});

			context.socket._receive(instance.channel, {
			    subject: 'trigger'
			    , trigger: 'trigger'
			});
		    });

		    it('should be triggered with data', function (done) {
			var context = newContext({
			    methods: ['method']
			})
			, instance = context.service.get(randomId())
			;
			instance.subscribe();
			instance.model.on('trigger', function (data) {
			    assert.equal(data.x, 1);
			    done();
			});

			context.socket._receive(instance.channel, {
			    subject: 'trigger'
			    , trigger: 'trigger'
			    , data: {
				x: 1
			    }
			});
		    });

		    it('should not be triggered by socket events for other channels', function () {
			var context = newContext({
			    methods: ['method']
			})
			, instance = context.service.get(randomId())
			, called = 0
			;
			instance.subscribe();
			instance.model.on('trigger', function (data) {
			    called = called + 1;
			});

			context.socket._receive(randomId(), {
			    subject: 'trigger'
			    , trigger: 'trigger'
			});

			context.socket._receive(instance.channel, {
			    subject: 'trigger'
			    , trigger: 'trigger'
			});

		    });

		});

	    });

	});

    });

});
<|endoftext|>


<commit_before>eg.module("infiniteGridService",
    [window.jQuery, eg, window, document], function($, ns, global, doc) {
    /**
     * Infinite cascading grid layout service for infiniteGrid
     * @ko infiniteGrid를 통한 무한 그리드 레이아웃 서비스.
     * @class
     * @name eg.infiniteGridService
     * @extends eg.Component
     * @group EvergreenJs
     *
     * @param {String} DOM Element to be InfiniteGride. <ko>타겟 엘리먼트</ko>
     * @param {Object} [Options] A set of key/value pairs that configure the InfiniteGridService. <ko>key/value 형태의 옵션</ko>
     * @param {Number} [options.count=60] Count DOM count for recycle. If value is -1, DOM does increase without limit -1. <ko>재사용할 DOM 갯수. -1일 경우 DOM은 계속 늘어남.</ko>
     * @param {Number} [threshold=120] Threshold Scroll coordinate threshold. <ko>append, prepend 이벤트가 발생하기 위한 스크롤 좌표 임계치.</ko>
     * @param {Boolean} [usePersist=true] usePersist Determines whether allows persist. <ko>persist 사용 여부.</ko>
     */
    ns.InfiniteGridService = ns.Class.extend(ns.Component, {
        /**
         * Constructor
         * @param {String} Element selector
         * @param {Object} options
         */
        construct: function(element, options) {
            this._$wrapper = $(element);

            this._prevScrollTop = 0;
            this._inserting = false;

            this._topElement;
            this._bottomElemment;
            this._prependTopElementInfo;

            this._PERSIST_KEY = "__INFINITEGRIDSERVICE_PERSISTKEY__";

            this._options = $.extend({
                count: 120,
                threshold: 100,
                usePersist: true
            }, options);

            if (this._isEnablePersist()) {
                this._$wrapper.addClass("NO_TAP_HIGHLIGHT");
            }

            this._getScrollTop();
            this._infiniteGrid = new eg.InfiniteGrid(element, this._options);

            this._infiniteGrid.on("layoutComplete", $.proxy(function(e) {
                this._setBoundaryElements();

                if (!e.isAppend) {
                    this._adjustPrependScroll(e);
                }

                this._inserting = false;
            }, this));

            this.activate();
        },
        _getScrollTop: function() {
            var fn;

            if (typeof global.scrollY === "number") {
                fn = function() {
                    return global.scrollY;
                };
            } else if (typeof global.pageYOffset === "number") {
                fn = function() {
                    return global.pageYOffset;
                };
            } else if (typeof doc.documentElement.scrollTop === "number") {
                fn = function() {
                    return doc.documentElement.scrollTop;
                };
            } else if (typeof doc.body.scrollTop === "number") {
                fn = function() {
                    return doc.body.scrollTop;
                };
            }

            this._getScrollTop = fn;
            return fn();
        },
        _setBoundaryElements: function() {
            var element;

            if (element = this._infiniteGrid.getTopElement()) {
                this._topElement = element;
            }

            if (element = this._infiniteGrid.getBottomElement()) {
                this._bottomElemment = element;
            }
        },
        _isEnablePersist: function() {
            var agent = eg.agent();
            var enablePersist = true;

            if (!this._options.usePersist ||
                    agent.os.name === "ios" ||
                    (agent.os.name === "android" && parseFloat(agent.os.version) < 4.4)) {
                enablePersist = false;
            }

            this._isEnablePersist = function () {
                return enablePersist;
            };

            return enablePersist;
        },
        _handleScrollEnd: function() {
            if (this._inserting) {
                return;
            }

            if (this._prevScrollTop < this._getScrollTop()) {
                if (this._bottomElemment) {
                    var bottomElementBoundingClientRect =
                        this._bottomElemment.getBoundingClientRect();

                    if (bottomElementBoundingClientRect.top <=
                            global.innerHeight + this._options.threshold) {
                        this.trigger("append");
                    }
                }
            } else {
                if (this._infiniteGrid.isRecycling() && this._topElement) {
                    var topElementBoundingClientRect =
                        this._topElement.getBoundingClientRect();

                    if (topElementBoundingClientRect.bottom >=
                            (0 - this._options.threshold)) {
                        this.trigger("prepend");
                    }
                }
            }

            this._prevScrollTop = this._getScrollTop();
        },
        _insertElements: function(mode, elements) {
            this._inserting = true;

            var length = 0;
            var $elements;

            if (typeof elements === "string") {
                $elements = $(elements);
            } else {
                $elements = elements;
            }

            if (mode === "append") {
                length = this._infiniteGrid.append($elements);
            } else if (mode === "prepend") {
                this._setPrependTopElementInfo();
                length = this._infiniteGrid.prepend($elements);
            }

            this._inserting = false;

            return length;
        },
        _insertAjax: function(mode, url, options, callback) {
            this._inserting = true;

            if (typeof url === "object") {
                options = url;
                url = undefined;
            }

            if ($.isFunction(options)) {
                callback = options;
                options = undefined;
            }

            return $.ajax(url, options)
                .always($.proxy(function(data, textStatus) {
                    var $elements;

                    if (textStatus === "success") {
                        if (callback) {
                            $elements = callback(data);
                        } else {
                            $elements = $(data);
                        }
                    }

                    this._insertElements(mode, $elements);
                }, this));
        },
        _setPrependTopElementInfo: function() {
            if (this._topElement) {
                this._prependTopElementInfo = {
                    element: this._topElement,
                    boundingClientRect: this._topElement.getBoundingClientRect()
                };
            }
        },
        _adjustPrependScroll: function() {
            if (this._prependTopElementInfo.element) {
                var $element = $(this._prependTopElementInfo.element);
                var scrollTop =
                        this._$wrapper.offset().top + $element.offset().top +
                        $element.outerHeight() +
                        (0 - this._prependTopElementInfo.boundingClientRect.bottom);

                global.scrollTo(0, scrollTop);
            }
        },
        /**
         * Activate
         * @ko 활성화
         * @method eg.InfiniteGridService#activate
         * @return {Object} infiniteGridService Instance itself.
         */
        activate: function() {
            $(global).on("scrollend", $.proxy(this._handleScrollEnd, this));
            return this;
        },
        /**
         * Deactivate
         * @ko 비활성화
         * @method eg.InfiniteGridService#deactivate
         * @return {Object} infiniteGridService Instance itself.
         */
        deactivate: function() {
            $(global).off("scrollend", this._handleScrollEnd);
            return this;
        },
        /**
         * Append elements
         * @ko 하단에 요소 추가
         * @method eg.InfiniteGridService#append
         * @param {String|jQuery} DOM Element to append in a target. <ko>타겟요소에 추가할 DOM 엘리먼트</ko>
         * @return {Number} Length The number of elements to prepended. <ko>추가한 요소의 갯수</ko>
         * @example
         *    infiniteGrid.append("<li> contents </li>");
         *    infiniteGrid.append($("<li> contents </li>"));
         */
        append: function(elements) {
            return this._insertElements("append", elements);
        },
        /**
         * Prepend elements
         * @ko 상단에 요소 추가
         * @method eg.InfiniteGridService#preppend
         * @param {String|jQuery} DOM Element to append in a target. <ko>타겟요소에 추가할 DOM 엘리먼트</ko>
         * @return {Number} Length The number of elements to prepended. <ko>추가한 요소의 갯수</ko>
         * @example
         * infiniteGrid.prepend("<li> contents </li>");
         * infiniteGrid.prepend($("<li> contents </li>"));
         */
        prepend: function(elements) {
            return this._insertElements("prepend", elements);
        },
        /**
         * Append Ajax response elements
         * @ko 하단에 Ajax 호출 결과 추가
         * @method eg.InfiniteGridService#ajaxAppend
         * @param {String} URL A string containing the URL to which the request is sent. <ko> 요청할 URL </ko>
         * @param {Object} [Settings] A set of key/value pairs that configure the Ajax request. <ko> Ajax 요청 설정 객체 </ko>
         * @param {Function} [Callback] A function to be called when the before append. The function receives one argument: data will append. <ko>요청 완료 후 실행 할 콜백. 응답 데이터를 파라메터로 받는다.</ko>
         * @return {Object} jqXHR.
         * @example
         *    infiniteGrid.ajaxAppend("http://server.com/contents", function(data) {
         *        return $(data);
         *    } );
         */
        appendAjax: function(url, settings, callback) {
            return this._insertAjax("append", url, settings, callback);
        },
        /**
         * Prepend Ajax response elements
         * @ko 상단에 요소 추가
         * @method eg.InfiniteGridService#preppend
         * @param {String} URL A string containing the URL to which the request is sent. <ko> 요청할 URL </ko>
         * @param {Object} [Settings] A set of key/value pairs that configure the Ajax request. <ko> Ajax 요청 설정 객체 </ko>
         * @param {Function} [Callback] A function to be called when the before append. The function receives one argument: data to prepended. <ko>요청 완료 후 실행 할 콜백. 응답 데이터를 파라메터로 받는다.</ko>
         * @return {Object} jqXHR.
         * @example
            infiniteGrid.ajaxPrepend("http://server.com/contents", function(data) {
                return $(data);
            } );
         */
        prependAjax: function(url, settings, callback) {
            return this._insertAjax("prepend", url, settings, callback);
        },
        /**
         * Stores state
         * @ko 상태 저장
         * @method eg.InfiniteGridService#storeContents
         * @param {String} [key] The type of keys maintained <ko>저장/복원을 위해 관리하는 키</ko>
         * @example
            infiniteGridService.store();
            infiniteGridService.store("customKey");
        */
        store: function(key) {
            if (this._isEnablePersist()) {
                var data;

                key = key || this._PERSIST_KEY;

                data = {
                    "infiniteGridStatus": this._infiniteGrid.getStatus(),
                    "scrollTop": this._getScrollTop()
                };

                this.trigger("store", data);
                $.persist(key, data);
            }
        },
        /**
         * Restores state
         * @ko 상태 복원
         * @method eg.InfiniteGridService#restore
         * @param {String} [key] The type of keys maintained <ko>저장/복원을 위해 관리하는 키</ko>
         * @example
            infiniteGridService.restore();
            infiniteGridService.restore("customKey");
        */
        restore: function(key) {
            var data;
            var isRestored = false;

            if (this._isEnablePersist()) {

                key = key || this._PERSIST_KEY;

                data = $.persist(key);

                if (data) {
                    this._infiniteGrid.setStatus(data.infiniteGridStatus);
                    global.scrollTo(0, data.scrollTop);
                    this._setBoundaryElements();
                    isRestored = true;
                }

                this.trigger("restore", data);
            }

            return isRestored;
        },
        /**
         * Clear elements
         * @ko 요소를 지움
         * @method eg.infiniteGrid#clear
         */
        clear: function() {
            this._infiniteGrid.clear();
        },
        /**
         * Release resources and off custom events
         * @ko 모든 커스텀 이벤트와 자원 해제
         * @method eg.infiniteGrid#destroy
         */
        destroy: function() {
            if (this._infiniteGrid) {
                this._infiniteGrid.destroy();
                this._infiniteGrid = null;
            }

            this.deactivate();
            this.off();
        }
    });
});<commit_msg>docs: modify service intro descriptions<commit_after>eg.module("infiniteGridService",
    [window.jQuery, eg, window, document], function($, ns, global, doc) {
    /**
     * Infinite cascading grid layout service for infiniteGrid
     * @ko infiniteGrid를 통한 무한 그리드 레이아웃 서비스.
     *
     * @param {String} DOM Element to be InfiniteGride. <ko>타겟 엘리먼트</ko>
     * @param {Object} [Options] A set of key/value pairs that configure the InfiniteGridService. <ko>key/value 형태의 옵션</ko>
     * @param {Number} [options.count=60] Count DOM count for recycle. If value is -1, DOM does increase without limit -1. <ko>재사용할 DOM 갯수. -1일 경우 DOM은 계속 늘어남.</ko>
     * @param {Number} [threshold=120] Threshold Scroll coordinate threshold. <ko>append, prepend 이벤트가 발생하기 위한 스크롤 좌표 임계치.</ko>
     * @param {Boolean} [usePersist=true] usePersist Determines whether allows persist. <ko>persist 사용 여부.</ko>
     */
    ns.InfiniteGridService = ns.Class.extend(ns.Component, {
        /**
         * Constructor
         * @param {String} Element selector
         * @param {Object} options
         */
        construct: function(element, options) {
            this._$wrapper = $(element);

            this._prevScrollTop = 0;
            this._inserting = false;

            this._topElement;
            this._bottomElemment;
            this._prependTopElementInfo;

            this._PERSIST_KEY = "__INFINITEGRIDSERVICE_PERSISTKEY__";

            this._options = $.extend({
                count: 120,
                threshold: 100,
                usePersist: true
            }, options);

            if (this._isEnablePersist()) {
                this._$wrapper.addClass("NO_TAP_HIGHLIGHT");
            }

            this._getScrollTop();
            this._infiniteGrid = new eg.InfiniteGrid(element, this._options);

            this._infiniteGrid.on("layoutComplete", $.proxy(function(e) {
                this._setBoundaryElements();

                if (!e.isAppend) {
                    this._adjustPrependScroll(e);
                }

                this._inserting = false;
            }, this));

            this.activate();
        },
        _getScrollTop: function() {
            var fn;

            if (typeof global.scrollY === "number") {
                fn = function() {
                    return global.scrollY;
                };
            } else if (typeof global.pageYOffset === "number") {
                fn = function() {
                    return global.pageYOffset;
                };
            } else if (typeof doc.documentElement.scrollTop === "number") {
                fn = function() {
                    return doc.documentElement.scrollTop;
                };
            } else if (typeof doc.body.scrollTop === "number") {
                fn = function() {
                    return doc.body.scrollTop;
                };
            }

            this._getScrollTop = fn;
            return fn();
        },
        _setBoundaryElements: function() {
            var element;

            if (element = this._infiniteGrid.getTopElement()) {
                this._topElement = element;
            }

            if (element = this._infiniteGrid.getBottomElement()) {
                this._bottomElemment = element;
            }
        },
        _isEnablePersist: function() {
            var agent = eg.agent();
            var enablePersist = true;

            if (!this._options.usePersist ||
                    agent.os.name === "ios" ||
                    (agent.os.name === "android" && parseFloat(agent.os.version) < 4.4)) {
                enablePersist = false;
            }

            this._isEnablePersist = function () {
                return enablePersist;
            };

            return enablePersist;
        },
        _handleScrollEnd: function() {
            if (this._inserting) {
                return;
            }

            if (this._prevScrollTop < this._getScrollTop()) {
                if (this._bottomElemment) {
                    var bottomElementBoundingClientRect =
                        this._bottomElemment.getBoundingClientRect();

                    if (bottomElementBoundingClientRect.top <=
                            global.innerHeight + this._options.threshold) {
                        this.trigger("append");
                    }
                }
            } else {
                if (this._infiniteGrid.isRecycling() && this._topElement) {
                    var topElementBoundingClientRect =
                        this._topElement.getBoundingClientRect();

                    if (topElementBoundingClientRect.bottom >=
                            (0 - this._options.threshold)) {
                        this.trigger("prepend");
                    }
                }
            }

            this._prevScrollTop = this._getScrollTop();
        },
        _insertElements: function(mode, elements) {
            this._inserting = true;

            var length = 0;
            var $elements;

            if (typeof elements === "string") {
                $elements = $(elements);
            } else {
                $elements = elements;
            }

            if (mode === "append") {
                length = this._infiniteGrid.append($elements);
            } else if (mode === "prepend") {
                this._setPrependTopElementInfo();
                length = this._infiniteGrid.prepend($elements);
            }

            this._inserting = false;

            return length;
        },
        _insertAjax: function(mode, url, options, callback) {
            this._inserting = true;

            if (typeof url === "object") {
                options = url;
                url = undefined;
            }

            if ($.isFunction(options)) {
                callback = options;
                options = undefined;
            }

            return $.ajax(url, options)
                .always($.proxy(function(data, textStatus) {
                    var $elements;

                    if (textStatus === "success") {
                        if (callback) {
                            $elements = callback(data);
                        } else {
                            $elements = $(data);
                        }
                    }

                    this._insertElements(mode, $elements);
                }, this));
        },
        _setPrependTopElementInfo: function() {
            if (this._topElement) {
                this._prependTopElementInfo = {
                    element: this._topElement,
                    boundingClientRect: this._topElement.getBoundingClientRect()
                };
            }
        },
        _adjustPrependScroll: function() {
            if (this._prependTopElementInfo.element) {
                var $element = $(this._prependTopElementInfo.element);
                var scrollTop =
                        this._$wrapper.offset().top + $element.offset().top +
                        $element.outerHeight() +
                        (0 - this._prependTopElementInfo.boundingClientRect.bottom);

                global.scrollTo(0, scrollTop);
            }
        },
        /**
         * Activate
         * @ko 활성화
         * @method eg.InfiniteGridService#activate
         * @return {Object} infiniteGridService Instance itself.
         */
        activate: function() {
            $(global).on("scrollend", $.proxy(this._handleScrollEnd, this));
            return this;
        },
        /**
         * Deactivate
         * @ko 비활성화
         * @method eg.InfiniteGridService#deactivate
         * @return {Object} infiniteGridService Instance itself.
         */
        deactivate: function() {
            $(global).off("scrollend", this._handleScrollEnd);
            return this;
        },
        /**
         * Append elements
         * @ko 하단에 요소 추가
         * @method eg.InfiniteGridService#append
         * @param {String|jQuery} DOM Element to append in a target. <ko>타겟요소에 추가할 DOM 엘리먼트</ko>
         * @return {Number} Length The number of elements to prepended. <ko>추가한 요소의 갯수</ko>
         * @example
         *    infiniteGrid.append("<li> contents </li>");
         *    infiniteGrid.append($("<li> contents </li>"));
         */
        append: function(elements) {
            return this._insertElements("append", elements);
        },
        /**
         * Prepend elements
         * @ko 상단에 요소 추가
         * @method eg.InfiniteGridService#preppend
         * @param {String|jQuery} DOM Element to append in a target. <ko>타겟요소에 추가할 DOM 엘리먼트</ko>
         * @return {Number} Length The number of elements to prepended. <ko>추가한 요소의 갯수</ko>
         * @example
         * infiniteGrid.prepend("<li> contents </li>");
         * infiniteGrid.prepend($("<li> contents </li>"));
         */
        prepend: function(elements) {
            return this._insertElements("prepend", elements);
        },
        /**
         * Append Ajax response elements
         * @ko 하단에 Ajax 호출 결과 추가
         * @method eg.InfiniteGridService#ajaxAppend
         * @param {String} URL A string containing the URL to which the request is sent. <ko> 요청할 URL </ko>
         * @param {Object} [Settings] A set of key/value pairs that configure the Ajax request. <ko> Ajax 요청 설정 객체 </ko>
         * @param {Function} [Callback] A function to be called when the before append. The function receives one argument: data will append. <ko>요청 완료 후 실행 할 콜백. 응답 데이터를 파라메터로 받는다.</ko>
         * @return {Object} jqXHR.
         * @example
         *    infiniteGrid.ajaxAppend("http://server.com/contents", function(data) {
         *        return $(data);
         *    } );
         */
        appendAjax: function(url, settings, callback) {
            return this._insertAjax("append", url, settings, callback);
        },
        /**
         * Prepend Ajax response elements
         * @ko 상단에 요소 추가
         * @method eg.InfiniteGridService#preppend
         * @param {String} URL A string containing the URL to which the request is sent. <ko> 요청할 URL </ko>
         * @param {Object} [Settings] A set of key/value pairs that configure the Ajax request. <ko> Ajax 요청 설정 객체 </ko>
         * @param {Function} [Callback] A function to be called when the before append. The function receives one argument: data to prepended. <ko>요청 완료 후 실행 할 콜백. 응답 데이터를 파라메터로 받는다.</ko>
         * @return {Object} jqXHR.
         * @example
            infiniteGrid.ajaxPrepend("http://server.com/contents", function(data) {
                return $(data);
            } );
         */
        prependAjax: function(url, settings, callback) {
            return this._insertAjax("prepend", url, settings, callback);
        },
        /**
         * Stores state
         * @ko 상태 저장
         * @method eg.InfiniteGridService#storeContents
         * @param {String} [key] The type of keys maintained <ko>저장/복원을 위해 관리하는 키</ko>
         * @example
            infiniteGridService.store();
            infiniteGridService.store("customKey");
        */
        store: function(key) {
            if (this._isEnablePersist()) {
                var data;

                key = key || this._PERSIST_KEY;

                data = {
                    "infiniteGridStatus": this._infiniteGrid.getStatus(),
                    "scrollTop": this._getScrollTop()
                };

                this.trigger("store", data);
                $.persist(key, data);
            }
        },
        /**
         * Restores state
         * @ko 상태 복원
         * @method eg.InfiniteGridService#restore
         * @param {String} [key] The type of keys maintained <ko>저장/복원을 위해 관리하는 키</ko>
         * @example
            infiniteGridService.restore();
            infiniteGridService.restore("customKey");
        */
        restore: function(key) {
            var data;
            var isRestored = false;

            if (this._isEnablePersist()) {

                key = key || this._PERSIST_KEY;

                data = $.persist(key);

                if (data) {
                    this._infiniteGrid.setStatus(data.infiniteGridStatus);
                    global.scrollTo(0, data.scrollTop);
                    this._setBoundaryElements();
                    isRestored = true;
                }

                this.trigger("restore", data);
            }

            return isRestored;
        },
        /**
         * Clear elements
         * @ko 요소를 지움
         * @method eg.infiniteGrid#clear
         */
        clear: function() {
            this._infiniteGrid.clear();
        },
        /**
         * Release resources and off custom events
         * @ko 모든 커스텀 이벤트와 자원 해제
         * @method eg.infiniteGrid#destroy
         */
        destroy: function() {
            if (this._infiniteGrid) {
                this._infiniteGrid.destroy();
                this._infiniteGrid = null;
            }

            this.deactivate();
            this.off();
        }
    });
});<|endoftext|>


<commit_before>define([
  'render/shaders/ShaderBase',
  'render/Attribute'
], function (ShaderBase, Attribute) {

  'use strict';

  var glfloat = 0x1406;

  var ShaderNormal = {};
  ShaderNormal.uniforms = {};
  ShaderNormal.attributes = {};
  ShaderNormal.program = undefined;

  ShaderNormal.uniformNames = ['uMV', 'uMVP'];
  Array.prototype.push.apply(ShaderNormal.uniformNames, ShaderBase.uniformNames.symmetryLine);

  ShaderNormal.vertex = [
    'attribute vec3 aVertex;',
    'attribute vec3 aNormal;',
    'attribute vec3 aMaterial;',
    'uniform mat4 uMV;',
    'uniform mat4 uMVP;',
    'varying vec3 vVertex;',
    'varying vec3 vNormal;',
    'varying float vMasking;',
    'void main() {',
    '  vec4 vert4 = vec4(aVertex, 1.0);',
    '  vNormal = normalize(aNormal);',
    '  vVertex = vec3(uMV * vert4);',
    '  vMasking = aMaterial.z;',
    '  gl_Position = uMVP * vert4;',
    '}'
  ].join('\n');

  ShaderNormal.fragment = [
    'precision mediump float;',
    'varying vec3 vVertex;',
    'varying vec3 vNormal;',
    ShaderBase.strings.fragColorUniforms,
    ShaderBase.strings.fragColorFunction,
    'void main() {',
    '  vec3 fragColor = vNormal * 0.5 + 0.5;',
    '  gl_FragColor = getFragColor(fragColor);',
    '}'
  ].join('\n');
  /** Draw */
  ShaderNormal.draw = function (render, main) {
    render.getGL().useProgram(this.program);
    this.bindAttributes(render);
    this.updateUniforms(render, main);
    ShaderBase.drawBuffer(render);
  };
  /** Get or create the shader */
  ShaderNormal.getOrCreate = function (gl) {
    return ShaderNormal.program ? ShaderNormal : ShaderBase.getOrCreate.call(this, gl);
  };
  /** Initialize attributes */
  ShaderNormal.initAttributes = function (gl) {
    var program = ShaderNormal.program;
    var attrs = ShaderNormal.attributes;
    attrs.aVertex = new Attribute(gl, program, 'aVertex', 3, glfloat);
    attrs.aNormal = new Attribute(gl, program, 'aNormal', 3, glfloat);
    attrs.aMaterial = new Attribute(gl, program, 'aMaterial', 3, glfloat);
  };
  /** Bind attributes */
  ShaderNormal.bindAttributes = function (render) {
    var attrs = ShaderNormal.attributes;
    attrs.aVertex.bindToBuffer(render.getVertexBuffer());
    attrs.aNormal.bindToBuffer(render.getNormalBuffer());
    attrs.aMaterial.bindToBuffer(render.getMaterialBuffer());
  };
  /** Updates uniforms */
  ShaderNormal.updateUniforms = function (render, main) {
    var gl = render.getGL();
    var uniforms = this.uniforms;
    var mesh = render.getMesh();

    gl.uniformMatrix4fv(uniforms.uMV, false, mesh.getMV());
    gl.uniformMatrix4fv(uniforms.uMVP, false, mesh.getMVP());

    ShaderBase.updateUniforms.call(this, render, main);
  };

  return ShaderNormal;
});<commit_msg>Updates normal shader<commit_after>define([
  'render/shaders/ShaderBase',
  'render/Attribute'
], function (ShaderBase, Attribute) {

  'use strict';

  var glfloat = 0x1406;

  var ShaderNormal = {};
  ShaderNormal.uniforms = {};
  ShaderNormal.attributes = {};
  ShaderNormal.program = undefined;

  ShaderNormal.uniformNames = ['uMV', 'uMVP', 'uN'];
  Array.prototype.push.apply(ShaderNormal.uniformNames, ShaderBase.uniformNames.symmetryLine);

  ShaderNormal.vertex = [
    'attribute vec3 aVertex;',
    'attribute vec3 aNormal;',
    'attribute vec3 aMaterial;',
    'uniform mat4 uMV;',
    'uniform mat4 uMVP;',
    'uniform mat3 uN;',
    'varying vec3 vVertex;',
    'varying vec3 vNormal;',
    'varying float vMasking;',
    'void main() {',
    '  vec4 vert4 = vec4(aVertex, 1.0);',
    '  vNormal = uN * normalize(aNormal);',
    '  vVertex = vec3(uMV * vert4);',
    '  vMasking = aMaterial.z;',
    '  gl_Position = uMVP * vert4;',
    '}'
  ].join('\n');

  ShaderNormal.fragment = [
    'precision mediump float;',
    'varying vec3 vVertex;',
    'varying vec3 vNormal;',
    ShaderBase.strings.fragColorUniforms,
    ShaderBase.strings.fragColorFunction,
    'void main() {',
    '  gl_FragColor = getFragColor(vNormal * 0.5 + 0.5);',
    '}'
  ].join('\n');
  /** Draw */
  ShaderNormal.draw = function (render, main) {
    render.getGL().useProgram(this.program);
    this.bindAttributes(render);
    this.updateUniforms(render, main);
    ShaderBase.drawBuffer(render);
  };
  /** Get or create the shader */
  ShaderNormal.getOrCreate = function (gl) {
    return ShaderNormal.program ? ShaderNormal : ShaderBase.getOrCreate.call(this, gl);
  };
  /** Initialize attributes */
  ShaderNormal.initAttributes = function (gl) {
    var program = ShaderNormal.program;
    var attrs = ShaderNormal.attributes;
    attrs.aVertex = new Attribute(gl, program, 'aVertex', 3, glfloat);
    attrs.aNormal = new Attribute(gl, program, 'aNormal', 3, glfloat);
    attrs.aMaterial = new Attribute(gl, program, 'aMaterial', 3, glfloat);
  };
  /** Bind attributes */
  ShaderNormal.bindAttributes = function (render) {
    var attrs = ShaderNormal.attributes;
    attrs.aVertex.bindToBuffer(render.getVertexBuffer());
    attrs.aNormal.bindToBuffer(render.getNormalBuffer());
    attrs.aMaterial.bindToBuffer(render.getMaterialBuffer());
  };
  /** Updates uniforms */
  ShaderNormal.updateUniforms = function (render, main) {
    var gl = render.getGL();
    var uniforms = this.uniforms;
    var mesh = render.getMesh();

    gl.uniformMatrix4fv(uniforms.uMV, false, mesh.getMV());
    gl.uniformMatrix4fv(uniforms.uMVP, false, mesh.getMVP());
    gl.uniformMatrix3fv(uniforms.uN, false, mesh.getN());

    ShaderBase.updateUniforms.call(this, render, main);
  };

  return ShaderNormal;
});<|endoftext|>


<commit_before>g_lastSaved = -1;

function MessagePanel(message)
{
	this.message = message;
	this.createContents = function(parentId)
	{
		var messageId = this.message.createId("li");

		elementById(parentId).append(createElement("li", {id :messageId, tweetid : this.message.tweetId}));
		elementById(messageId).append(createElement("span", {id:this.message.createId("span")}, this.message.text));
		var spanId = this.message.createId("span");
		elementById(spanId).click(
			function() {
				elementById(spanId).css('display', 'none');
				elementById(inputId).val(elementById(spanId).text()).css('display',
						'').focus();
			});
		var inputId = this.message.createId("input");
		elementById(messageId).append(createElement("input", {id:inputId, style:"display: none;"}));
		elementById(inputId).blur(function(){handleEdit(this.message);});
        elementById(inputId).keydown(function(event){
            if (event.which == 13)
            {
                handleEdit(this.message);
            }
        });
        var successIconId = this.message.createId("successIconSpan");
        var successIconDisplayId = this.message.id == g_lastSaved ? "display: '';" : "display: none;";

        elementById(messageId).append(createElement("span", {id:successIconId, style:successIconDisplayId}));
        elementById(successIconId).append(createElement("img", {alt:"Saved", src:"icons/success.png"}));

		if (this.message.tweetId == -1) {
		    var removeId = this.message.createId("removeIcon");
			elementById(messageId).append(createElement("span", {
				id : removeId,
				onclick : "onDelete(" + this.message.id + ")"
			}));
			elementById(removeId).append(createElement("img", {
			    alt : "Delete",
			    src : "icons/remove.png"}));

			var tweetId = this.message.createId("tweetIcon");
			elementById(messageId).append(createElement("span",{
			   id : tweetId}));
			elementById(tweetId).click(function(){
			   onTweet(this.message);
			});
			elementById(tweetId).append(createElement("img", {
			   alt : "Tweet", src:"https://twitter.com/images/b2_btn_icon.gif"}));
		}

		elementById(messageId).append(createElement("div", {
					style : "font-size: 50%;"
				}, "Last modified: " + formatDate(this.message.lastsave)));
	};

	this.handleEdit = function(message) {
		var inputId = message.createId("input");
		elementById(inputId).css('display', 'none');
		var newText = elementById(inputId).val();
		var spanId = message.createId("span");
		elementById(spanId).text(newText).css('display', '');
		message.message = newText;
		editBookmark(message, function() {
			g_lastSaved = message.id;
			readBookmarks(onRefreshSuccess);
		});
	};
}

function elementById(id)
{
	return $("#"+id);
}<commit_msg>Fix editing issue.<commit_after>g_lastSaved = -1;

function MessagePanel(message)
{
	this.message = message;
	this.createContents = function(parentId)
	{
		var messageId = this.message.createId("li");

		elementById(parentId).append(createElement("li", {id :messageId, tweetid : this.message.tweetId}));
		elementById(messageId).append(createElement("span", {id:this.message.createId("span")}, this.message.text));
		var spanId = this.message.createId("span");
		elementById(spanId).click(
			function() {
				elementById(spanId).css('display', 'none');
				elementById(inputId).val(elementById(spanId).text()).css('display',
						'').focus();
			});
		var inputId = this.message.createId("input");
		elementById(messageId).append(createElement("input", {id:inputId, style:"display: none;"}));
		var outer = this;
		elementById(inputId).blur(function(){outer.handleEdit(message);});
        elementById(inputId).keydown(function(event){
            if (event.which == 13)
            {
                outer.handleEdit(message);
            }
        });
        var successIconId = this.message.createId("successIconSpan");
        var successIconDisplayId = this.message.id == g_lastSaved ? "display: '';" : "display: none;";

        elementById(messageId).append(createElement("span", {id:successIconId, style:successIconDisplayId}));
        elementById(successIconId).append(createElement("img", {alt:"Saved", src:"icons/success.png"}));

		if (this.message.tweetId == -1) {
		    var removeId = this.message.createId("removeIcon");
			elementById(messageId).append(createElement("span", {
				id : removeId,
				onclick : "onDelete(" + this.message.id + ")"
			}));
			elementById(removeId).append(createElement("img", {
			    alt : "Delete",
			    src : "icons/remove.png"}));

			var tweetId = this.message.createId("tweetIcon");
			elementById(messageId).append(createElement("span",{
			   id : tweetId}));
			elementById(tweetId).click(function(){
			   onTweet(this.message);
			});
			elementById(tweetId).append(createElement("img", {
			   alt : "Tweet", src:"https://twitter.com/images/b2_btn_icon.gif"}));
		}

		elementById(messageId).append(createElement("div", {
					style : "font-size: 50%;"
				}, "Last modified: " + formatDate(this.message.lastsave)));
	};

	this.handleEdit = function(message) {
		var inputId = message.createId("input");
		elementById(inputId).css('display', 'none');
		var newText = elementById(inputId).val();
		var spanId = message.createId("span");
		elementById(spanId).text(newText).css('display', '');
		message.text = newText;
		editMessage(message, function() {
			g_lastSaved = message.id;
			readMessages(onRefreshSuccess);
		});
	};
}

function elementById(id)
{
	return $("#"+id);
}<|endoftext|>


<commit_before>import { zipSync, strToU8 } from '../libs/fflate.module.min.js';

class USDZExporter {

	parse( scene ) {

		let output = buildHeader();

		const materials = {};

		scene.traverse( ( object ) => {

			if ( object.isMesh ) {

				materials[ object.material.uuid ] = object.material;
				output += buildXform( object, buildMesh( object.geometry, object.material ) );

			}

		} );

		output += buildMaterials( materials );

		return zipSync( { 'model.usda': strToU8( output ) }, { level: 0 } );

	}

}

//

function buildHeader() {

	return `#usda 1.0
(
    doc = "Three.js"
    metersPerUnit = 1
    upAxis = "Y"
)

`;

}

// Xform

function buildXform( object, define ) {

	const name = object.name || 'Xform1';
	const transform = buildMatrix( object.matrixWorld );

	return `def Xform "${ name }"
{
    matrix4d xformOp:transform = ${ transform }
    uniform token[] xformOpOrder = ["xformOp:transform"]

    ${ define }
}

`;

}

function buildMatrix( matrix ) {

	const array = matrix.elements;

	return `( ${ buildMatrixRow( array, 0 ) }, ${ buildMatrixRow( array, 4 ) }, ${ buildMatrixRow( array, 8 ) }, ${ buildMatrixRow( array, 12 ) } )`;

}

function buildMatrixRow( array, offset ) {

	return `(${ array[ offset + 0 ] }, ${ array[ offset + 1 ] }, ${ array[ offset + 2 ] }, ${ array[ offset + 3 ] })`;

}

// Mesh

function buildMesh( geometry, material ) {

	const name = geometry.name || 'Mesh1';
	const attributes = geometry.attributes;
	const count = attributes.position.count;

	return `def Mesh "${ name }"
    {
        int[] faceVertexCounts = [${ buildMeshVertexCount( geometry ) }]
        int[] faceVertexIndices = [${ buildMeshVertexIndices( geometry ) }]
        rel material:binding = </_materials/Material_${ material.id }>
        normal3f[] normals = [${ buildVector3Array( attributes.normal, count )}] (
            interpolation = "faceVarying"
        )
        point3f[] points = [${ buildVector3Array( attributes.position, count )}]
        texCoord2f[] primvars:UVMap = [${ buildVector2Array( attributes.uv, count )}] (
            interpolation = "faceVarying"
        )
        uniform token subdivisionScheme = "none"
    }
`;

}

function buildMeshVertexCount( geometry ) {

	const count = geometry.index !== null ? geometry.index.array.length : geometry.attributes.position.count;

	return Array( count / 3 ).fill( 3 ).join( ', ' );

}

function buildMeshVertexIndices( geometry ) {

	if ( geometry.index !== null ) {

		return geometry.index.array.join( ', ' );

	}

	const array = [];
	const length = geometry.attributes.position.count;

	for ( let i = 0; i < length; i ++ ) {

		array.push( i );

	}

	return array.join( ', ' );

}

function buildVector3Array( attribute, count ) {

	if ( attribute === undefined ) {

		console.warn( 'USDZExporter: Normals missing.' );
		return Array( count ).fill( '(0, 0, 0)' ).join( ', ' );

	}

	const array = [];
	const data = attribute.array;

	for ( let i = 0; i < data.length; i += 3 ) {

		array.push( `(${ data[ i + 0 ] }, ${ data[ i + 1 ] }, ${ data[ i + 2 ] })` );

	}

	return array.join( ', ' );

}

function buildVector2Array( attribute, count ) {

	if ( attribute === undefined ) {

		console.warn( 'USDZExporter: UVs missing.' );
		return Array( count ).fill( '(0, 0)' ).join( ', ' );

	}

	const array = [];
	const data = attribute.array;

	for ( let i = 0; i < data.length; i += 2 ) {

		array.push( `(${ data[ i + 0 ] }, ${ data[ i + 1 ] })` );

	}

	return array.join( ', ' );

}

// Materials

function buildMaterials( materials ) {

	const array = [];

	for ( const uuid in materials ) {

		const material = materials[ uuid ];

		array.push( buildMaterial( material ) );

	}

	return `def "_materials"
{
${ array.join( '' ) }
}

`;

}

function buildMaterial( material ) {

	return `
    def Material "Material_${ material.id }"
    {
        token outputs:surface.connect = </_materials/Material_${ material.id }/previewShader.outputs:surface>

        def Shader "previewShader"
        {
            uniform token info:id = "UsdPreviewSurface"
            color3f inputs:diffuseColor = ${ buildColor( material.color ) }
            float inputs:metallic = ${ material.metalness }
            float inputs:roughness = ${ material.roughness }
            token outputs:surface
        }
    }
`;

}

function buildColor( color ) {

	return `(${ color.r }, ${ color.g }, ${ color.b })`;

}

export { USDZExporter };
<commit_msg>USDZExporter: Fixed exporting Xforms with duplicated names.<commit_after>import { zipSync, strToU8 } from '../libs/fflate.module.min.js';

class USDZExporter {

	parse( scene ) {

		let output = buildHeader();

		const materials = {};

		scene.traverse( ( object ) => {

			if ( object.isMesh ) {

				materials[ object.material.uuid ] = object.material;
				output += buildXform( object, buildMesh( object.geometry, object.material ) );

			}

		} );

		output += buildMaterials( materials );

		return zipSync( { 'model.usda': strToU8( output ) }, { level: 0 } );

	}

}

//

function buildHeader() {

	return `#usda 1.0
(
    doc = "Three.js"
    metersPerUnit = 1
    upAxis = "Y"
)

`;

}

// Xform

function buildXform( object, define ) {

	const name = 'Object' + object.id;
	const transform = buildMatrix( object.matrixWorld );

	return `def Xform "${ name }"
{
    matrix4d xformOp:transform = ${ transform }
    uniform token[] xformOpOrder = ["xformOp:transform"]

    ${ define }
}

`;

}

function buildMatrix( matrix ) {

	const array = matrix.elements;

	return `( ${ buildMatrixRow( array, 0 ) }, ${ buildMatrixRow( array, 4 ) }, ${ buildMatrixRow( array, 8 ) }, ${ buildMatrixRow( array, 12 ) } )`;

}

function buildMatrixRow( array, offset ) {

	return `(${ array[ offset + 0 ] }, ${ array[ offset + 1 ] }, ${ array[ offset + 2 ] }, ${ array[ offset + 3 ] })`;

}

// Mesh

function buildMesh( geometry, material ) {

	const name = 'Geometry' + geometry.id;
	const attributes = geometry.attributes;
	const count = attributes.position.count;

	return `def Mesh "${ name }"
    {
        int[] faceVertexCounts = [${ buildMeshVertexCount( geometry ) }]
        int[] faceVertexIndices = [${ buildMeshVertexIndices( geometry ) }]
        rel material:binding = </_materials/Material_${ material.id }>
        normal3f[] normals = [${ buildVector3Array( attributes.normal, count )}] (
            interpolation = "faceVarying"
        )
        point3f[] points = [${ buildVector3Array( attributes.position, count )}]
        texCoord2f[] primvars:UVMap = [${ buildVector2Array( attributes.uv, count )}] (
            interpolation = "faceVarying"
        )
        uniform token subdivisionScheme = "none"
    }
`;

}

function buildMeshVertexCount( geometry ) {

	const count = geometry.index !== null ? geometry.index.array.length : geometry.attributes.position.count;

	return Array( count / 3 ).fill( 3 ).join( ', ' );

}

function buildMeshVertexIndices( geometry ) {

	if ( geometry.index !== null ) {

		return geometry.index.array.join( ', ' );

	}

	const array = [];
	const length = geometry.attributes.position.count;

	for ( let i = 0; i < length; i ++ ) {

		array.push( i );

	}

	return array.join( ', ' );

}

function buildVector3Array( attribute, count ) {

	if ( attribute === undefined ) {

		console.warn( 'USDZExporter: Normals missing.' );
		return Array( count ).fill( '(0, 0, 0)' ).join( ', ' );

	}

	const array = [];
	const data = attribute.array;

	for ( let i = 0; i < data.length; i += 3 ) {

		array.push( `(${ data[ i + 0 ] }, ${ data[ i + 1 ] }, ${ data[ i + 2 ] })` );

	}

	return array.join( ', ' );

}

function buildVector2Array( attribute, count ) {

	if ( attribute === undefined ) {

		console.warn( 'USDZExporter: UVs missing.' );
		return Array( count ).fill( '(0, 0)' ).join( ', ' );

	}

	const array = [];
	const data = attribute.array;

	for ( let i = 0; i < data.length; i += 2 ) {

		array.push( `(${ data[ i + 0 ] }, ${ data[ i + 1 ] })` );

	}

	return array.join( ', ' );

}

// Materials

function buildMaterials( materials ) {

	const array = [];

	for ( const uuid in materials ) {

		const material = materials[ uuid ];

		array.push( buildMaterial( material ) );

	}

	return `def "_materials"
{
${ array.join( '' ) }
}

`;

}

function buildMaterial( material ) {

	return `
    def Material "Material_${ material.id }"
    {
        token outputs:surface.connect = </_materials/Material_${ material.id }/previewShader.outputs:surface>

        def Shader "previewShader"
        {
            uniform token info:id = "UsdPreviewSurface"
            color3f inputs:diffuseColor = ${ buildColor( material.color ) }
            float inputs:metallic = ${ material.metalness }
            float inputs:roughness = ${ material.roughness }
            token outputs:surface
        }
    }
`;

}

function buildColor( color ) {

	return `(${ color.r }, ${ color.g }, ${ color.b })`;

}

export { USDZExporter };
<|endoftext|>


<commit_before>/**
 * Paginator class module
 * @module classes/Paginator
 */

'use strict';

// var _ = require('lodash');
var Display = require('./Display');
var Page = require('./Page');
var parser = require('./paginator/parser');

var errors = require('./paginator/errors'),
  InvalidPageRankError = errors.InvalidPageRankError;

/**
 * Paginator is the page manager
 * @constructor
 * @param {string} pageFormatLabel The label of the paper format for all pages. For example, 'A4'
 * @param {string} pageOrientation The label of the orientation for all pages. May be 'portait' or 'landscape'
 * @param {DOMDocument} doc The document given by editor.getDoc() of the tinymce API
 *
 * @example
 paginator = new Paginator('A4','portait', editor.getDoc());
 *
 * @see utils/page-formats
 */
function Paginator(pageFormatLabel, pageOrientation, ed){

  editor = ed;
  /**
   * The DOMDocument given in the constructor
   * @property {DOMDocument}
   * @private
   */
  this._document = ed.getDoc();
  /**
   * The Display to manage screen and dimensions
   * @property {Display}
   * @private
   */
  this._display = new Display(this._document);
  /**
   * The default abstract page from all real pages inherits
   * @property {Page}
   * @private
   */
  this._defaultPage = new Page(pageFormatLabel, pageOrientation);
  /**
   * The body element of the full document
   * @property {Element}
   * @private
   */
  this._body = this._document.getElementsByTagName('body');

}

/**
 * The current page
 * @property {Page}
 * @private
 */
var currentPage;

/**
 * The list of pages
 * @property {Array}
 * @private
 */
var pages = [];

/**
 * Current editor
 * @property {Editor}
 * @private
 */
var editor;

/**
 * Get the current page
 * @method
 * @return {Page} the current page loaded in editor
 */
Paginator.prototype.getCurrentPage = function(){
  return currentPage;
};

/**
 * Get the page with the given rank
 * @method
 * @param {Number} rank The requested page rank
 * @return {Page} The requested page
 */
Paginator.prototype.getPage = function(rank){
  if (!pages.length)
    throw new Error('Paginator pages length in null. Can\'t iterate on it.');

  var isLower = rank-1 < 0;
  var isGreater = rank-1 > pages.length;

  if (isLower || isGreater) throw new InvalidPageRankError(rank);
  else return pages[rank-1];
};

/**
 * Get all pages in paginator
 * @method
 * @return {Array<Page>} all paginator pages
 */
Paginator.prototype.getPages = function(){
  return pages;
};

/**
 * Return the previous page
 * @method
 * @return {Page} The previous page
 */
Paginator.prototype.getPrevious = function(){
  try {
    console.log('this.getCurrentPage()',currentPage);
    return this.getPage(this.getCurrentPage().rank-1);
  } catch(err) {
    console.error(err.stck);
    return null;
  }
};

/**
 * Get the next page
 * @method
 * @return {Page} The next page
 */
Paginator.prototype.getNext = function(){
  try {
    return this.getPage(this.getCurrentPage().rank+1);
  } catch(err) {
    return null;
  }
};

/**
 * Navigate to the given page
 * @method
 * @param {Page} the page to navigate to
 * @return void
 */
Paginator.prototype.gotoPage = function(toPage){

  // Show the destination page
  $(toPage._content).css({ 'display': 'block' });

  // Hide all other pages
  $.each(pages,function(i, loopPage){
    if (toPage.rank !== loopPage.rank) {
      $(loopPage._content).css({ 'display': 'none' });
    }
  });

  currentPage = toPage;

};

/**
 * Get the currently focused page div
 * @method
 * @private
 * @return {Element} The parent div element having an attribute data-paginator
 */
var _getFocusedPageDiv = function(){
  var selectedElement = editor.selection.getRng().startContainer;
  var parents = editor.dom.getParents(selectedElement,'div',editor.getDoc().body);
  var ret;
  $.each(parents,function(i,parent){
    if ($(parent).attr('data-paginator')) {
      ret = parent;
    }
  });
  if (!ret) throw new Error('No parent page found ! You are out of a page.');
  else return ret;
};

/**
 * Go to the page having the focus
 * @method
 * @return void
 */
Paginator.prototype.gotoFocusedPage = function(){
  var focusedDiv = _getFocusedPageDiv.call(this);
  var pageRank = $(focusedDiv).attr('data-paginator-page-rank');
  var focusedPage = this.getPage(pageRank);
  currentPage = focusedPage;
  this.gotoPage(focusedPage);
};

/**
 * Navigate to the previous page
 * @method
 * @return {Page} The previous page after navigation is done
 */
Paginator.prototype.gotoPrevious = function(){
  console.info('goto previous page');
  return this.gotoPage(this.getPrevious());
};

/**
 * Navigate to the next page
 * @method
 * @return {Page} The next page after navigation is done
 */
Paginator.prototype.gotoNext = function(){
  console.info('goto next page');
  return this.gotoPage(this.getNext());
};

/**
 * Watch the current page, to check if content overflows the page's max-height.
 * @method
 * @return void
 */
Paginator.prototype.watchPage = function(){

  var maxHeight = Math.ceil(_getPageInnerHeight.call(this));
  var currentHeight = Number($(currentPage.content()).css('height').split('px').join(''));

  if (currentHeight > maxHeight) {
    alert('Dépassement de page !');
    _repage.call();
  }

};

};

/**
 * Get the current computed padding
 * @method
 * @private
 * @return {object}
 */
var _getDocPadding = function(){
  var that = this;
  return {
    top: $(that._body).css('padding-top'),
    right: $(that._body).css('padding-right'),
    bottom: $(that._body).css('padding-bottom'),
    left: $(that._body).css('padding-left')
  };
}

/**
 * Compute the page inner height in pixels
 * @method
 * @private
 * @return {Number} The resulted height in pixels
 */
var _getPageInnerHeight = function(){

  var outerHeight = Number(this._display.mm2px(this._defaultPage.height)*10); // @TODO (*10) is a bug fix
  var docPadding = _getDocPadding.call(this);
  var paddingTop = Number(docPadding.top.split('px').join(''));
  var paddingBottom = Number(docPadding.bottom.split('px').join(''));

  var innerHeight = outerHeight - paddingTop - paddingBottom;

  return innerHeight-1 // -1 because of a bug in border-bottom pdf rendering
};

/**
 * Initialize the paginator
 * @method
 * @return void
 */
Paginator.prototype.init = function(){
  function findPageWrappers(){
    return $('div[data-paginator-page-rank]',that._body);
  }
  var that = this;

  // search the paginator page wrappers
  var wrappedPages = findPageWrappers();
  var wrapper = $('<div>');
  wrapper.attr({
    'data-paginator': true,
    'data-paginator-page-rank': 1
  }).css({
    'page-break-after': 'always',
    'height': _getPageInnerHeight.call(that),
    // 'border': 'solid red 1px',
    // 'background': 'yellow',
    'overflow': 'hidden'
  });

  // wrap unwrapped content
  if (!wrappedPages.length){
    $(this._body).wrapInner(wrapper);
    wrappedPages = findPageWrappers();
  }

  pages = [];
  $.each(wrappedPages,function(i,el){
    pages.push(new Page(that._defaultPage.format().label, that._defaultPage.orientation, i+1, el));
  });

};

/**
 * Paginator class
 */
module.exports = Paginator;
<commit_msg>fix comments doc and typos<commit_after>/**
 * Paginator class module
 * @module classes/Paginator
 */

'use strict';

// var _ = require('lodash');
var Display = require('./Display');
var Page = require('./Page');
var parser = require('./paginator/parser');

var errors = require('./paginator/errors'),
  InvalidPageRankError = errors.InvalidPageRankError;

/**
 * Paginator is the page manager
 * @constructor
 * @param {string} pageFormatLabel The label of the paper format for all pages. For example, 'A4'
 * @param {string} pageOrientation The label of the orientation for all pages. May be 'portait' or 'landscape'
 * @param {DOMDocument} doc The document given by editor.getDoc() of the tinymce API
 *
 * @example
 paginator = new Paginator('A4','portait', editor.getDoc());
 *
 * @see utils/page-formats
 */
function Paginator(pageFormatLabel, pageOrientation, ed){

  editor = ed;
  /**
   * The DOMDocument given in the constructor
   * @property {DOMDocument}
   * @private
   */
  this._document = ed.getDoc();
  /**
   * The Display to manage screen and dimensions
   * @property {Display}
   * @private
   */
  this._display = new Display(this._document);
  /**
   * The default abstract page from all real pages inherits
   * @property {Page}
   * @private
   */
  this._defaultPage = new Page(pageFormatLabel, pageOrientation);
  /**
   * The body element of the full document
   * @property {Element}
   * @private
   */
  this._body = this._document.getElementsByTagName('body');

}

/**
 * The current page
 * @property {Page}
 * @private
 */
var currentPage;

/**
 * The list of pages
 * @property {Array}
 * @private
 */
var pages = [];

/**
 * Current editor
 * @property {Editor}
 * @private
 */
var editor;

/**
 * Get the current page
 * @method
 * @return {Page} the current page loaded in editor
 */
Paginator.prototype.getCurrentPage = function(){
  return currentPage;
};

/**
 * Get the page with the given rank
 * @method
 * @param {Number} rank The requested page rank
 * @return {Page} The requested page
 */
Paginator.prototype.getPage = function(rank){
  if (!pages.length)
    throw new Error('Paginator pages length in null. Can\'t iterate on it.');

  var isLower = rank-1 < 0;
  var isGreater = rank-1 > pages.length;

  if (isLower || isGreater) throw new InvalidPageRankError(rank);
  else return pages[rank-1];
};

/**
 * Get all pages in paginator
 * @method
 * @return {Array<Page>} all paginator pages
 */
Paginator.prototype.getPages = function(){
  return pages;
};

/**
 * Return the previous page
 * @method
 * @return {Page} The previous page
 */
Paginator.prototype.getPrevious = function(){
  try {
    console.log('this.getCurrentPage()',currentPage);
    return this.getPage(this.getCurrentPage().rank-1);
  } catch(err) {
    console.error(err.stck);
    return null;
  }
};

/**
 * Get the next page
 * @method
 * @return {Page} The next page
 */
Paginator.prototype.getNext = function(){
  try {
    return this.getPage(this.getCurrentPage().rank+1);
  } catch(err) {
    return null;
  }
};

/**
 * Navigate to the given page
 * @method
 * @param {Page} the page to navigate to
 * @return void
 */
Paginator.prototype.gotoPage = function(toPage){

  // Show the destination page
  $(toPage._content).css({ 'display': 'block' });

  // Hide all other pages
  $.each(pages,function(i, loopPage){
    if (toPage.rank !== loopPage.rank) {
      $(loopPage._content).css({ 'display': 'none' });
    }
  });

  currentPage = toPage;

};

/**
 * Get the currently focused page div
 * @method
 * @private
 * @return {Element} The parent div element having an attribute data-paginator
 */
var _getFocusedPageDiv = function(){
  var selectedElement = editor.selection.getRng().startContainer;
  var parents = editor.dom.getParents(selectedElement,'div',editor.getDoc().body);
  var ret;
  $.each(parents,function(i,parent){
    if ($(parent).attr('data-paginator')) {
      ret = parent;
    }
  });
  if (!ret) throw new Error('No parent page found ! You are out of a page.');
  else return ret;
};

/**
 * Go to the page having the focus
 * @method
 * @return void
 */
Paginator.prototype.gotoFocusedPage = function(){
  var focusedDiv = _getFocusedPageDiv.call(this);
  var pageRank = $(focusedDiv).attr('data-paginator-page-rank');
  var focusedPage = this.getPage(pageRank);
  currentPage = focusedPage;
  this.gotoPage(focusedPage);
};

/**
 * Navigate to the previous page
 * @method
 * @return {Page} The previous page after navigation is done
 */
Paginator.prototype.gotoPrevious = function(){
  console.info('goto previous page');
  return this.gotoPage(this.getPrevious());
};

/**
 * Navigate to the next page
 * @method
 * @return {Page} The next page after navigation is done
 */
Paginator.prototype.gotoNext = function(){
  console.info('goto next page');
  return this.gotoPage(this.getNext());
};

/**
 * Watch the current page, to check if content overflows the page's max-height.
 * @method
 * @return void
 */
Paginator.prototype.watchPage = function(){

  var maxHeight = Math.ceil(_getPageInnerHeight.call(this));
  var currentHeight = Number($(currentPage.content()).css('height').split('px').join(''));

  if (currentHeight > maxHeight) {
    alert('Dépassement de page !');
    _repage.call();
  }

};

};

/**
 * Get the current computed padding
 * @method
 * @private
 * @return {object}
 */
var _getDocPadding = function(){
  var that = this;
  return {
    top: $(that._body).css('padding-top'),
    right: $(that._body).css('padding-right'),
    bottom: $(that._body).css('padding-bottom'),
    left: $(that._body).css('padding-left')
  };
};

/**
 * Compute the page inner height in pixels. It must maches the height of the `div[data-paginator]` block.
 * @method
 * @private
 * @return {Number} The resulted height in pixels.
 */
var _getPageInnerHeight = function(){

  var outerHeight = Number(this._display.mm2px(this._defaultPage.height)*10); // @TODO (*10) is a bug fix
  var docPadding = _getDocPadding.call(this);
  var paddingTop = Number(docPadding.top.split('px').join(''));
  var paddingBottom = Number(docPadding.bottom.split('px').join(''));

  var innerHeight = outerHeight - paddingTop - paddingBottom;

  return innerHeight-1 // -1 because of a bug in border-bottom pdf rendering
};

/**
 * Initialize the paginator. The editor and its content has to be loaded before initialize the paginator
 * @method
 * @return void
 */
Paginator.prototype.init = function(){
  function findPageWrappers(){
    return $('div[data-paginator-page-rank]',that._body);
  }
  var that = this;

  // search the paginator page wrappers
  var wrappedPages = findPageWrappers();
  var wrapper = $('<div>');
  wrapper.attr({
    'data-paginator': true,
    'data-paginator-page-rank': 1
  }).css({
    'page-break-after': 'always',
    'height': _getPageInnerHeight.call(that),
    // 'border': 'solid red 1px',
    // 'background': 'yellow',
    'overflow': 'hidden'
  });

  // wrap unwrapped content
  if (!wrappedPages.length){
    $(this._body).wrapInner(wrapper);
    wrappedPages = findPageWrappers();
  }

  pages = [];
  $.each(wrappedPages,function(i,el){
    pages.push(new Page(that._defaultPage.format().label, that._defaultPage.orientation, i+1, el));
  });

};

/**
 * Paginator class
 */
module.exports = Paginator;
<|endoftext|>


<commit_before>// var Classes = (function () {
// 	var Classes ={};

	var Ship =(function () {
		function Ship (x, y, orientation, length) {
			this.x =x;
			this.y =y;
			this.orientation = orientation;	// vertical - true, horizontal - false
			this.length = length;
			this.hp =[];

			if (this.len ==5)
				this.type = "Aircraft Carrier";
			else if (this.len ==4)
				this.type = "Battleship";
			else if (this.len ==3)
				this.type = "Submarine";
			else if (this.len ==2)
				this.type = "Cruiser";
			else if (this.len ==1)
				this.type = "Patrol Boat";
			else
				this.type = "Unknown";

			for (var i = this.length - 1; i >= 0; i--) {
				this.hp.push(true);
			}
		}

		{}.defineProperty(Ship.prototype, "isDead", {
			get: function(){
				for (var i = this.hp.length - 1; i >= 0; i--)
					if (this.hp[i] ==true)
						return false;

				return true;
			},
			enumerable: true,
			configurable: true
		});

		return Ship;
	})();

	var Set =(function () {
		function Set (ships) {
			//0 empty space
			//1 ship
			//2 killed ship
			//3 missed shot
			this.map = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0].
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
			this.ships = ships || [];

			// locates all ships on map
			for (var i = this.ships.length - 1; i >= 0; i--) {
				this.locate(this.ships[i])
			}
		}

		Set.prototype.locate = function(ship) {
			if(ship.orientation == 'v'){
				for(int i =0; i <ship.length; i++){
					try{
						if(this.map[ship.y +i][ship.x] ==0)
							this.map[ship.y +i][ship.x] =1;
						else
							throw new Error("Ship you are trying to locate collides with another ship");
					}
					catch(error){
						console.log(error);
						return 1;
					}
				}
			}
			else if(ship.orientation == 'h'){
				for(int i =0; i <ship.length; i++){
					try{
						if(this.map[ship.y][ship.x +i] ==0)
							this.map[ship.y][ship.x +1] =1;
						else
							throw new Error("Ship you are trying to locate collides with another ship");
					}
					catch(error){
						console.log(error);
						return 1;
					}
				}
			}

		};

		return Set;
	})();

	var Player =(function () {
		function Player(nick, status, set){
			this.nick =nick;
			this.set =set || new Set();
			this.status = status || "pending";	// pending or playing
		}

		Player.prototype.attackedBy = function(opponent, x, y) {
			if(this.set.map[y][x] ==0){
				this.set.map[y][x] =3;
				return 0;
			}
			else if(this.set.map[y][x] ==1){
				this.set.map[y][x] =2;
				return 1;
			}
			else if(this.set.map[y][x] ==2)
				return 2;
			else if(this.set.map[y][x] ==3)
				return 3;
			else
				return -1;		//fail
		};

		return Ship;
	})();

// 	Classes.Ship = Ship;
// 	Classes.Set = Set;
// 	Classes.Player = Player;

// 	return Classes;
// })();<commit_msg>classes.js<commit_after>// var Classes = (function () {
// 	var Classes ={};

	var Ship =(function () {
		function Ship (x, y, orientation, length) {
			this.x =x;
			this.y =y;
			this.orientation = orientation;	// vertical - true, horizontal - false
			this.length = length;
			this.hp =[];

			if (this.len ==5)
				this.type = "Aircraft Carrier";
			else if (this.len ==4)
				this.type = "Battleship";
			else if (this.len ==3)
				this.type = "Submarine";
			else if (this.len ==2)
				this.type = "Cruiser";
			else if (this.len ==1)
				this.type = "Patrol Boat";
			else
				this.type = "Unknown";

			for (var i = this.length - 1; i >= 0; i--) {
				this.hp.push(true);
			}
		}

		Object.defineProperty(Ship.prototype, "isDead", {
			get: function(){
				for (var i = this.hp.length - 1; i >= 0; i--)
					if (this.hp[i] ==true)
						return false;

				return true;
			},
			enumerable: true,
			configurable: true
		});

		return Ship;
	})();

	var Set =(function () {
		function Set (ships) {
			//0 empty space
			//1 ship
			//2 killed ship
			//3 missed shot
			this.map = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
			this.ships = ships || [];

			// locates all ships on map
			for (var i = this.ships.length - 1; i >= 0; i--) {
				this.locate(this.ships[i])
			}
		}

		Set.prototype.locate = function(ship) {
			if(ship.orientation == 'v'){
				for(var i =0; i <ship.length; i++){
					try{
						if(this.map[ship.y +i][ship.x] ==0)
							this.map[ship.y +i][ship.x] =1;
						else
							throw new Error("Ship you are trying to locate collides with another ship");
					}
					catch(error){
						console.log(error);
						return 1;
					}
				}
			}
			else if(ship.orientation == 'h'){
				for(var i =0; i <ship.length; i++){
					try{
						if(this.map[ship.y][ship.x +i] ==0)
							this.map[ship.y][ship.x +1] =1;
						else
							throw new Error("Ship you are trying to locate collides with another ship");
					}
					catch(error){
						console.log(error);
						return 1;
					}
				}
			}

		};

		return Set;
	})();

	var Player =(function () {
		function Player(nick, status, set){
			this.nick =nick;
			this.set =set || new Set();
			this.status = status || "pending";	// pending or playing
		}

		Player.prototype.attackedBy = function(opponent, x, y) {
			if(this.set.map[y][x] ==0){
				this.set.map[y][x] =3;
				return 0;
			}
			else if(this.set.map[y][x] ==1){
				this.set.map[y][x] =2;
				return 1;
			}
			else if(this.set.map[y][x] ==2)
				return 2;
			else if(this.set.map[y][x] ==3)
				return 3;
			else
				return -1;		//fail
		};

		return Ship;
	})();

	function letter2digit (letter) {
		switch(letter){
			case "A":
				return 0;
			case "B":
				return 1;
			case "C":
				return 2;
			case "D":
				return 3;
			case "E":
				return 4;
			case "F":
				return 5;
			case "G":
				return 6;
			case "H":
				return 7;
			case "I":
				return 8;
			case "J":
				return 9;
		}
	}

// 	Classes.Ship = Ship;
// 	Classes.Set = Set;
// 	Classes.Player = Player;

// 	return Classes;
// })();<|endoftext|>


<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
const { mocha, expect } = require('../common');
const convertToReadings = require('../../services/Pipeline/convertToReadings');
const Reading = require('../../models/Reading');
const moment = require('moment');

mocha.describe('Convert data', () => {
	mocha.it('array of reading & moment to array of Reading values', async () => {
		let sampleArray = [ [ 0, moment('1980-01-01 00:00:00'), moment('1990-01-01 00:00:00') ],
							[ 1, moment('2000-01-01 00:00:00'), moment('2000-01-01 00:00:00') ],
							[ 2, moment('2010-01-01 00:00:00'), moment('2020-01-01 00:00:00') ]];
		let result = convertToReadings(sampleArray, undefined, -Number.MAX_VALUE, Number.MAX_VALUE, null, null, null, 0);
		for (let i = 0; i < result.length; ++i) {
			expect(result[i].reading).to.equal(sampleArray[i][0]);
			expect(result[i].startTimeStamp).to.equal(sampleArray[i][1]);
			expect(result[i].endTimeStamp).to.equal(sampleArray[i][2]);
		}
	});
});
<commit_msg>debug convertToReading<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
const { mocha, expect } = require('../common');
const convertToReadings = require('../../services/Pipeline/convertToReadings');
const Reading = require('../../models/Reading');
const moment = require('moment');

mocha.describe('Convert data', () => {
	mocha.it('array of reading & moment to array of Reading values', async () => {
		let sampleArray = [ [ 0, moment('1980-01-01 00:00:00'), moment('1990-01-01 00:00:00') ],
							[ 1, moment('2000-01-01 00:00:00'), moment('2000-01-01 00:00:00') ],
							[ 2, moment('2010-01-01 00:00:00'), moment('2020-01-01 00:00:00') ]];
		let result = convertToReadings(sampleArray, undefined, -Number.MAX_VALUE, Number.MAX_VALUE, null, null, null, 0);
		for (let i = 0; i < result.length; ++i) {
			expect(result[i].reading).to.equal(sampleArray[i][0]);
			expect(result[i].startTimeStamp.isSame(sampleArray[i][1])).to.equal(true);
			expect(result[i].endTimeStamp.isSame(sampleArray[i][2])).to.equal(true);
		}
	});
});
<|endoftext|>


<commit_before>const stringify = require('../../dist/util/stringify');

describe('util/stringify', () => {
  it('should convert strings', () => {
    stringify('abc').should.be.exactly('"abc"');
  });

  it('should convert strings without quotation marks', () => {
    stringify('abc', false).should.be.exactly('abc');
  });

  it('should convert numbers', () => {
    stringify(234).should.be.exactly('234');
    stringify(1.23).should.be.exactly('1.23');
  });

  it('should convert booleans', () => {
    stringify(true).should.be.exactly('true');
    stringify(false).should.be.exactly('false');
  });

  it('should convert lists', () => {
    stringify([true, 1, 'abc']).should.be.exactly('[true, 1, "abc"]');
    stringify([[1, 3], 3, 6]).should.be.exactly('[[1, 3], 3, 6]');
    stringify([]).should.be.exactly('[]');
  });

  it('should convert sets', () => {
    const set1 = new Set([true, 1, 'abc']);
    stringify(set1).should.be.exactly('{true, 1, "abc"}');
    const set2 = new Set([new Set([1, 3]), 3, 6]);
    stringify(set2).should.be.exactly('{{1, 3}, 3, 6}');
    stringify(new Set()).should.be.exactly('{}');
  });
});
<commit_msg>use immutable in stringify tests<commit_after>import 'should';
import Immutable, { Set, List } from 'immutable';
import stringify from '../../src/util/stringify';

describe('util/stringify', () => {
  it('should convert strings', () => {
    stringify('abc').should.be.exactly('"abc"');
  });

  it('should convert strings without quotation marks', () => {
    stringify('abc', false).should.be.exactly('abc');
  });

  it('should convert numbers', () => {
    stringify(234).should.be.exactly('234');
    stringify(1.23).should.be.exactly('1.23');
  });

  it('should convert booleans', () => {
    stringify(true).should.be.exactly('true');
    stringify(false).should.be.exactly('false');
  });

  it('should convert lists', () => {
    stringify(List.of(true, 1, 'abc')).should.be.exactly('[true, 1, "abc"]');
    stringify(Immutable.fromJS([[1, 3], 3, 6])).should.be.exactly('[[1, 3], 3, 6]');
    stringify(List()).should.be.exactly('[]');
  });

  it('should convert sets', () => {
    const set1 = Set.of(true, 1, 'abc');
    stringify(set1).should.be.exactly('{true, 1, "abc"}');
    const set2 = Set.of(Set.of(1, 3), 3, 6);
    stringify(set2).should.be.exactly('{{1, 3}, 3, 6}');
    stringify(Set()).should.be.exactly('{}');
  });
});
<|endoftext|>


<commit_before>import React from 'react';
import {
  Image,
  StyleSheet,
  View,
  Dimensions,
  TouchableOpacity,
} from 'react-native';
import RNFS from 'react-native-fs';
import Sound from 'react-native-sound';
import IconIonicons from 'react-native-vector-icons/Ionicons';

export default class MessageAudio extends React.Component {
   constructor(props) {
    super(props);
    this.onActionsPress = this.onActionsPress.bind(this);
  }

  onActionsPress() {
    // console.log(this.props.currentMessage.audio);
    setTimeout(() => {
      var path = RNFS.CachesDirectoryPath+'/audioMsg_'+new Date().getTime()+'.aac';
      RNFS.writeFile(path, this.props.currentMessage.audio, 'base64')
          .then((success) => {
            var whoosh = new Sound(path, "", (error) => {
              if (error) {
                console.log('failed to load the sound', error);
                return;
              }
              // loaded successfully
              console.log('duration in seconds: ' + whoosh.getDuration() + 'number of channels: ' + whoosh.getNumberOfChannels());
              setTimeout(() => {
                // Play the sound with an onEnd callback
                whoosh.play((success) => {
                  if (success) {
                    console.log('successfully finished playing');
                  } else {
                    console.log('playback failed due to audio decoding errors');
                  }
                });
              }, 100);
            });
          })
          .catch((err) => {
            console.log(err.message);
          });
    }, 100);
  }

  render() {
    const { width, height } = Dimensions.get('window');

    return (
      <View style={[styles.container, this.props.containerStyle]}>
        <TouchableOpacity
          style={[styles.audio, this.props.audioStyle]}
          onPress={this.onActionsPress}
        >
          <IconIonicons name="ios-play" size={30} color="#FFFFFF" />
        </TouchableOpacity>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
  },
  audio: {
    width: 100,
    height: 30,
    alignItems:'center',
  },
});

MessageAudio.defaultProps = {
  currentMessage: {
    image: null,
  },
  containerStyle: {},
  audioStyle: {},
  audioProps: {},
};

MessageAudio.propTypes = {
  currentMessage: React.PropTypes.object,
  containerStyle: View.propTypes.style,
  audioStyle: Image.propTypes.style,
  audioProps: React.PropTypes.object,
};
<commit_msg>play icon color change<commit_after>import React from 'react';
import {
  Image,
  StyleSheet,
  View,
  Dimensions,
  TouchableOpacity,
} from 'react-native';
import RNFS from 'react-native-fs';
import Sound from 'react-native-sound';
import IconIonicons from 'react-native-vector-icons/Ionicons';

export default class MessageAudio extends React.Component {
   constructor(props) {
    super(props);
    this.onActionsPress = this.onActionsPress.bind(this);
  }

  onActionsPress() {
    // console.log(this.props.currentMessage.audio);
    setTimeout(() => {
      var path = RNFS.CachesDirectoryPath+'/audioMsg_'+new Date().getTime()+'.aac';
      RNFS.writeFile(path, this.props.currentMessage.audio, 'base64')
          .then((success) => {
            var whoosh = new Sound(path, "", (error) => {
              if (error) {
                console.log('failed to load the sound', error);
                return;
              }
              // loaded successfully
              console.log('duration in seconds: ' + whoosh.getDuration() + 'number of channels: ' + whoosh.getNumberOfChannels());
              setTimeout(() => {
                // Play the sound with an onEnd callback
                whoosh.play((success) => {
                  if (success) {
                    console.log('successfully finished playing');
                  } else {
                    console.log('playback failed due to audio decoding errors');
                  }
                });
              }, 100);
            });
          })
          .catch((err) => {
            console.log(err.message);
          });
    }, 100);
  }

  render() {
    const { width, height } = Dimensions.get('window');

    return (
      <View style={[styles.container, this.props.containerStyle]}>
        <TouchableOpacity
          style={[styles.audio, this.props.audioStyle]}
          onPress={this.onActionsPress}
        >
          <IconIonicons name="ios-play" size={30} color="#000000" />
        </TouchableOpacity>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
  },
  audio: {
    width: 100,
    height: 30,
    alignItems:'center',
  },
});

MessageAudio.defaultProps = {
  currentMessage: {
    image: null,
  },
  containerStyle: {},
  audioStyle: {},
  audioProps: {},
};

MessageAudio.propTypes = {
  currentMessage: React.PropTypes.object,
  containerStyle: View.propTypes.style,
  audioStyle: Image.propTypes.style,
  audioProps: React.PropTypes.object,
};
<|endoftext|>


<commit_before>var $ = require('../internals/export');
var getBuiltIn = require('../internals/get-built-in');
var fails = require('../internals/fails');

var $stringify = getBuiltIn('JSON', 'stringify');
var reg = /[\uD800-\uDFFF]/g;
var re = /^[\uD800-\uDFFF]$/;
var low = /^[\uD800-\uDBFF]$/;
var hi = /^[\uDC00-\uDFFF]$/;

var fix = function (string) {
  var result = '';
  var length = string.length;
  var i = 0;
  var point, prev, next;
  for (; i < length; i++) {
    point = string.charAt(i);
    if (re.test(point)) {
      prev = string.charAt(i - 1);
      next = string.charAt(i + 1);
      if ((low.test(point) && !hi.test(next)) || (hi.test(point) && !low.test(prev))) {
        result += '\\u' + point.charCodeAt(0).toString(16);
        continue;
      }
    } result += point;
  } return result;
};

var FORCED = fails(function () {
  return $stringify('\uDF06\uD834') !== '"\\udf06\\ud834"'
    || $stringify('\uDEAD') !== '"\\udead"';
});

if ($stringify) {
  // https://github.com/tc39/proposal-well-formed-stringify
  $({ target: 'JSON', stat: true, forced: FORCED }, {
    // eslint-disable-next-line no-unused-vars
    stringify: function stringify(it, replacer, space) {
      var result = $stringify.apply(null, arguments);
      return typeof result == 'string' && reg.test(result) ? fix(result) : result;
    }
  });
}
<commit_msg>simplify with `.replace`<commit_after>var $ = require('../internals/export');
var getBuiltIn = require('../internals/get-built-in');
var fails = require('../internals/fails');

var $stringify = getBuiltIn('JSON', 'stringify');
var re = /[\uD800-\uDFFF]/g;
var low = /^[\uD800-\uDBFF]$/;
var hi = /^[\uDC00-\uDFFF]$/;

var fix = function (match, offset, string) {
  var prev = string.charAt(offset - 1);
  var next = string.charAt(offset + 1);
  if ((low.test(match) && !hi.test(next)) || (hi.test(match) && !low.test(prev))) {
    return '\\u' + match.charCodeAt(0).toString(16);
  } return match;
};

var FORCED = fails(function () {
  return $stringify('\uDF06\uD834') !== '"\\udf06\\ud834"'
    || $stringify('\uDEAD') !== '"\\udead"';
});

if ($stringify) {
  // https://github.com/tc39/proposal-well-formed-stringify
  $({ target: 'JSON', stat: true, forced: FORCED }, {
    // eslint-disable-next-line no-unused-vars
    stringify: function stringify(it, replacer, space) {
      var result = $stringify.apply(null, arguments);
      return typeof result == 'string' ? result.replace(re, fix) : result;
    }
  });
}
<|endoftext|>