<commit_before>(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,d=e.filter,g=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,j=i.bind,w=function(n){return n instanceof w?n:this instanceof w?(this._wrapped=n,void 0):new w(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=w),exports._=w):n._=w,w.VERSION="1.4.4";var A=w.each=w.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(w.has(n,a)&&t.call(e,n[a],a,n)===r)return};w.map=w.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e[e.length]=t.call(r,n,u,i)}),e)};var O="Reduce of empty array with no initial value";w.reduce=w.foldl=w.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=w.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},w.reduceRight=w.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=w.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=w.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},w.find=w.detect=function(n,t,r){var e;return E(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},w.filter=w.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&(e[e.length]=n)}),e)},w.reject=function(n,t,r){return w.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},w.every=w.all=function(n,t,e){t||(t=w.identity);var u=!0;return null==n?u:g&&n.every===g?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var E=w.some=w.any=function(n,t,e){t||(t=w.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};w.contains=w.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:E(n,function(n){return n===t})},w.invoke=function(n,t){var r=o.call(arguments,2),e=w.isFunction(t);return w.map(n,function(n){return(e?t:n[t]).apply(n,r)})},w.pluck=function(n,t){return w.map(n,function(n){return n[t]})},w.where=function(n,t,r){return w.isEmpty(t)?r?null:[]:w[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},w.findWhere=function(n,t){return w.where(n,t,!0)},w.max=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.max.apply(Math,n);if(!t&&w.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>=e.computed&&(e={value:n,computed:a})}),e.value},w.min=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.min.apply(Math,n);if(!t&&w.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;e.computed>a&&(e={value:n,computed:a})}),e.value},w.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=w.random(r++),e[r-1]=e[t],e[t]=n}),e};var k=function(n){return w.isFunction(n)?n:function(t){return t[n]}};w.sortBy=function(n,t,r){var e=k(t);return w.pluck(w.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index<t.index?-1:1}),"value")};var F=function(n,t,r,e){var u={},i=k(t||w.identity);return A(n,function(t,a){var o=i.call(r,t,a,n);e(u,o,t)}),u};w.groupBy=function(n,t,r){return F(n,t,r,function(n,t,r){(w.has(n,t)?n[t]:n[t]=[]).push(r)})},w.countBy=function(n,t,r){return F(n,t,r,function(n,t){w.has(n,t)||(n[t]=0),n[t]++})},w.sortedIndex=function(n,t,r,e){r=null==r?w.identity:k(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;u>r.call(e,n[o])?i=o+1:a=o}return i},w.toArray=function(n){return n?w.isArray(n)?o.call(n):n.length===+n.length?w.map(n,w.identity):w.values(n):[]},w.size=function(n){return null==n?0:n.length===+n.length?n.length:w.keys(n).length},w.first=w.head=w.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},w.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},w.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},w.rest=w.tail=w.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},w.compact=function(n){return w.filter(n,w.identity)};var R=function(n,t,r){return A(n,function(n){w.isArray(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r};w.flatten=function(n,t){return R(n,t,[])},w.without=function(n){return w.difference(n,o.call(arguments,1))},w.uniq=w.unique=function(n,t,r,e){w.isFunction(t)&&(e=r,r=t,t=!1);var u=r?w.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:w.contains(a,r))||(a.push(r),i.push(n[e]))}),i},w.union=function(){return w.uniq(c.apply(e,arguments))},w.intersection=function(n){var t=o.call(arguments,1);return w.filter(w.uniq(n),function(n){return w.every(t,function(t){return w.indexOf(t,n)>=0})})},w.difference=function(n){var t=c.apply(e,o.call(arguments,1));return w.filter(n,function(n){return!w.contains(t,n)})},w.zip=function(){for(var n=o.call(arguments),t=w.max(w.pluck(n,"length")),r=Array(t),e=0;t>e;e++)r[e]=w.pluck(n,""+e);return r},w.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},w.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=w.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},w.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},w.range=function(n,t,r){1>=arguments.length&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=Array(e);e>u;)i[u++]=n,n+=r;return i},w.bind=function(n,t){if(n.bind===j&&j)return j.apply(n,o.call(arguments,1));var r=o.call(arguments,2);return function(){return n.apply(t,r.concat(o.call(arguments)))}},w.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},w.bindAll=function(n){var t=o.call(arguments,1);return 0===t.length&&(t=w.functions(n)),A(t,function(t){n[t]=w.bind(n[t],n)}),n},w.memoize=function(n,t){var r={};return t||(t=w.identity),function(){var e=t.apply(this,arguments);return w.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},w.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},w.defer=function(n){return w.delay.apply(w,[n,1].concat(o.call(arguments,1)))},w.throttle=function(n,t){var r,e,u,i,a=0,o=function(){a=new Date,u=null,i=n.apply(r,e)};return function(){var c=new Date,l=t-(c-a);return r=this,e=arguments,0>=l?(clearTimeout(u),u=null,a=c,i=n.apply(r,e)):u||(u=setTimeout(o,l)),i}},w.debounce=function(n,t,r){var e,u;return function(){var i=this,a=arguments,o=function(){e=null,r||(u=n.apply(i,a))},c=r&&!e;return clearTimeout(e),e=setTimeout(o,t),c&&(u=n.apply(i,a)),u}},w.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},w.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},w.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},w.after=function(n,t){return 0>=n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},w.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)w.has(n,r)&&(t[t.length]=r);return t},w.values=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push(n[r]);return t},w.pairs=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push([r,n[r]]);return t},w.invert=function(n){var t={};for(var r in n)w.has(n,r)&&(t[n[r]]=r);return t},w.functions=w.methods=function(n){var t=[];for(var r in n)w.isFunction(n[r])&&t.push(r);return t.sort()},w.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},w.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},w.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)w.contains(r,u)||(t[u]=n[u]);return t},w.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)null==n[r]&&(n[r]=t[r])}),n},w.clone=function(n){return w.isObject(n)?w.isArray(n)?n.slice():w.extend({},n):n},w.tap=function(n,t){return t(n),n};var I=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof w&&(n=n._wrapped),t instanceof w&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==t+"";case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;r.push(n),e.push(t);var a=0,o=!0;if("[object Array]"==u){if(a=n.length,o=a==t.length)for(;a--&&(o=I(n[a],t[a],r,e)););}else{var c=n.constructor,f=t.constructor;if(c!==f&&!(w.isFunction(c)&&c instanceof c&&w.isFunction(f)&&f instanceof f))return!1;for(var s in n)if(w.has(n,s)&&(a++,!(o=w.has(t,s)&&I(n[s],t[s],r,e))))break;if(o){for(s in t)if(w.has(t,s)&&!a--)break;o=!a}}return r.pop(),e.pop(),o};w.isEqual=function(n,t){return I(n,t,[],[])},w.isEmpty=function(n){if(null==n)return!0;if(w.isArray(n)||w.isString(n))return 0===n.length;for(var t in n)if(w.has(n,t))return!1;return!0},w.isElement=function(n){return!(!n||1!==n.nodeType)},w.isArray=x||function(n){return"[object Array]"==l.call(n)},w.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){w["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),w.isArguments(arguments)||(w.isArguments=function(n){return!(!n||!w.has(n,"callee"))}),"function"!=typeof/./&&(w.isFunction=function(n){return"function"==typeof n}),w.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},w.isNaN=function(n){return w.isNumber(n)&&n!=+n},w.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},w.isNull=function(n){return null===n},w.isUndefined=function(n){return n===void 0},w.has=function(n,t){return f.call(n,t)},w.noConflict=function(){return n._=t,this},w.identity=function(n){return n},w.times=function(n,t,r){for(var e=Array(n),u=0;n>u;u++)e[u]=t.call(r,u);return e},w.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var M={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};M.unescape=w.invert(M.escape);var S={escape:RegExp("["+w.keys(M.escape).join("")+"]","g"),unescape:RegExp("("+w.keys(M.unescape).join("|")+")","g")};w.each(["escape","unescape"],function(n){w[n]=function(t){return null==t?"":(""+t).replace(S[n],function(t){return M[n][t]})}}),w.result=function(n,t){if(null==n)return null;var r=n[t];return w.isFunction(r)?r.call(n):r},w.mixin=function(n){A(w.functions(n),function(t){var r=w[t]=n[t];w.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),D.call(this,r.apply(w,n))}})};var N=0;w.uniqueId=function(n){var t=++N+"";return n?n+t:t},w.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var T=/(.)^/,q={"'":"'","\\":"\\","\r":"r","\n":"n","	":"t","\u2028":"u2028","\u2029":"u2029"},B=/\\|'|\r|\n|\t|\u2028|\u2029/g;w.template=function(n,t,r){var e;r=w.defaults({},r,w.templateSettings);var u=RegExp([(r.escape||T).source,(r.interpolate||T).source,(r.evaluate||T).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(B,function(n){return"\\"+q[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,w);var c=function(n){return e.call(this,n,w)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},w.chain=function(n){return w(n).chain()};var D=function(n){return this._chain?w(n).chain():n};w.mixin(w),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];w.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],D.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];w.prototype[n]=function(){return D.call(this,t.apply(this._wrapped,arguments))}}),w.extend(w.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this);
<commit_msg>first commit<commit_after><|endoftext|>


<commit_before>/**
 * @fileoverview test plot
 * @author NHN Ent.
 *         FE Development Lab <dl_javascript@nhnent.com>
 */

'use strict';

var Plot = require('../../src/js/plots/plot.js');
var dom = require('../../src/js/helpers/domHandler.js');
var renderUtil = require('../../src/js/helpers/renderUtil.js');

describe('Test for Plot', function() {
    var plot, boundsMaker;

    beforeAll(function() {
        boundsMaker = jasmine.createSpyObj('boundsMaker', ['getPosition', 'getDimension']);
    });
    beforeEach(function() {
        plot = new Plot({
            boundsMaker: boundsMaker,
            theme: {
                lineColor: 'black'
            }
        });

    });

    describe('_renderPlotArea()', function() {
        it('plotContainer와 dimension정보를 renderDimension()에 전달하여 너비 높이를 렌더링 합니다. ', function() {
            boundsMaker.getDimension.and.returnValue({
                width: 400,
                height: 300
            });
            spyOn(renderUtil, 'renderDimension');
            spyOn(renderUtil, 'renderPosition');
            spyOn(plot, '_renderLines');

            plot._renderPlotArea('plotContainer');

            expect(renderUtil.renderDimension).toHaveBeenCalledWith('plotContainer', {
                width: 400,
                height: 300
            });
        });

        it('전달된 데이터는 plot.data에 할당됩니다.', function() {
            spyOn(renderUtil, 'renderDimension');
            spyOn(renderUtil, 'renderPosition');
            spyOn(plot, '_renderLines');

            plot._renderPlotArea('plotContainer', 'data');

            expect(plot.data).toBe('data');
        });

        it('options.showLine을 설정하지 않으면 기본값이 true로 설정되어 line을 렌더링 합니다.', function() {
            boundsMaker.getDimension.and.returnValue({
                width: 400,
                height: 300
            });
            spyOn(renderUtil, 'renderDimension');
            spyOn(renderUtil, 'renderPosition');
            spyOn(plot, '_renderLines');

            plot._renderPlotArea('plotContainer');

            expect(plot._renderLines).toHaveBeenCalledWith('plotContainer', {
                width: 400,
                height: 300
            });
        });

        it('options.showLine이 false이면 _renderLines()을 호출하지 않습니다.', function() {
            boundsMaker.getDimension.and.returnValue({
                width: 400,
                height: 300
            });
            spyOn(renderUtil, 'renderDimension');
            spyOn(renderUtil, 'renderPosition');
            spyOn(plot, '_renderLines');
            plot.options = {
                showLine: false
            };

            plot._renderPlotArea('plotContainer');

            expect(plot._renderLines).not.toHaveBeenCalled();
        });
    });

    describe('_renderLines()', function() {
        it('vTickCount=5 width=400인 경우에는 시작 라인을 제외한 4개의 가로라인(horizontal)을 라인을 50px(or 40px) 간격으로 아래에서 부터 렌더링합니다.', function() {
            var el = dom.create('DIV'),
                childNodes;
            plot.bound = {
                dimension: {width: 400, height: 200},
                position: {top: 5, right: 5}
            };
            plot.data = {
                vTickCount: 5
            };
            plot._renderLines(el, plot.bound.dimension);
            childNodes = el.childNodes;

            expect(childNodes.length).toBe(4);
            expect(dom.hasClass(childNodes[0], 'horizontal')).toBe(true);
            expect(dom.hasClass(childNodes[3], 'horizontal')).toBe(true);
            expect(childNodes[3].style.bottom).toBe('199px');
            expect(childNodes[0].style.bottom).toBe('49.75px');
            expect(childNodes[1].style.bottom).toBe('99.5px');
            expect(childNodes[2].style.bottom).toBe('149.25px');
            expect(childNodes[0].style.width).toBe('400px');
            expect(childNodes[3].style.width).toBe('400px');
        });
    });

    describe('_makeLineHtml()', function() {
        it('position(라인 각각의 위치), size(라인 높이 or 너비), className(vertical or horizontal), positionType (left or top), sizeType(width or height) 정보를 이용하여 세로라인 html을 생성합니다.', function() {
            var positions = [10, 20, 30, 40],
                size = 200,
                className = 'vertical',
                positionType = 'left',
                sizeType = 'height',
                resultHtml = plot._makeLineHtml({
                    positions: positions,
                    size: size,
                    className: className,
                    positionType: positionType,
                    sizeType: sizeType
                }),
                compareHtml = '

' +
                    '

' +
                    '

' +
                    '

';
            expect(resultHtml).toBe(compareHtml);
        });
    });

    describe('_makeVerticalPixelPositions()', function() {
        it('vTickCount=5, size=200의 세로 라인들의 pixel타입 위치 정보(position.left)를 반환([50, 100, 149, 199])합니다.', function() {
            var positions;
            plot.data = {
                vTickCount: 5
            };
            positions = plot._makeVerticalPixelPositions(200);
            expect(positions).toEqual([49.75, 99.5, 149.25, 199]);
        });

        it('vTickCount=0일 경우에는 빈 배열을 반환합니다.', function() {
            var positions;
            plot.data = {
                vTickCount: 0
            };
            positions = plot._makeVerticalPixelPositions(200);
            expect(positions).toEqual([]);
        });
    });

    describe('_makeDividedPlotPositions()', function() {
        it('divided 옵션(yAxis 중앙 배치)에 따라 plot line position을 재계산 합니다.', function() {
            var actual, expected;

            boundsMaker.getDimension.and.returnValue({
                width: 50
            });
            plot.data.hTickCount = 8;

            actual = plot._makeDividedPlotPositions(400);
            expected = [0, 43.5, 87, 130.5, 268.5, 312, 355.5, 399];

            expect(actual).toEqual(expected);
        });
    });

    describe('_makeHorizontalPixelPositions()', function() {
        it('hTickCount=5, size=200의 가로 라인들의 pixel타입 위치 정보(position.top)를 반환([50, 100, 149, 199])합니다.', function() {
            var positions;
            plot.data = {
                hTickCount: 5
            };
            positions = plot._makeHorizontalPixelPositions(200);
            expect(positions).toEqual([49.75, 99.5, 149.25, 199]);
        });

        it('hTickCount=0일 경우에는 빈 배열을 반환합니다.', function() {
            var positions;
            plot.data = {
                hTickCount: 0
            };
            positions = plot._makeHorizontalPixelPositions(200);
            expect(positions).toEqual([]);
        });

        it('divided옵션이 true인 경우 _makeDividedPlotPositions()의 수행 결과를 반환합니다.', function() {
            var actual, expected;

            boundsMaker.getDimension.and.returnValue({
                width: 50
            });
            plot.options.divided = true;
            plot.data.hTickCount = 7;
            actual = plot._makeHorizontalPixelPositions(350);
            expected = plot._makeDividedPlotPositions(350);

            expect(actual).toEqual(expected);
        });
    });

    describe('render()', function() {
        it('vTickCount=5 width=400, height=200인 plot 영역은 시작 라인을 제외한 4개의 가로라인(horizontal)을 라인을 50px(or 40px) 간격으로 렌더링합니다.', function() {
            var container, childNodes;

            boundsMaker.getPosition.and.returnValue({
                top: 5,
                left: 5
            });
            boundsMaker.getDimension.and.returnValue({
                width: 400,
                height: 200
            });
            container = plot.render({
                vTickCount: 5
            });

            expect(container.style.width).toBe('400px');
            expect(container.style.height).toBe('200px');
            expect(container.style.top).toBe('5px');
            expect(container.style.left).toBe('5px');
            expect(container.className).toBe('tui-chart-plot-area');

            childNodes = container.childNodes;

            expect(childNodes.length).toBe(4);
            expect(dom.hasClass(childNodes[0], 'horizontal')).toBe(true);
            expect(dom.hasClass(childNodes[3], 'horizontal')).toBe(true);
            expect(childNodes[3].style.bottom).toBe('199px');
            expect(childNodes[0].style.bottom).toBe('49.75px');
            expect(childNodes[1].style.bottom).toBe('99.5px');
            expect(childNodes[2].style.bottom).toBe('149.25px');
            expect(childNodes[0].style.width).toBe('400px');
            expect(childNodes[3].style.width).toBe('400px');
        });
    });
});
<commit_msg>test: Fix test<commit_after>/**
 * @fileoverview test plot
 * @author NHN Ent.
 *         FE Development Lab <dl_javascript@nhnent.com>
 */

'use strict';

var Plot = require('../../src/js/plots/plot.js');
var dom = require('../../src/js/helpers/domHandler.js');
var renderUtil = require('../../src/js/helpers/renderUtil.js');

describe('Test for Plot', function() {
    var plot, boundsMaker;

    beforeAll(function() {
        boundsMaker = jasmine.createSpyObj('boundsMaker', ['getPosition', 'getDimension']);
    });
    beforeEach(function() {
        plot = new Plot({
            boundsMaker: boundsMaker,
            theme: {
                lineColor: 'black'
            }
        });

    });

    describe('_renderPlotArea()', function() {
        it('plotContainer와 dimension정보를 renderDimension()에 전달하여 너비 높이를 렌더링 합니다. ', function() {
            boundsMaker.getDimension.and.returnValue({
                width: 400,
                height: 300
            });
            spyOn(renderUtil, 'renderDimension');
            spyOn(renderUtil, 'renderPosition');
            spyOn(plot, '_renderLines');

            plot._renderPlotArea('plotContainer');

            expect(renderUtil.renderDimension).toHaveBeenCalledWith('plotContainer', {
                width: 400,
                height: 300
            });
        });

        it('전달된 데이터는 plot.data에 할당됩니다.', function() {
            spyOn(renderUtil, 'renderDimension');
            spyOn(renderUtil, 'renderPosition');
            spyOn(plot, '_renderLines');

            plot._renderPlotArea('plotContainer', 'data');

            expect(plot.data).toBe('data');
        });

        it('options.showLine을 설정하지 않으면 기본값이 true로 설정되어 line을 렌더링 합니다.', function() {
            boundsMaker.getDimension.and.returnValue({
                width: 400,
                height: 300
            });
            spyOn(renderUtil, 'renderDimension');
            spyOn(renderUtil, 'renderPosition');
            spyOn(plot, '_renderLines');

            plot._renderPlotArea('plotContainer');

            expect(plot._renderLines).toHaveBeenCalledWith('plotContainer', {
                width: 400,
                height: 300
            });
        });

        it('options.showLine이 false이면 _renderLines()을 호출하지 않습니다.', function() {
            boundsMaker.getDimension.and.returnValue({
                width: 400,
                height: 300
            });
            spyOn(renderUtil, 'renderDimension');
            spyOn(renderUtil, 'renderPosition');
            spyOn(plot, '_renderLines');
            plot.options = {
                showLine: false
            };

            plot._renderPlotArea('plotContainer');

            expect(plot._renderLines).not.toHaveBeenCalled();
        });
    });

    describe('_renderLines()', function() {
        it('vTickCount=5 width=400인 경우에는 시작 라인을 제외한 4개의 가로라인(horizontal)을 라인을 50px(or 40px) 간격으로 아래에서 부터 렌더링합니다.', function() {
            var el = dom.create('DIV'),
                childNodes;
            plot.bound = {
                dimension: {width: 400, height: 200},
                position: {top: 5, right: 5}
            };
            plot.data = {
                vTickCount: 5
            };
            plot._renderLines(el, plot.bound.dimension);
            childNodes = el.childNodes;

            expect(childNodes.length).toBe(4);
            expect(dom.hasClass(childNodes[0], 'horizontal')).toBe(true);
            expect(dom.hasClass(childNodes[3], 'horizontal')).toBe(true);
            expect(childNodes[0].style.bottom).toBe('50px');
            expect(childNodes[1].style.bottom).toBe('100px');
            expect(childNodes[2].style.bottom).toBe('150px');
            expect(childNodes[3].style.bottom).toBe('199px');
            expect(childNodes[0].style.width).toBe('400px');
            expect(childNodes[3].style.width).toBe('400px');
        });
    });

    describe('_makeLineHtml()', function() {
        it('position(라인 각각의 위치), size(라인 높이 or 너비), className(vertical or horizontal), positionType (left or top), sizeType(width or height) 정보를 이용하여 세로라인 html을 생성합니다.', function() {
            var positions = [10, 20, 30, 40],
                size = 200,
                className = 'vertical',
                positionType = 'left',
                sizeType = 'height',
                resultHtml = plot._makeLineHtml({
                    positions: positions,
                    size: size,
                    className: className,
                    positionType: positionType,
                    sizeType: sizeType
                }),
                compareHtml = '

' +
                    '

' +
                    '

' +
                    '

';
            expect(resultHtml).toBe(compareHtml);
        });
    });

    describe('_makeVerticalPixelPositions()', function() {
        it('vTickCount=5, size=200의 세로 라인들의 pixel타입 위치 정보(position.left)를 반환([50, 100, 149, 199])합니다.', function() {
            var positions;
            plot.data = {
                vTickCount: 5
            };
            positions = plot._makeVerticalPixelPositions(200);
            expect(positions).toEqual([50, 100, 150, 199]);
        });

        it('vTickCount=0일 경우에는 빈 배열을 반환합니다.', function() {
            var positions;
            plot.data = {
                vTickCount: 0
            };
            positions = plot._makeVerticalPixelPositions(200);
            expect(positions).toEqual([]);
        });
    });

    describe('_makeDividedPlotPositions()', function() {
        it('divided 옵션(yAxis 중앙 배치)에 따라 plot line position을 재계산 합니다.', function() {
            var actual, expected;

            boundsMaker.getDimension.and.returnValue({
                width: 50
            });
            plot.data.hTickCount = 8;

            actual = plot._makeDividedPlotPositions(400);
            expected = [0, 43.75, 87.5, 131.25, 268.75, 312.5, 356.25, 399];

            expect(actual).toEqual(expected);
        });
    });

    describe('_makeHorizontalPixelPositions()', function() {
        it('hTickCount=5, size=200의 가로 라인들의 pixel타입 위치 정보(position.top)를 반환([50, 100, 149, 199])합니다.', function() {
            var positions;
            plot.data = {
                hTickCount: 5
            };
            positions = plot._makeHorizontalPixelPositions(200);
            expect(positions).toEqual([50, 100, 150, 199]);
        });

        it('hTickCount=0일 경우에는 빈 배열을 반환합니다.', function() {
            var positions;
            plot.data = {
                hTickCount: 0
            };
            positions = plot._makeHorizontalPixelPositions(200);
            expect(positions).toEqual([]);
        });

        it('divided옵션이 true인 경우 _makeDividedPlotPositions()의 수행 결과를 반환합니다.', function() {
            var actual, expected;

            boundsMaker.getDimension.and.returnValue({
                width: 50
            });
            plot.options.divided = true;
            plot.data.hTickCount = 7;
            actual = plot._makeHorizontalPixelPositions(350);
            expected = plot._makeDividedPlotPositions(350);

            expect(actual).toEqual(expected);
        });
    });

    describe('render()', function() {
        it('vTickCount=5 width=400, height=200인 plot 영역은 시작 라인을 제외한 4개의 가로라인(horizontal)을 라인을 50px(or 40px) 간격으로 렌더링합니다.', function() {
            var container, childNodes;

            boundsMaker.getPosition.and.returnValue({
                top: 5,
                left: 5
            });
            boundsMaker.getDimension.and.returnValue({
                width: 400,
                height: 200
            });
            container = plot.render({
                vTickCount: 5
            });

            expect(container.style.width).toBe('400px');
            expect(container.style.height).toBe('200px');
            expect(container.style.top).toBe('5px');
            expect(container.style.left).toBe('5px');
            expect(container.className).toBe('tui-chart-plot-area');

            childNodes = container.childNodes;

            expect(childNodes.length).toBe(4);
            expect(dom.hasClass(childNodes[0], 'horizontal')).toBe(true);
            expect(dom.hasClass(childNodes[3], 'horizontal')).toBe(true);
            expect(childNodes[0].style.bottom).toBe('50px');
            expect(childNodes[1].style.bottom).toBe('100px');
            expect(childNodes[2].style.bottom).toBe('150px');
            expect(childNodes[3].style.bottom).toBe('199px');
            expect(childNodes[0].style.width).toBe('400px');
            expect(childNodes[3].style.width).toBe('400px');
        });
    });
});
<|endoftext|>


<commit_before>var gulp = require('gulp'),
    browserify = require('browserify'),
    tsify = require('tsify'),
    buffer = require('vinyl-buffer'),
    source = require('vinyl-source-stream'),
    watchify = require('watchify'),
    nodemon = require("gulp-nodemon"),
    paths = {src: "src/", build:"build/", tmp:"tmp/"},
    mainFile = "start.ts",
    version = "0.0.1";

var srcCodeBundler = browserify({debug:true}).add(paths.src+mainFile).plugin(tsify),
    watchifyBundler = watchify(browserify({debug:true}).add(paths.src+mainFile).plugin(tsify));

function transpile(bundler){
    return function()
    { return bundler.bundle()
        .on('error', function(error){console.error(error.toString()); })
        .pipe(source('build-'+version+'.js'))
        .pipe(buffer())
        .pipe(gulp.dest(paths.build));
    }
}

gulp.task('transpile', transpile(srcCodeBundler));

gulp.task('watchify', transpile(watchifyBundler));

gulp.task('watch', ['transpile'], function() {
    gulp.watch(paths.src+'**/*.ts', ['watchify']);
});

gulp.task("server", ["transpile"],  function () {
   return nodemon({
       script: "src/server/main.js",
       ext: 'js'
   }).once('quit', function(){
       process.exit();
   });
});

gulp.task('default', ['transpile']);<commit_msg>* added start server only gulp task<commit_after>var gulp = require('gulp'),
    browserify = require('browserify'),
    tsify = require('tsify'),
    buffer = require('vinyl-buffer'),
    source = require('vinyl-source-stream'),
    watchify = require('watchify'),
    nodemon = require("gulp-nodemon"),
    paths = {src: "src/", build:"build/", tmp:"tmp/"},
    mainFile = "start.ts",
    version = "0.0.1";

var srcCodeBundler = browserify({debug:true}).add(paths.src+mainFile).plugin(tsify),
    watchifyBundler = watchify(browserify({debug:true}).add(paths.src+mainFile).plugin(tsify));

function transpile(bundler){
    return function()
    { return bundler.bundle()
        .on('error', function(error){console.error(error.toString()); })
        .pipe(source('build-'+version+'.js'))
        .pipe(buffer())
        .pipe(gulp.dest(paths.build));
    }
}

gulp.task('transpile', transpile(srcCodeBundler));

gulp.task('watchify', transpile(watchifyBundler));

gulp.task('watch', ['transpile'], function() {
    gulp.watch(paths.src+'**/*.ts', ['watchify']);
});

gulp.task("server", ["transpile"],  function () {
   return nodemon({
       script: "src/server/main.js",
       ext: 'js'
   }).once('quit', function(){
       process.exit();
   });
});

gulp.task("server-only",  function () {
    return nodemon({
        script: "src/server/main.js",
        ext: 'js'
    }).once('quit', function(){
        process.exit();
    });
});

gulp.task('default', ['transpile']);<|endoftext|>


<commit_before>// User menu toggle
$("#dropdown-menu a").on("click", function(event) {
    $(this).parent().toggleClass("open");
});
$("body").on("click", function(event) {
    if(!$("#dropdown-menu").is(event.target) && $("#dropdown-menu").has(event.target).length === 0) {
        $("#dropdown-menu").removeClass("open");
    }
});

function piholeChanged(action)
{
    const status = $("#status");
    const ena = $("#pihole-enable");
    const dis = $("#pihole-disable");

    switch(action) {
        case "enabled":
        status.html(" Active");
        ena.hide();
        dis.show();
        dis.removeClass("active");
        break;

        case "disabled":
        status.html(" Offline");
        ena.show();
        dis.hide();
        break;
    }

}

function piholeChange(action, duration)
{
    const token = encodeURIComponent($("#token").html());
    var btnStatus;

    switch(action) {
        case "enable":
        btnStatus = $("#flip-status-enable");
        btnStatus.html(" ");
        $.getJSON("api.php?enable&token=" + token, (data) => {
            if(data.status === "enabled") {
                btnStatus.html("");
                piholeChanged("enabled");
            }
        });
        break;

        case "disable":
        btnStatus = $("#flip-status-disable");
        btnStatus.html(" ");
        $.getJSON("api.php?disable=" + duration + "&token=" + token, (data) => {
            if(data.status === "disabled") {
                btnStatus.html("");
                piholeChanged("disabled");
            }
        });
        break;
    }
}

// Handle Enable/Disable
$("#pihole-enable").on("click", (e) => {
    e.preventDefault();
    piholeChange("enable","");
});
$("#pihole-disable-permanently").on("click", (e) => {
    e.preventDefault();
    piholeChange("disable","0");
});
$("#pihole-disable-10s").on("click", (e) => {
    e.preventDefault();
    piholeChange("disable","10");
    setTimeout(function(){piholeChanged("enabled");},10000);
});
$("#pihole-disable-30s").on("click", (e) => {
    e.preventDefault();
    piholeChange("disable","30");
    setTimeout(function(){piholeChanged("enabled");},30000);
});
$("#pihole-disable-5m").on("click", (e) => {
    e.preventDefault();
    piholeChange("disable","300");
    setTimeout(function(){piholeChanged("enabled");},300000);
});

var piholeVersion = $("#piholeVersion").html();
var webVersion = $("#webVersion").html();

// Credit for following function: https://gist.github.com/alexey-bass/1115557
// Modified to discard any possible "v" in the string
function versionCompare(left, right) {
    if (typeof left + typeof right !== "stringstring")
    {
        return false;
    }

    // If we are on vDev then we assume that it is always
    // newer than the latest online release, i.e. version
    // comparison should return 1
    if(left === "vDev")
    {
        return 1;
    }

    var aa = left.split("v"),
        bb = right.split("v");

    var a = aa[aa.length-1].split(".")
        ,   b = bb[bb.length-1].split(".")
        ,   i = 0, len = Math.max(a.length, b.length);

    for (; i < len; i++) {
        if ((a[i] && !b[i] && parseInt(a[i]) > 0) || (parseInt(a[i]) > parseInt(b[i]))) {
            return 1;
        } else if ((b[i] && !a[i] && parseInt(b[i]) > 0) || (parseInt(a[i]) < parseInt(b[i]))) {
            return -1;
        }
    }
    return 0;
}

// Update check
$.getJSON("https://api.github.com/repos/pi-hole/pi-hole/releases/latest", function(json) {
    if(versionCompare(piholeVersion, json.tag_name.slice(1)) < 0) {
        // Alert user
        $("#piholeVersion").html($("#piholeVersion").text() + "(Update available!)");
        $("#alPiholeUpdate").show();
    }
});
$.getJSON("https://api.github.com/repos/pi-hole/AdminLTE/releases/latest", function(json) {
    if(versionCompare(webVersion, json.tag_name.slice(1)) < 0) {
        // Alert user
        $("#webVersion").html($("#webVersion").text() + "(Update available!)");
        $("#alWebUpdate").show();
    }
});

/*
 * Make sure that Pi-hole is updated to at least v2.7, since that is needed to use the sudo
 * features of the interface. Skip if on dev
 */
if(versionCompare(piholeVersion, "v2.7") < 0) {
    alert("Pi-hole needs to be updated to at least v2.7 before you can use features such as whitelisting/blacklisting from this web interface!");
}

// Session timer
var sessionvalidity = parseInt(document.getElementById("sessiontimercounter").textContent);
var start = new Date;

function updateSessionTimer()
{
    start = new Date;
    start.setSeconds(start.getSeconds() + sessionvalidity);
}

if(sessionvalidity > 0)
{
    // setSeconds will correctly handle wrap-around cases
    updateSessionTimer();

    setInterval(function() {
        var current = new Date;
        var totalseconds = (start - current) / 1000;

        // var hours = Math.floor(totalseconds / 3600);
        // totalseconds = totalseconds % 3600;

        var minutes = Math.floor(totalseconds / 60);
        if(minutes < 10){ minutes = "0" + minutes; }

        var seconds = Math.floor(totalseconds % 60);
        if(seconds < 10){ seconds = "0" + seconds; }

        if(totalseconds > 0)
        {
            document.getElementById("sessiontimercounter").textContent = minutes + ":" + seconds;
        }
        else
        {
            document.getElementById("sessiontimercounter").textContent = "-- : --";
        }

    }, 1000);
}
else
{
    document.getElementById("sessiontimer").style.display = "none";
}

// Hide "exact match" button on queryads.php page if version is 2.9.5 or lower
if(versionCompare(piholeVersion, "v2.9.5") < 1)
{
	$("#btnSearchExact").hide();
}

// Handle Strg + Enter button on Login page
$(document).keypress(function(e) {
	if(e.which === 10 && $("#loginpw").is(":focus")) {
		$("#loginform").attr("action", "settings.php");
		$("#loginform").submit();
	}
});
<commit_msg>Try to detect it also on non-Unix platforms<commit_after>// User menu toggle
$("#dropdown-menu a").on("click", function(event) {
    $(this).parent().toggleClass("open");
});
$("body").on("click", function(event) {
    if(!$("#dropdown-menu").is(event.target) && $("#dropdown-menu").has(event.target).length === 0) {
        $("#dropdown-menu").removeClass("open");
    }
});

function piholeChanged(action)
{
    const status = $("#status");
    const ena = $("#pihole-enable");
    const dis = $("#pihole-disable");

    switch(action) {
        case "enabled":
        status.html(" Active");
        ena.hide();
        dis.show();
        dis.removeClass("active");
        break;

        case "disabled":
        status.html(" Offline");
        ena.show();
        dis.hide();
        break;
    }

}

function piholeChange(action, duration)
{
    const token = encodeURIComponent($("#token").html());
    var btnStatus;

    switch(action) {
        case "enable":
        btnStatus = $("#flip-status-enable");
        btnStatus.html(" ");
        $.getJSON("api.php?enable&token=" + token, (data) => {
            if(data.status === "enabled") {
                btnStatus.html("");
                piholeChanged("enabled");
            }
        });
        break;

        case "disable":
        btnStatus = $("#flip-status-disable");
        btnStatus.html(" ");
        $.getJSON("api.php?disable=" + duration + "&token=" + token, (data) => {
            if(data.status === "disabled") {
                btnStatus.html("");
                piholeChanged("disabled");
            }
        });
        break;
    }
}

// Handle Enable/Disable
$("#pihole-enable").on("click", (e) => {
    e.preventDefault();
    piholeChange("enable","");
});
$("#pihole-disable-permanently").on("click", (e) => {
    e.preventDefault();
    piholeChange("disable","0");
});
$("#pihole-disable-10s").on("click", (e) => {
    e.preventDefault();
    piholeChange("disable","10");
    setTimeout(function(){piholeChanged("enabled");},10000);
});
$("#pihole-disable-30s").on("click", (e) => {
    e.preventDefault();
    piholeChange("disable","30");
    setTimeout(function(){piholeChanged("enabled");},30000);
});
$("#pihole-disable-5m").on("click", (e) => {
    e.preventDefault();
    piholeChange("disable","300");
    setTimeout(function(){piholeChanged("enabled");},300000);
});

var piholeVersion = $("#piholeVersion").html();
var webVersion = $("#webVersion").html();

// Credit for following function: https://gist.github.com/alexey-bass/1115557
// Modified to discard any possible "v" in the string
function versionCompare(left, right) {
    if (typeof left + typeof right !== "stringstring")
    {
        return false;
    }

    // If we are on vDev then we assume that it is always
    // newer than the latest online release, i.e. version
    // comparison should return 1
    if(left === "vDev")
    {
        return 1;
    }

    var aa = left.split("v"),
        bb = right.split("v");

    var a = aa[aa.length-1].split(".")
        ,   b = bb[bb.length-1].split(".")
        ,   i = 0, len = Math.max(a.length, b.length);

    for (; i < len; i++) {
        if ((a[i] && !b[i] && parseInt(a[i]) > 0) || (parseInt(a[i]) > parseInt(b[i]))) {
            return 1;
        } else if ((b[i] && !a[i] && parseInt(b[i]) > 0) || (parseInt(a[i]) < parseInt(b[i]))) {
            return -1;
        }
    }
    return 0;
}

// Update check
$.getJSON("https://api.github.com/repos/pi-hole/pi-hole/releases/latest", function(json) {
    if(versionCompare(piholeVersion, json.tag_name.slice(1)) < 0) {
        // Alert user
        $("#piholeVersion").html($("#piholeVersion").text() + "(Update available!)");
        $("#alPiholeUpdate").show();
    }
});
$.getJSON("https://api.github.com/repos/pi-hole/AdminLTE/releases/latest", function(json) {
    if(versionCompare(webVersion, json.tag_name.slice(1)) < 0) {
        // Alert user
        $("#webVersion").html($("#webVersion").text() + "(Update available!)");
        $("#alWebUpdate").show();
    }
});

/*
 * Make sure that Pi-hole is updated to at least v2.7, since that is needed to use the sudo
 * features of the interface. Skip if on dev
 */
if(versionCompare(piholeVersion, "v2.7") < 0) {
    alert("Pi-hole needs to be updated to at least v2.7 before you can use features such as whitelisting/blacklisting from this web interface!");
}

// Session timer
var sessionvalidity = parseInt(document.getElementById("sessiontimercounter").textContent);
var start = new Date;

function updateSessionTimer()
{
    start = new Date;
    start.setSeconds(start.getSeconds() + sessionvalidity);
}

if(sessionvalidity > 0)
{
    // setSeconds will correctly handle wrap-around cases
    updateSessionTimer();

    setInterval(function() {
        var current = new Date;
        var totalseconds = (start - current) / 1000;

        // var hours = Math.floor(totalseconds / 3600);
        // totalseconds = totalseconds % 3600;

        var minutes = Math.floor(totalseconds / 60);
        if(minutes < 10){ minutes = "0" + minutes; }

        var seconds = Math.floor(totalseconds % 60);
        if(seconds < 10){ seconds = "0" + seconds; }

        if(totalseconds > 0)
        {
            document.getElementById("sessiontimercounter").textContent = minutes + ":" + seconds;
        }
        else
        {
            document.getElementById("sessiontimercounter").textContent = "-- : --";
        }

    }, 1000);
}
else
{
    document.getElementById("sessiontimer").style.display = "none";
}

// Hide "exact match" button on queryads.php page if version is 2.9.5 or lower
if(versionCompare(piholeVersion, "v2.9.5") < 1)
{
	$("#btnSearchExact").hide();
}

// Handle Strg + Enter button on Login page
$(document).keypress(function(e) {
	if((e.keyCode == 10 || e.keyCode == 13) && e.ctrlKey && $("#loginpw").is(":focus")) {
		$("#loginform").attr("action", "settings.php");
		$("#loginform").submit();
	}
});
<|endoftext|>


<commit_before>/**
 * Nomads Basic Mobile and Desktop Client
 */

ANIMATION_OFFSET = 50;

INTERFACE_CIRCLE_RAD = 110;
INTERFACE_CIRCLE0_X = 250 + ANIMATION_OFFSET;
INTERFACE_CIRCLE0_Y = 129 + ANIMATION_OFFSET;
INTERFACE_CIRCLE1_X = 370 + ANIMATION_OFFSET;
INTERFACE_CIRCLE1_Y = 215 + ANIMATION_OFFSET;
INTERFACE_CIRCLE2_X = 330 + ANIMATION_OFFSET;
INTERFACE_CIRCLE2_Y = 360 + ANIMATION_OFFSET;
INTERFACE_CIRCLE3_X = 176 + ANIMATION_OFFSET;
INTERFACE_CIRCLE3_Y = 375 + ANIMATION_OFFSET;
INTERFACE_CIRCLE4_X = 134 + ANIMATION_OFFSET;
INTERFACE_CIRCLE4_Y = 215 + ANIMATION_OFFSET;

GRAPHICS_W = 600;
GRAPHICS_H = 600;

var client;
var currentZone;
var currentX;
var currentY;
var canvas;
var context;
var clientAnimation;
var x, y;
var allClientThoughts = []; //by instantiating this here, users will get a clean slate as they enter the fray. will start populating globally as new messages appear.

$(document).ready(function(){
  client = new NomadsMobileClient(initCallback);

  client.geolocate();

  $('#namefield').focus();
  canvas = document.getElementById('mainui');

  // setup animation
  clientAnimation = new NomadsMobileClientAnimation();

  $('#enter_phrase').prop('disabled', true);
  $('#cancel_phrase').prop('disabled', true);
  $('#phrasefield').prop('disabled', true);
  //hide entry div until user selects a zone.
  $("#phrase-entry").hide();

  //Listeners

  $('#login-form').submit(login);

  $('#phrase-form').submit(submitPhrase);
  $('#cancel_phrase').hide();
  $('#cancel_phrase').click(cancelPhrase);

  canvas.addEventListener('mousedown', zoneClick);

  //Load sounds
  $('.sounds').load();
  $("html, body").animate({ scrollTop: 0 }, "slow");

});

pointInCircle = function (center_x, center_y, radius, x, y){
  var dist = (center_x - x)*(center_x - x) + (center_y - y)*(center_y - y);
  if(dist < radius*radius){
    return true;
  }else{
    return false;
  }
}

zoneClick = function(evt){
  var rect = canvas.getBoundingClientRect();

  x = currentX = evt.clientX - rect.left;
  y = currentY = evt.clientY - rect.top;

  //tests!
  if(pointInCircle(INTERFACE_CIRCLE0_X, INTERFACE_CIRCLE0_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 0
    if(pointInCircle(INTERFACE_CIRCLE4_X, INTERFACE_CIRCLE4_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 9");
      zoneSelect(9);
    }else
    if(pointInCircle(INTERFACE_CIRCLE1_X, INTERFACE_CIRCLE1_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 1");
      zoneSelect(1);
    }else{
      console.log("zone 0");
      zoneSelect(0);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE1_X, INTERFACE_CIRCLE1_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 1
    if(pointInCircle(INTERFACE_CIRCLE0_X, INTERFACE_CIRCLE0_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 1");
      zoneSelect(1);
    }else
    if(pointInCircle(INTERFACE_CIRCLE2_X, INTERFACE_CIRCLE2_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 3");
      zoneSelect(3);
    }else{
      console.log("zone 2");
      zoneSelect(2);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE2_X, INTERFACE_CIRCLE2_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 2
    if(pointInCircle(INTERFACE_CIRCLE1_X, INTERFACE_CIRCLE1_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 3");
      zoneSelect(3);
    }else
    if(pointInCircle(INTERFACE_CIRCLE3_X, INTERFACE_CIRCLE3_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 5");
      zoneSelect(5);
    }else{
      console.log("zone 4");
      zoneSelect(4);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE3_X, INTERFACE_CIRCLE3_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 3
    if(pointInCircle(INTERFACE_CIRCLE2_X, INTERFACE_CIRCLE2_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 5");
      zoneSelect(5);
    }else
    if(pointInCircle(INTERFACE_CIRCLE4_X, INTERFACE_CIRCLE4_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 7")
      zoneSelect(7);
    }else{
      console.log("zone 6");
      zoneSelect(6);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE4_X, INTERFACE_CIRCLE4_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 4
    if(pointInCircle(INTERFACE_CIRCLE3_X, INTERFACE_CIRCLE3_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 7");
      zoneSelect(7);
    }else
    if(pointInCircle(INTERFACE_CIRCLE0_X, INTERFACE_CIRCLE0_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 9");
      zoneSelect(9);
    }else{
      console.log("zone 8");
      zoneSelect(8);
    }
  }

  console.log("mouse down "+x + ' ' + y);
}

initCallback = function(){
  $('#loader').hide();
}

login = function(e){
  //cancel form submission
  e.preventDefault();

  if($('#namefield').val()==""){
    //must submit phrase
    return;
  }

  client.login($('#namefield').val(), loginComplete);
}

loginComplete = function(){
  $("#namefield").blur();
  $('#login').fadeOut();
}

zoneSelect = function(cz){
  $("#phrase-entry").show(1, function(){$('#phrasefield').focus();});
  $('#enter_phrase').prop('disabled', false);
  $('#cancel_phrase').prop('disabled', false);
  $('#phrasefield').prop('disabled', false);

  currentZone = cz;//$(this).attr("data-location");
  return false;
}

submitPhrase = function(e){
  //cancel form submission
  e.preventDefault();
  var text = $('#phrasefield').val();
  if(text==""){
    //must submit phrase
    //tell the user to submit something?
    return;
  }

  client.sendMessage(text, currentZone, x, y, 'textMessage');

  //error with this function. won't play anything else below. doesn't exist?
  //clientAnimation.sendMessage();

  //create new clientThought, push to allClientThoughts[]
  //see NomadsMobileClientAnimation.js for display on canvas.
  //this only displays a single Client's thoughts on his/her canvas.
  allClientThoughts.push({
    "thought":text,
    "x":x,
    "y":y,
    "life":20,
    "size":18,
    "alpha":1.0
  });

  $('#phrasefield').val('');
  //Play sound
  var i = Math.floor(Math.random()*14);
  console.log("playing sound "+i);
  $('#sound'+i)[0].play();
  $('#enter_phrase').prop('disabled', true);
  $('#cancel_phrase').prop('disabled', true);
  $('#phrasefield').prop('disabled', true);
  $("#phrasefield").blur();
  //jump user screen back up to top of page.
  //$("body, html").scrollTop($("#mainui").offset().top);
  $("body, html").animate({
    scrollTop: $("#mainui").offset().top
  }, 600, function() {
    // Animation complete.
    $("#phrase-entry").hide();

  });

}

cancelPhrase = function(e){
  //cancel form submission
  $('#enter_phrase').prop('disabled', true);
  $('#cancel_phrase').prop('disabled', true);
  $('#phrasefield').prop('disabled', true);
  $('#phrasefield').val('');

  //jump user back to top after cancel.
  $("body, html").animate({
    scrollTop: $("#mainui").offset().top
  }, 600, function() {
    // Animation complete.
    $("#phrase-entry").hide();
  });
}
<commit_msg>input styling<commit_after>/**
 * Nomads Basic Mobile and Desktop Client
 */

ANIMATION_OFFSET = 50;

INTERFACE_CIRCLE_RAD = 110;
INTERFACE_CIRCLE0_X = 250 + ANIMATION_OFFSET;
INTERFACE_CIRCLE0_Y = 129 + ANIMATION_OFFSET;
INTERFACE_CIRCLE1_X = 370 + ANIMATION_OFFSET;
INTERFACE_CIRCLE1_Y = 215 + ANIMATION_OFFSET;
INTERFACE_CIRCLE2_X = 330 + ANIMATION_OFFSET;
INTERFACE_CIRCLE2_Y = 360 + ANIMATION_OFFSET;
INTERFACE_CIRCLE3_X = 176 + ANIMATION_OFFSET;
INTERFACE_CIRCLE3_Y = 375 + ANIMATION_OFFSET;
INTERFACE_CIRCLE4_X = 134 + ANIMATION_OFFSET;
INTERFACE_CIRCLE4_Y = 215 + ANIMATION_OFFSET;

GRAPHICS_W = 600;
GRAPHICS_H = 600;

var client;
var currentZone;
var currentX;
var currentY;
var canvas;
var context;
var clientAnimation;
var x, y;
var allClientThoughts = []; //by instantiating this here, users will get a clean slate as they enter the fray. will start populating globally as new messages appear.

$(document).ready(function(){
  client = new NomadsMobileClient(initCallback);

  client.geolocate();

  $('#namefield').focus();
  canvas = document.getElementById('mainui');

  // setup animation
  clientAnimation = new NomadsMobileClientAnimation();

  $('#enter_phrase').prop('disabled', true);
  $('#cancel_phrase').prop('disabled', true);
  $('#phrasefield').prop('disabled', true);
  //hide entry div until user selects a zone.
  $("#phrase-entry").hide();

  //Listeners

  $('#login-form').submit(login);

  $('#phrase-form').submit(submitPhrase);
  $('#cancel_phrase').hide();
  $('#cancel_phrase').click(cancelPhrase);

  canvas.addEventListener('mousedown', zoneClick);

  //Load sounds
  $('.sounds').load();
  $("html, body").animate({ scrollTop: 0 }, "slow");

});

pointInCircle = function (center_x, center_y, radius, x, y){
  var dist = (center_x - x)*(center_x - x) + (center_y - y)*(center_y - y);
  if(dist < radius*radius){
    return true;
  }else{
    return false;
  }
}

zoneClick = function(evt){
  var rect = canvas.getBoundingClientRect();

  x = currentX = evt.clientX - rect.left;
  y = currentY = evt.clientY - rect.top;

  //tests!
  if(pointInCircle(INTERFACE_CIRCLE0_X, INTERFACE_CIRCLE0_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 0
    if(pointInCircle(INTERFACE_CIRCLE4_X, INTERFACE_CIRCLE4_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 9");
      zoneSelect(9);
    }else
    if(pointInCircle(INTERFACE_CIRCLE1_X, INTERFACE_CIRCLE1_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 1");
      zoneSelect(1);
    }else{
      console.log("zone 0");
      zoneSelect(0);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE1_X, INTERFACE_CIRCLE1_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 1
    if(pointInCircle(INTERFACE_CIRCLE0_X, INTERFACE_CIRCLE0_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 1");
      zoneSelect(1);
    }else
    if(pointInCircle(INTERFACE_CIRCLE2_X, INTERFACE_CIRCLE2_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 3");
      zoneSelect(3);
    }else{
      console.log("zone 2");
      zoneSelect(2);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE2_X, INTERFACE_CIRCLE2_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 2
    if(pointInCircle(INTERFACE_CIRCLE1_X, INTERFACE_CIRCLE1_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 3");
      zoneSelect(3);
    }else
    if(pointInCircle(INTERFACE_CIRCLE3_X, INTERFACE_CIRCLE3_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 5");
      zoneSelect(5);
    }else{
      console.log("zone 4");
      zoneSelect(4);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE3_X, INTERFACE_CIRCLE3_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 3
    if(pointInCircle(INTERFACE_CIRCLE2_X, INTERFACE_CIRCLE2_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 5");
      zoneSelect(5);
    }else
    if(pointInCircle(INTERFACE_CIRCLE4_X, INTERFACE_CIRCLE4_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 7")
      zoneSelect(7);
    }else{
      console.log("zone 6");
      zoneSelect(6);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE4_X, INTERFACE_CIRCLE4_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 4
    if(pointInCircle(INTERFACE_CIRCLE3_X, INTERFACE_CIRCLE3_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 7");
      zoneSelect(7);
    }else
    if(pointInCircle(INTERFACE_CIRCLE0_X, INTERFACE_CIRCLE0_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 9");
      zoneSelect(9);
    }else{
      console.log("zone 8");
      zoneSelect(8);
    }
  }

  $(window).scrollTop($(document).height());
  console.log("mouse down "+x + ' ' + y);
}

initCallback = function(){
  $('#loader').hide();
}

login = function(e){
  //cancel form submission
  e.preventDefault();

  if($('#namefield').val()==""){
    //must submit phrase
    return;
  }

  client.login($('#namefield').val(), loginComplete);
}

loginComplete = function(){
  $("#namefield").blur();
  $('#login').fadeOut();
}

zoneSelect = function(cz){
  $("#phrase-entry").show(1, function(){$('#phrasefield').focus();});
  $('#enter_phrase').prop('disabled', false);
  $('#cancel_phrase').prop('disabled', false);
  $('#phrasefield').prop('disabled', false);

  currentZone = cz;//$(this).attr("data-location");
  return false;
}

submitPhrase = function(e){
  //cancel form submission
  e.preventDefault();
  var text = $('#phrasefield').val();
  if(text==""){
    //must submit phrase
    //tell the user to submit something?
    return;
  }

  client.sendMessage(text, currentZone, x, y, 'textMessage');

  //error with this function. won't play anything else below. doesn't exist?
  //clientAnimation.sendMessage();

  //create new clientThought, push to allClientThoughts[]
  //see NomadsMobileClientAnimation.js for display on canvas.
  //this only displays a single Client's thoughts on his/her canvas.
  allClientThoughts.push({
    "thought":text,
    "x":x,
    "y":y,
    "life":20,
    "size":18,
    "alpha":1.0
  });

  $('#phrasefield').val('');
  //Play sound
  var i = Math.floor(Math.random()*14);
  console.log("playing sound "+i);
  $('#sound'+i)[0].play();
  $('#enter_phrase').prop('disabled', true);
  $('#cancel_phrase').prop('disabled', true);
  $('#phrasefield').prop('disabled', true);
  $("#phrasefield").blur();
  //jump user screen back up to top of page.
  //$("body, html").scrollTop($("#mainui").offset().top);
  $("body, html").animate({
    scrollTop: $("#mainui").offset().top
  }, 600, function() {
    // Animation complete.
    $("#phrase-entry").hide();

  });

}

cancelPhrase = function(e){
  //cancel form submission
  $('#enter_phrase').prop('disabled', true);
  $('#cancel_phrase').prop('disabled', true);
  $('#phrasefield').prop('disabled', true);
  $('#phrasefield').val('');

  //jump user back to top after cancel.
  $("body, html").animate({
    scrollTop: $("#mainui").offset().top
  }, 600, function() {
    // Animation complete.
    $("#phrase-entry").hide();
  });
}
<|endoftext|>


<commit_before>/*global Stats:true*/

// extends src/nodes/time.js which extends src/node-box-native-view.js

$(function(){

  var template =
    'makeymakey

'+
    '<input type="checkbox" class="active" checked /> active';;

  Iframework.NativeNodes["ui-makeymakey"] = Iframework.NativeNodes["ui"].extend({

    template: _.template(template),
    info: {
      title: "makeymakey",
      description: "makeymakey board"
    },
    events: {
      "change .active": "changeActive"
    },
    initializeModule: function(){
      var self = this;

      Mousetrap.bind('space', function () {
        if (self._active) {
          self.sendSpace();
        }
      });

      Mousetrap.bind('up', function () {
        if (self._active) {
          self.sendUp();
        }
      });

      Mousetrap.bind('down', function () {
        if (self._active) {
          self.sendDown();
        }
      });

      Mousetrap.bind('right', function () {
        if (self._active) {
          self.sendRight();
        }
      });

      Mousetrap.bind('left', function () {
        if (self._active) {
          self.sendLeft();
        }
      });

      $(window).click(function (event) {
        if (self._active) {
          self.sendClick(event);
        }
      });
    },
    _active: true,
    changeActive: function(event){
      if (event.target.checked) {
        this._active = true;
      } else {
        this._active = false;
      }
    },
    sendSpace: function() {
      this.send("space", "bang");
      this.$(".info").text('Space!');
    },
    sendClick: function(evt) {
      this.send("click", "bang");
      this.$(".info").text('Click!');
    },
    sendUp: function() {
      this.send("up", "bang");
      this.$(".info").text('Up!');
    },
    sendDown: function() {
      this.send("down", "bang");
      this.$(".info").text('Down!');
    },
    sendLeft: function() {
      this.send("left", "bang");
      this.$(".info").text('Left!');
    },
    sendRight: function() {
      this.send("right", "bang");
      this.$(".info").text('Right!');
    },
    outputs: {
      space: {
        type: "bang"
      },
      click: {
        type: "bang"
      },
      up: {
        type: "bang"
      },
      down: {
        type: "bang"
      },
      left: {
        type: "bang"
      },
      right: {
        type: "bang"
      }
    }
  });
});
<commit_msg>unbinding when destroy ui-makeymakey<commit_after>/*global Stats:true*/

// extends src/nodes/time.js which extends src/node-box-native-view.js

$(function(){

  var template =
    'makeymakey

'+
    '<input type="checkbox" class="active" checked /> active';;

  Iframework.NativeNodes["ui-makeymakey"] = Iframework.NativeNodes["ui"].extend({

    template: _.template(template),
    info: {
      title: "makeymakey",
      description: "makeymakey board"
    },
    events: {
      "change .active": "changeActive"
    },
    initializeModule: function(){
      var self = this;

      Mousetrap.bind('space', function () {
        if (self._active) {
          self.sendSpace();
        }
      });

      Mousetrap.bind('up', function () {
        if (self._active) {
          self.sendUp();
        }
      });

      Mousetrap.bind('down', function () {
        if (self._active) {
          self.sendDown();
        }
      });

      Mousetrap.bind('right', function () {
        if (self._active) {
          self.sendRight();
        }
      });

      Mousetrap.bind('left', function () {
        if (self._active) {
          self.sendLeft();
        }
      });

      $(window).click(function (event) {
        if (self._active) {
          self.sendClick(event);
        }
      });
    },
    _active: true,
    changeActive: function(event){
      if (event.target.checked) {
        this._active = true;
      } else {
        this._active = false;
      }
    },
    sendSpace: function() {
      this.send("space", "bang");
      this.$(".info").text('Space!');
    },
    sendClick: function(evt) {
      this.send("click", "bang");
      this.$(".info").text('Click!');
    },
    sendUp: function() {
      this.send("up", "bang");
      this.$(".info").text('Up!');
    },
    sendDown: function() {
      this.send("down", "bang");
      this.$(".info").text('Down!');
    },
    sendLeft: function() {
      this.send("left", "bang");
      this.$(".info").text('Left!');
    },
    sendRight: function() {
      this.send("right", "bang");
      this.$(".info").text('Right!');
    },
    remove: function() {
      var keys = ['space', 'up', 'down', 'left', 'right'];
      for (key in keys) {
        Mousetrap.unbind(key, 'keydown');
      }
      $(window).unbind('click');
    },
    outputs: {
      space: {
        type: "bang"
      },
      click: {
        type: "bang"
      },
      up: {
        type: "bang"
      },
      down: {
        type: "bang"
      },
      left: {
        type: "bang"
      },
      right: {
        type: "bang"
      }
    }
  });
});
<|endoftext|>


<commit_before>$(function() {
	var delayTimer = null;

	$(document).on('rsv-service-added rsv-service-removed rsv-service-switched', bindTextareas);

	function bindTextareas() {
		$('.json-input').off('change keyup').on('change keyup', reactToChange);
		$('.json-input').off('blur').on('blur', function() {
			try {
				$(this).val(JSON.stringify(JSON.parse($(this).val()), null, 3)).change();
			} catch (e) {
				// ignore errors
			}
			reactToChange();
		});
	}

	function reactToChange() {
		var combinedData = {
			exchanges: [],
			queues: []
		};

		$('.json-input').each(function() {
			var data = {};

			try {
				data = JSON.parse($(this).val());
			}
			catch (err) {
				$(this).addClass('has-error');
				console.warn(err);
			}
			$(this).removeClass('has-error');

			if (data && data.exchanges) {
				_.each(data.exchanges, function(exchange, i) {
					if (_.find(combinedData.exchanges, { name: exchange.name })) {
						data.exchanges.splice(i);
						// TODO: validate exchange properties and alert if there is a mismatch
					}
				});
				combinedData.exchanges = combinedData.exchanges.concat(data.exchanges);
			}
			if (data && data.queues) {
				_.each(data.queues, function(queue, i) {
					var existingQueue = _.find(combinedData.queues, { name: queue.name });
					if (existingQueue) {
						existingQueue.bindings = existingQueue.bindings.concat(queue.bindings);
						data.queues.splice(i);
						// TODO: validate queue properties and alert if there is a mismatch
					}
				});
				combinedData.queues = combinedData.queues.concat(data.queues);
			}
			$(document).trigger('rsv-service-json-updated', { id: $(this).data('service-id'), json: data });
		});

		renderStructureWithDelay(combinedData);
	}

	function renderStructureWithDelay(structure) {
		if (delayTimer) {
			clearTimeout(delayTimer);
		}
		delayTimer = setTimeout(function() {
			renderStructure(structure);
		}, 200);
	}

	function renderStructure(structure) {
		if (!structure || !structure.exchanges || !structure.queues) {
			return;
		}

		$('#chart').css('height', Math.max(250, Math.max(structure.exchanges.length, structure.queues.length) * 60));

		var chart = d3
				.select('#chart')
				.html('')
				.append('svg')
				.chart('Sankey.Path'),
			exchangeFmt = _.template('Exchange: <%- name %>'),
			queueFmt = _.template('Queue: <%- name %>'),
			bindingFmt = _.template('→ <%- routing %> →'),
			deadLetterBindingFmt = _.template('← x-dead-letter-exchange: <%- data["x-dead-letter-exchange"] %> (<%- data["x-message-ttl"] %> ms) ←', { variable: 'data' });

		chart
			.nodeWidth(20)
			.nodePadding(25)
			.iterations(60)
			.spread(true)
			.name(function(n) { return n.name; })
			.colorNodes(function(name, node) {
				if (name && name.toLowerCase().indexOf('queue') > -1) return '#f6b26b';
				if (name && name.toLowerCase().indexOf('→') > -1) return '#9ec4e8';
				if (name && name.toLowerCase().indexOf('x-dead-letter') > -1) return '#f00';
				return '#fff176';
			})
			.colorLinks(function(link) {
				return '#999';
			});

		var nodes = [],
			bindings = [],
			links = [];

		structure.exchanges.forEach(function(exchange, key) {
			exchange.name = exchangeFmt(exchange);
			exchange._index = nodes.push(exchange) - 1;
		});

		structure.queues.forEach(function(queue) {
			queue.name = queueFmt(queue);
			queue._index = nodes.push(queue) - 1;
			if (queue.bindings instanceof Array) {
				queue.bindings.forEach(function(binding) {
					binding._target = queue;
					binding.name = bindingFmt(binding);
					binding._source = _.find(nodes, { name: exchangeFmt({name: binding.exchange}) });
					bindings.push(binding);
					binding._index = nodes.push(binding) - 1;
				});
			}
			if (queue.options && queue.options.arguments && queue.options.arguments['x-dead-letter-exchange']) {
				var deadLetterBinding = {
					_source: _.find(nodes, { name: exchangeFmt({name: queue.options.arguments['x-dead-letter-exchange'] }) }),
					name: deadLetterBindingFmt(queue.options.arguments),
					_target: queue,
					_value: 0.5
				};
				bindings.push(deadLetterBinding);
				deadLetterBinding._index = nodes.push(deadLetterBinding) - 1;
			}
		});

		bindings.forEach(function(binding) {
			// look up source...
			var linkSource = {},
				linkTarget = {};

			if (!binding._source) {
				console.warn('Source not found for binding ' + binding.name);
				return;
			}

			linkSource.source = binding._source._index;
			linkSource.target = binding._index;
			linkSource.value = binding._value || 1;

			// ...and then target
			var targetCandidate = _.find(nodes, { name: binding._target.name });

			if (!targetCandidate || !targetCandidate._index) {
				throw new Error('Target not found for binding ' + binding.name);
			}

			linkTarget.source = binding._index;
			linkTarget.target = targetCandidate._index;
			linkTarget.value = binding._value || 1;

			links.push(linkSource);
			links.push(linkTarget);
		});

		var chartData = {
			nodes: nodes,
			links: links
		};

		chart.draw(chartData);
	}
});<commit_msg>fix vertical sizing of diagram<commit_after>$(function() {
	var delayTimer = null;

	$(document).on('rsv-service-added rsv-service-removed rsv-service-switched', bindTextareas);

	function bindTextareas() {
		$('.json-input').off('change keyup').on('change keyup', reactToChange);
		$('.json-input').off('blur').on('blur', function() {
			try {
				$(this).val(JSON.stringify(JSON.parse($(this).val()), null, 3)).change();
			} catch (e) {
				// ignore errors
			}
			reactToChange();
		});
	}

	function reactToChange() {
		var combinedData = {
			exchanges: [],
			queues: []
		};

		$('.json-input').each(function() {
			var data = {};

			try {
				data = JSON.parse($(this).val());
			}
			catch (err) {
				$(this).addClass('has-error');
				console.warn(err);
			}
			$(this).removeClass('has-error');

			if (data && data.exchanges) {
				_.each(data.exchanges, function(exchange, i) {
					if (_.find(combinedData.exchanges, { name: exchange.name })) {
						data.exchanges.splice(i);
						// TODO: validate exchange properties and alert if there is a mismatch
					}
				});
				combinedData.exchanges = combinedData.exchanges.concat(data.exchanges);
			}
			if (data && data.queues) {
				_.each(data.queues, function(queue, i) {
					var existingQueue = _.find(combinedData.queues, { name: queue.name });
					if (existingQueue) {
						existingQueue.bindings = existingQueue.bindings.concat(queue.bindings);
						data.queues.splice(i);
						// TODO: validate queue properties and alert if there is a mismatch
					}
				});
				combinedData.queues = combinedData.queues.concat(data.queues);
			}
			$(document).trigger('rsv-service-json-updated', { id: $(this).data('service-id'), json: data });
		});

		renderStructureWithDelay(combinedData);
	}

	function renderStructureWithDelay(structure) {
		if (delayTimer) {
			clearTimeout(delayTimer);
		}
		delayTimer = setTimeout(function() {
			renderStructure(structure);
		}, 200);
	}

	function renderStructure(structure) {
		if (!structure || !structure.exchanges || !structure.queues) {
			return;
		}

		var nodes = [],
			bindings = [],
			links = [],
			exchangeFmt = _.template('Exchange: <%- name %>'),
			queueFmt = _.template('Queue: <%- name %>'),
			bindingFmt = _.template('→ <%- routing %> →'),
			deadLetterBindingFmt = _.template('← x-dead-letter-exchange: <%- data["x-dead-letter-exchange"] %> (<%- data["x-message-ttl"] %> ms) ←', { variable: 'data' });

		structure.exchanges.forEach(function(exchange, key) {
			exchange.name = exchangeFmt(exchange);
			exchange._index = nodes.push(exchange) - 1;
		});

		structure.queues.forEach(function(queue) {
			queue.name = queueFmt(queue);
			queue._index = nodes.push(queue) - 1;
			if (queue.bindings instanceof Array) {
				queue.bindings.forEach(function(binding) {
					binding._target = queue;
					binding.name = bindingFmt(binding);
					binding._source = _.find(nodes, { name: exchangeFmt({name: binding.exchange}) });
					bindings.push(binding);
					binding._index = nodes.push(binding) - 1;
				});
			}
			if (queue.options && queue.options.arguments && queue.options.arguments['x-dead-letter-exchange']) {
				var deadLetterBinding = {
					_source: _.find(nodes, { name: exchangeFmt({name: queue.options.arguments['x-dead-letter-exchange'] }) }),
					name: deadLetterBindingFmt(queue.options.arguments),
					_target: queue,
					_value: 0.5
				};
				bindings.push(deadLetterBinding);
				deadLetterBinding._index = nodes.push(deadLetterBinding) - 1;
			}
		});

		bindings.forEach(function(binding) {
			// look up source...
			var linkSource = {},
				linkTarget = {};

			if (!binding._source) {
				console.warn('Source not found for binding ' + binding.name);
				return;
			}

			linkSource.source = binding._source._index;
			linkSource.target = binding._index;
			linkSource.value = binding._value || 1;

			// ...and then target
			var targetCandidate = _.find(nodes, { name: binding._target.name });

			if (!targetCandidate || !targetCandidate._index) {
				throw new Error('Target not found for binding ' + binding.name);
			}

			linkTarget.source = binding._index;
			linkTarget.target = targetCandidate._index;
			linkTarget.value = binding._value || 1;

			links.push(linkSource);
			links.push(linkTarget);
		});

		$('#chart').css('height', Math.max(250, Math.max(nodes.length, links.length) * 25));

		var chart = d3
				.select('#chart')
				.html('')
				.append('svg')
				.chart('Sankey.Path');

		chart
			.nodeWidth(20)
			.nodePadding(25)
			.iterations(60)
			.spread(true)
			.name(function(n) { return n.name; })
			.colorNodes(function(name, node) {
				if (name && name.toLowerCase().indexOf('queue') > -1) return '#f6b26b';
				if (name && name.toLowerCase().indexOf('→') > -1) return '#9ec4e8';
				if (name && name.toLowerCase().indexOf('x-dead-letter') > -1) return '#f00';
				return '#fff176';
			})
			.colorLinks(function(link) {
				return '#999';
			});

		var chartData = {
			nodes: nodes,
			links: links
		};

		chart.draw(chartData);
	}
});<|endoftext|>


<commit_before>const gulp = require('gulp')
const browserSync = require('browser-sync').create()
const sourcemaps = require('gulp-sourcemaps')
const deploy = require('gulp-gh-pages')

const markdown = require('gulp-markdown')
const inject = require('gulp-inject')

const concat = require('gulp-concat')
const uglify = require('gulp-uglify')

const sass = require('gulp-sass')
const autoprefixer = require('gulp-autoprefixer')

const PATHS = {
  styles: {
    src: 'src/sass/**/*.scss',
    dest: 'app/assets/css/'
  },
  scripts: {
    src: 'src/js/**/*.js',
    dest: 'app/assets/js/'
  },
  content: {
    src: 'src/content/**/*.md',
    dest: '**/*.html'
  }
}

gulp.task('sass', function () {
  return gulp.src(PATHS.styles.src)
    .pipe(sourcemaps.init())
    .pipe(sass({ outputStyle: 'expanded'} ).on('error', sass.logError))
    .pipe(sourcemaps.write())
    .pipe( autoprefixer({ browsers: ['last 2 versions'] }) )
    .pipe(gulp.dest(PATHS.styles.dest))
    .pipe(browserSync.stream())
})

gulp.task('js', function () {
  return gulp.src(PATHS.scripts.src)
    .pipe(sourcemaps.init())
    .pipe(concat('all.min.js'))
    .pipe(uglify())
    .pipe(sourcemaps.write(''))
    .pipe(gulp.dest(PATHS.scripts.dest))
    .pipe(browserSync.stream())
})

gulp.task('content', function () {
  var CONTENT = gulp.src(PATHS.content.src)
                  .pipe(markdown())

  return gulp.src('src/' + PATHS.content.dest)
    .pipe(inject(CONTENT, {
      starttag: '<!-- inject:{{path}} -->',
      relative: true,
      transform: function (filePath, file) {
        return file.contents.toString('utf8')
      }
    }))
    .pipe(gulp.dest('app/'))
    .pipe(browserSync.stream())
})

gulp.task('build', ['content', 'sass', 'js'], function () {
  // Move our CNAME to production
  gulp.src('src/CNAME').pipe(gulp.dest('app/'))
})

gulp.task('serve', ['build'], function () {
  browserSync.init({
    server: './app',
    injectChanges: true,
    notify: false
  })

  gulp.watch(PATHS.styles.src, ['sass'])
  gulp.watch(PATHS.scripts.src, ['js'])
  gulp.watch(PATHS.content.src, ['content'])
})

gulp.task('deploy', function () {
  if (!process.env.TRAVIS) throw new Error('Only TRAVIS is allowed deploy')
  if (!process.env.GITHUB_TOKEN) throw new Error('Missing env variable: GITHUB_TOKEN')

  let options = {
    remoteUrl: `https://${process.env.GITHUB_TOKEN}@github.com/jessevdp/web.git`
  }
  return gulp.src('./app/**/*')
    .pipe(deploy(options))
})

gulp.task('default', ['serve'])
<commit_msg>Style touchups in gulpfile<commit_after>const gulp = require('gulp')
const browserSync = require('browser-sync').create()
const sourcemaps = require('gulp-sourcemaps')
const deploy = require('gulp-gh-pages')

const markdown = require('gulp-markdown')
const inject = require('gulp-inject')

const concat = require('gulp-concat')
const uglify = require('gulp-uglify')

const sass = require('gulp-sass')
const autoprefixer = require('gulp-autoprefixer')

const PATHS = {
  styles: {
    src: 'src/sass/**/*.scss',
    dest: 'app/assets/css/'
  },
  scripts: {
    src: 'src/js/**/*.js',
    dest: 'app/assets/js/'
  },
  content: {
    src: 'src/content/**/*.md',
    dest: '**/*.html'
  }
}

gulp.task('sass', function () {
  return gulp.src(PATHS.styles.src)
    .pipe(sourcemaps.init())
    .pipe(sass({ outputStyle: 'expanded' }).on('error', sass.logError))
    .pipe(sourcemaps.write())
    .pipe(autoprefixer({ browsers: ['last 2 versions'] }))
    .pipe(gulp.dest(PATHS.styles.dest))
    .pipe(browserSync.stream())
})

gulp.task('js', function () {
  return gulp.src(PATHS.scripts.src)
    .pipe(sourcemaps.init())
    .pipe(concat('all.min.js'))
    .pipe(uglify())
    .pipe(sourcemaps.write(''))
    .pipe(gulp.dest(PATHS.scripts.dest))
    .pipe(browserSync.stream())
})

gulp.task('content', function () {
  var CONTENT = gulp.src(PATHS.content.src)
                  .pipe(markdown())

  return gulp.src('src/' + PATHS.content.dest)
    .pipe(inject(CONTENT, {
      starttag: '<!-- inject:{{path}} -->',
      relative: true,
      transform: function (filePath, file) {
        return file.contents.toString('utf8')
      }
    }))
    .pipe(gulp.dest('app/'))
    .pipe(browserSync.stream())
})

gulp.task('build', ['content', 'sass', 'js'], function () {
  // Move our CNAME to production
  gulp.src('src/CNAME').pipe(gulp.dest('app/'))
})

gulp.task('serve', ['build'], function () {
  browserSync.init({
    server: './app',
    injectChanges: true,
    notify: false
  })

  gulp.watch(PATHS.styles.src, ['sass'])
  gulp.watch(PATHS.scripts.src, ['js'])
  gulp.watch(PATHS.content.src, ['content'])
})

gulp.task('deploy', function () {
  if (!process.env.TRAVIS) throw new Error('Only TRAVIS is allowed to deploy')
  if (!process.env.GITHUB_TOKEN) throw new Error('Missing env variable: GITHUB_TOKEN')

  let options = {
    remoteUrl: `https://${process.env.GITHUB_TOKEN}@github.com/jessevdp/web.git`
  }
  return gulp.src('./app/**/*')
    .pipe(deploy(options))
})

gulp.task('default', ['serve'])
<|endoftext|>


<commit_before>/**
 	Constructor for Button
	@constructor
*/
var ButtonObject = function()
{
	//Call the parent constructor!!!!
	RealObject.call(this);

	//Add a property "font" and "text" to button
	this.font = "18px Arial";
	this.text = "";
	this.checkForInput = true;

	//Let's override the method "update"
	//Even though the update in RealObject is exactly same
	this.update = function()
	{
		//Call this to update the bounding box of the object
		//Otherwise, the object would be unclickable
		this.updateRealObject();
	}

	//Declare a new method called setText
	//so we can change the button text
	this.setText = function(text)
	{
		//Temporarily change the canvas' font
		context.font = this.font;

		//context.measureText(text) gets the approximate
		//width of the button text
		var width = context.measureText(text).width;

		//Our button size will be that width plus some extra
		this.size.x = width+25;

		//Nice hardcoded height
		this.size.y = 32;

		this.text = text;
	}

	//Override the draw function a bit
	this.draw = function()
	{
		context.lineWidth = 2;
		//Set the current drawing font
		context.font = this.font;

		//this.mouseHover is set by the Engine
		//if the mouse is over the object

		if (this.mouseHover) //if mouse.hover
			context.fillStyle = "#AAAAAA"; //use some darker background
		else
			context.fillStyle = "#FFFFFF";

		//Fill the area from position to position+size
		context.fillRect(this.position.x, this.position.y, this.size.x, this.size.y);

		//Stroke a nice shadow
		context.strokeStyle = "#888888";
		context.strokeRect(this.position.x, this.position.y, this.size.x-2, this.size.y-2);

		//Stroke dat edges 2
		context.strokeStyle = "#000000";
		context.strokeRect(this.position.x, this.position.y, this.size.x, this.size.y);

		//Change color to black
		context.fillStyle = "#000000";

		//And print our text
		context.fillText(this.text,this.position.x+10,this.position.y+22);
	}

	//Override this in instantiation to
	//do some cool stuff
	this.onClick = function()
	{
		alert("ERROR: No button action!!!")
	}
}

//The "inheritance"
ButtonObject.prototype = new RealObject();

//The constructor assignment
ButtonObject.constructor = ButtonObject;

var InvisibleButton = function()
{
    this.draw = function()
    {

    }
}

//The "inheritance"
InvisibleButton.prototype = new ButtonObject();

//The constructor assignment
InvisibleButton.constructor = InvisibleButton;

var RadioButton = function(pos, buttonnumber)
{

    this.selected = false;
    this.value = 0;
    this.position = pos;
    this.size = new Vector2(48, 48);
    this.font = "18px Arial";
	this.text = this.value;
    this.depth = 1000;
    this.buttonnumber = buttonnumber;
    this.inputContext += Context.map["gameCalculationScreen"];
    this.drawContext += Context.map["gameCalculationScreen"];
	this.checkForInput = true;
    this.setText = function(text)
	{
		//Temporarily change the canvas' font
		context.font = this.font;

		//context.measureText(text) gets the approximate
		//width of the button text
		var width = context.measureText(text).width;

		//Our button size will be that width plus some extra
		this.size.x = width+25;

		//Nice hardcoded height
		this.size.y = 32;

		this.text = text;
	}
    this.draw = function()
	{
		context.lineWidth = 2;
		//Set the current drawing font
		context.font = this.font;

		//this.mouseHover is set by the Engine
		//if the mouse is over the object

		if (this.mouseHover || this.selected) //if mouse.hover or button selected
			context.fillStyle = "#AAAAAA"; //use some darker background
		else
			context.fillStyle = "#FFFFFF";

		//Fill the area from position to position+size
		context.fillRect(this.position.x, this.position.y, this.size.x, this.size.y);

		//Stroke a nice shadow
		context.strokeStyle = "#888888";
		context.strokeRect(this.position.x, this.position.y, this.size.x-2, this.size.y-2);

		//Stroke dat edges 2
		context.strokeStyle = "#000000";
		context.strokeRect(this.position.x, this.position.y, this.size.x, this.size.y);

		//Change color to black
		context.fillStyle = "#000000";

		//And print our text
		context.fillText(this.text,this.position.x+10,this.position.y+22);
	}

    this.update = function()
    {
        this.updateRealObject();
    }

    this.onClick = function()
    {
        this.selected = true;
        RadioButtons.checkForSelections(this.buttonnumber);
    }

}

RadioButton.prototype = new ButtonObject();
RadioButton.constructor = RadioButton;

var RadioButtons =
{

    buttons : [],
    buttonsAmount : 4,
    position : new Vector2(1235, 232),
    size : new Vector2(1,1),
    depth : 0,

    changeButtonValues : function(values)
    {
        for(var i = 0; i < this.buttonsAmount; i++)
        {
            this.buttons[i].value = values[i];
            this.buttons[i].setText(values[i]);
        }
        this.reSize();
    },

    reSize : function()
    {
        if(this.buttons[0])
            this.size = new Vector2(this.buttons[0].size.x, this.buttons[0].size.y + this.buttonsAmount * 20);
    },

    generateButtons : function()
    {
        for(var i = 0; i < this.buttonsAmount; i++)
        {
            this.buttons.push(new RadioButton(new Vector2(this.position.x, this.position.y + i * 50), i));
        }
        for(var i = 0; i < this.buttonsAmount; i++)
            Engine.addObject(this.buttons[i]);
    },

    checkForSelections : function(num)
    {
        for(var i = 0; i < this.buttonsAmount; i++)
        {
            if(this.buttons[i].selected && this.buttons[i].buttonnumber != num)
            {
                this.buttons[i].selected = false;
            }
        }
    },

    update : function()
    {

    },

    draw : function()
    {

    },
}

<commit_msg>Fix RadioButton depth<commit_after>/**
 	Constructor for Button
	@constructor
*/
var ButtonObject = function()
{
	//Call the parent constructor!!!!
	RealObject.call(this);

	//Add a property "font" and "text" to button
	this.font = "18px Arial";
	this.text = "";
	this.checkForInput = true;

	//Let's override the method "update"
	//Even though the update in RealObject is exactly same
	this.update = function()
	{
		//Call this to update the bounding box of the object
		//Otherwise, the object would be unclickable
		this.updateRealObject();
	}

	//Declare a new method called setText
	//so we can change the button text
	this.setText = function(text)
	{
		//Temporarily change the canvas' font
		context.font = this.font;

		//context.measureText(text) gets the approximate
		//width of the button text
		var width = context.measureText(text).width;

		//Our button size will be that width plus some extra
		this.size.x = width+25;

		//Nice hardcoded height
		this.size.y = 32;

		this.text = text;
	}

	//Override the draw function a bit
	this.draw = function()
	{
		context.lineWidth = 2;
		//Set the current drawing font
		context.font = this.font;

		//this.mouseHover is set by the Engine
		//if the mouse is over the object

		if (this.mouseHover) //if mouse.hover
			context.fillStyle = "#AAAAAA"; //use some darker background
		else
			context.fillStyle = "#FFFFFF";

		//Fill the area from position to position+size
		context.fillRect(this.position.x, this.position.y, this.size.x, this.size.y);

		//Stroke a nice shadow
		context.strokeStyle = "#888888";
		context.strokeRect(this.position.x, this.position.y, this.size.x-2, this.size.y-2);

		//Stroke dat edges 2
		context.strokeStyle = "#000000";
		context.strokeRect(this.position.x, this.position.y, this.size.x, this.size.y);

		//Change color to black
		context.fillStyle = "#000000";

		//And print our text
		context.fillText(this.text,this.position.x+10,this.position.y+22);
	}

	//Override this in instantiation to
	//do some cool stuff
	this.onClick = function()
	{
		alert("ERROR: No button action!!!")
	}
}

//The "inheritance"
ButtonObject.prototype = new RealObject();

//The constructor assignment
ButtonObject.constructor = ButtonObject;

var InvisibleButton = function()
{
    this.draw = function()
    {

    }
}

//The "inheritance"
InvisibleButton.prototype = new ButtonObject();

//The constructor assignment
InvisibleButton.constructor = InvisibleButton;

var RadioButton = function(pos, buttonnumber)
{

    this.selected = false;
    this.value = 0;
    this.position = pos;
    this.size = new Vector2(48, 48);
    this.font = "18px Arial";
	this.text = this.value;
    this.depth = 500;
    this.buttonnumber = buttonnumber;
    this.inputContext += Context.map["gameCalculationScreen"];
    this.drawContext += Context.map["gameCalculationScreen"];
	this.checkForInput = true;
    this.setText = function(text)
	{
		//Temporarily change the canvas' font
		context.font = this.font;

		//context.measureText(text) gets the approximate
		//width of the button text
		var width = context.measureText(text).width;

		//Our button size will be that width plus some extra
		this.size.x = width+25;

		//Nice hardcoded height
		this.size.y = 32;

		this.text = text;
	}
    this.draw = function()
	{
		context.lineWidth = 2;
		//Set the current drawing font
		context.font = this.font;

		//this.mouseHover is set by the Engine
		//if the mouse is over the object

		if (this.mouseHover || this.selected) //if mouse.hover or button selected
			context.fillStyle = "#AAAAAA"; //use some darker background
		else
			context.fillStyle = "#FFFFFF";

		//Fill the area from position to position+size
		context.fillRect(this.position.x, this.position.y, this.size.x, this.size.y);

		//Stroke a nice shadow
		context.strokeStyle = "#888888";
		context.strokeRect(this.position.x, this.position.y, this.size.x-2, this.size.y-2);

		//Stroke dat edges 2
		context.strokeStyle = "#000000";
		context.strokeRect(this.position.x, this.position.y, this.size.x, this.size.y);

		//Change color to black
		context.fillStyle = "#000000";

		//And print our text
		context.fillText(this.text,this.position.x+10,this.position.y+22);
	}

    this.update = function()
    {
        this.updateRealObject();
    }

    this.onClick = function()
    {
        this.selected = true;
        RadioButtons.checkForSelections(this.buttonnumber);
    }

}

RadioButton.prototype = new ButtonObject();
RadioButton.constructor = RadioButton;

var RadioButtons =
{

    buttons : [],
    buttonsAmount : 4,
    position : new Vector2(1235, 232),
    size : new Vector2(1,1),
    depth : 0,

    changeButtonValues : function(values)
    {
        for(var i = 0; i < this.buttonsAmount; i++)
        {
            this.buttons[i].value = values[i];
            this.buttons[i].setText(values[i]);
        }
        this.reSize();
    },

    reSize : function()
    {
        if(this.buttons[0])
            this.size = new Vector2(this.buttons[0].size.x, this.buttons[0].size.y + this.buttonsAmount * 20);
    },

    generateButtons : function()
    {
        for(var i = 0; i < this.buttonsAmount; i++)
        {
            this.buttons.push(new RadioButton(new Vector2(this.position.x, this.position.y + i * 50), i));
        }
        for(var i = 0; i < this.buttonsAmount; i++)
            Engine.addObject(this.buttons[i]);
    },

    checkForSelections : function(num)
    {
        for(var i = 0; i < this.buttonsAmount; i++)
        {
            if(this.buttons[i].selected && this.buttons[i].buttonnumber != num)
            {
                this.buttons[i].selected = false;
            }
        }
    },

    update : function()
    {

    },

    draw : function()
    {

    },
}

<|endoftext|>


<commit_before><commit_msg>chore(gulp): configure gulp tasks<commit_after>var gulp = require('gulp');
var gutil = require('gulp-util')
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
var browserify = require('browserify');
var reactify = require('reactify');
var watchify = require('watchify');
var nodemon = require('gulp-nodemon');
var del = require('del');
var rename = require('gulp-rename');
var sourcemaps = require('gulp-sourcemaps');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');

gulp.paths = {
  app: 'app',
  builds: 'assets/dist',
  test: 'test'
};

gulp.task('clean', function() {
  del(['assets/dist/*.js', 'assets/dist/*.css']).then(function() {
    console.log("removed previous build");
  });
});

gulp.task('join', function() {
  return gulp.src(['app/components/*.js', 'app/app.js'])
    .pipe(sourcemaps.init())
    .pipe(concat('app.js'))
    .pipe(gulp.dest(gulp.paths.builds));
});

gulp.task('build', ['join'], function() {

  var bundler = browserify({
    entries: [gulp.paths.builds + '/app.js'],
    transform: [reactify],
    debug: true,
    cache: {},
    packageCache: {},
    fullPaths: true
  });
  bundler.external('react');

  return watchify(bundler)
    .bundle()
    .pipe(source('main.js'))
    .pipe(buffer())
    .pipe(sourcemaps.init())
    .pipe(uglify())
    .pipe(rename({
      extname: '.min.js'
    }))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest(gulp.paths.builds));
});

gulp.task('nodemon', ['join', 'build'], function() {
  nodemon({
      script: 'server.js',
      ext: 'js',
      ignore: ['.package.json']
    })
    .on('restart', function() {
      console.log('server restarted');
    });
});

gulp.task('watch', function() {
  gulp.watch(gulp.paths.app+ '/**/*.js', ['clean', 'join', 'build', 'nodemon']);
});

gulp.task('default', ['clean', 'join', 'build', 'nodemon'], function() {
  gulp.start('watch');
});

module.exports = gulp;
<|endoftext|>