<commit_before>//http://davidwalsh.name/snackjs
//http://microjs.com/
//http://westcoastlogic.com/lawnchair/
//https://github.com/madrobby/emile
//http://www.bobbyvandersluis.com/articles/clientside_scripting/
//==========================================
//  事件模块（包括伪事件对象，事件绑定与事件代理）
//==========================================

$.define("event", "node,target",function(){
    // $.log("加载event模块成功");
    var types = "contextmenu,click,dblclick,mouseout,mouseover,mouseenter,mouseleave,mousemove,mousedown,mouseup,mousewheel," +
    "abort,error,load,unload,resize,scroll,change,input,select,reset,submit,"+"blur,focus,focusin,focusout,"+"keypress,keydown,keyup";
    $.eventSupport = function( eventName,el ) {
        el = el || document.createElement("div");
        eventName = "on" + eventName;
        var ret = eventName in el;
        if (el.setAttribute && !ret ) {
            el.setAttribute(eventName, "return;");
            ret = typeof el[eventName] === "function";
        }
        el = null;
        return ret;
    };

    var facade = $.event,
    adapter = $.eventAdapter = {
        focus: {
            delegateType: "focusin"
        },
        blur: {
            delegateType: "focusout"
        },

        beforeunload: {
            setup: function(src, _, _, fn ) {
                // We only want to do this special case on windows
                if ( $.type(src, "Window") ) {
                    src.onbeforeunload = fn;
                }
            },
            teardown: function( src, _, _, fn ) {
                if ( src.onbeforeunload === fn ) {
                    src.onbeforeunload = null;
                }
            }
        }
    };
    function fixAndDispatch(src, type, e){
        e = facade.fix( e );
        e.type = type;
        facade.dispatch.call(src,e);
    }
    //用于在标准浏览器下模拟mouseenter与mouseleave
    //现在除了IE系列支持mouseenter/mouseleave/focusin/focusout外
    //opera11也支持这四个事件,同时它们也成为w3c DOM3 Event的规范
    //详见http://www.filehippo.com/pl/download_opera/changelog/9476/
    //http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html
    "mouseenter_mouseover,mouseleave_mouseout".replace(/(\w+)_(\w+)/g, function(_,orig, fix){
        adapter[ orig ]  = {
            setup:function(src){//使用事件冒充
                $._data( src, orig+"_handle", $.bind( src, fix, function( e ){
                    var parent = e.relatedTarget;
                    try {
                        while ( parent && parent !== src ) {
                            parent = parent.parentNode;
                        }
                        if ( parent !== src ) {
                            fixAndDispatch(src, orig, e)
                        }
                    } catch(err) { };
                }));
            },
            teardown: function(){
                $.unbind(this, fix, $._data( orig+"_handle" ) || $.noop);
            }
        };
    });
    var checkEls = /radio|checkbox/;
    var delegate = function( fn ){
        return function(src,selector, type){
            if(type =="change" && src.tagName === "INPUT" && checkEls.test(src.type) || selector ){
                 fn(src);
            }else{
                return false;
            }
        }
    }
    //模拟IE678的reset,submit,change的事件代理
    var submitWhich = $.oneObject("13,108");
    var submitInput = $.oneObject("submit,image");
    var submitType  = $.oneObject("text,password,textarea");
    if(!document.dispatchEvent){
        var changeEls = /^(?:textarea|input|select)$/i
        var changeType = {
            "select-one":"selectedIndex",
            "select-multiple":"selectedIndex",
            "radio":"checked",
            "checkbox":"checked"
        }
        var changeNotify = function(e){
            if(e.propertyName === ( changeType[this.type] || "value") ){
                var sups = $._data( this,"publisher");
                e = facade.fix(e);
                e.type = "change";
                for(var i in sups){
                    facade.dispatch.call(sups[i], e);
                }
            }
        }

        $.mix(adapter,{
            //reset事件的冒泡情况----FF与opera能冒泡到document,其他浏览器只能到form
            reset:{
                setup: delegate(function(src){
                    facade.bind.call( src, "click._reset keypress._reset", function( e ) {
                        if(  e.target.form && (e.which === 27  ||  e.target.type == "reset") ){
                            fixAndDispatch(src, "reset", e);
                        }
                    });
                }),
                teardown: delegate(function(src){
                    facade.unbind.call( src, "._reset" );
                })
            },
            //submit事件的冒泡情况----IE6-9 :form ;FF: document; chrome: window;safari:window;opera:window
            submit : {
                setup: delegate(function(src){
                    facade.bind.call( src, "click._submit keypress._submit", function( e ) {
                        var el = e.target, type = el.type;
                        if( el.form &&  ( submitInput[type] || submitWhich[ e.which ] && submitType[type]) ){
                            fixAndDispatch( src, "submit", e );
                        }
                    });
                }),
                teardown: delegate(function(src){
                    facade.unbind.call( src, "._submit" );
                })
            },
            change : {
                setup: delegate(function( src ){
                    var subscriber = $._data( src, "subscriber", {} );//用于保存订阅者的UUID
                    $._data( src,"valuechange_setup", $.bind( src, "beforeactivate", function() {
                        var target = event.srcElement;
                        //如果发现孩子是表单元素并且没有注册propertychange事件，则为其注册一个，那么它们在变化时就会发过来通知顶层元素
                        if ( changeEls.test( target.nodeName) && !subscriber[ target.uniqueNumber ] ) {
                            subscriber[ target.uniqueNumber] = target;//表明其已注册
                            var publisher = ($._data( target,"publisher") || $._data(target,"publisher",{}));
                            publisher[ src.uniqueNumber] = src;//此孩子可能同时要向N个顶层元素报告变化
                            facade.bind.call( target,"propertychange._change", changeNotify );
                        }
                    }));
                }),
                teardown: delegate(function(src){
                    $.unbind( src, "beforeactive", $._data( src, "valuechange_setup") || $.noop );
                    var els = $.removeData( src, "subscriber", true ) || {};
                    for(var i in els){
                        $.unbind(els[i],"._change");
                        var publisher = $._data( els[i], "publisher");
                        if(publisher){
                            delete publisher[src.uniqueNumber];
                        }
                    }
                })
            }
        })

    }
    //我们可以通过change的事件代理来模拟YUI的valuechange事件
    //支持情况 FF2+ chrome 1+ IE9+ safari3+ opera9+11 The built-in Android browser,Dolphin HD browser
    if($.eventSupport("input", document.createElement("input"))){
        //http://blog.danielfriesen.name/2010/02/16/html5-browser-maze-oninput-support/
        adapter.change = {
            setup: delegate(function(src){
                $._data( src,"valuechange_setup", $.bind( src, "input", function( e){
                    fixAndDispatch(src, "change", e);
                },true));
                $._data(src,"selectchange_setup", $.bind( src, "change", function( e){
                    var type = e.target.type;
                    if(type && !submitType[type]){
                        facade.dispatch.call( src, e);
                    }
                },true))
            }),
            teardown: delegate(function(src){
                $.unbind( src, "input", $._data(src,"valuechange_setup") || $.noop);
                $.unbind( src, "change", $._data(src,"selectchange_setup") || $.noop);
            })
        }
    }

    //在标准浏览器里面模拟focusin
    if( !$.eventSupport("focusin") ){
        "focusin_focus,focusout_blur".replace( /(\w+)_(\w+)/g, function(_,$1, $2){
            var notice = 0, focusinNotify = function (e) {
                var src = e.target
                do{//模拟冒泡
                    var events = $._data( src,"events");
                    if(events && events[$1]){
                        fixAndDispatch(src, $1, e);
                    }
                } while (src = src.parentNode );
            }
            adapter[ $1 ] = {
                setup: function( ) {
                    if ( notice++ === 0 ) {
                        document.addEventListener( $2, focusinNotify, true );
                    }
                },
                teardown: function() {
                    if ( --notice === 0 ) {
                        document.removeEventListener( $2, focusinNotify, true );
                    }
                }
            };
        });
    }
    try{
        //FF3使用DOMMouseScroll代替标准的mousewheel事件
        document.createEvent("MouseScrollEvents");
        adapter.mousewheel = {
            bindType    : "DOMMouseScroll",
            delegateType: "DOMMouseScroll"
        }
        try{
            //可能末来FF会支持标准的mousewheel事件，则需要删除此分支
            document.createEvent("WheelEvent");
            delete adapter.mousewheel;
        }catch(e){};
    }catch(e){};
    //当一个元素，或者其内部任何一个元素获得焦点的时候会触发这个事件。
    //这跟focus事件区别在于，他可以在父元素上检测子元素获取焦点的情况。
    var  rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/
    function quickParse( selector ) {
        var quick = rquickIs.exec( selector );
        if ( quick ) {
            //   0  1    2   3
            // [ _, tag, id, class ]
            quick[1] = ( quick[1] || "" ).toLowerCase();
            quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
        }
        return quick;
    }
    $.implement({
        toggle:function(/*fn1,fn2,fn3*/){
            var fns = [].slice.call(arguments), i = 0;
            return this.click(function(e){
                var fn  = fns[i++] || fns[i = 0, i++];
                fn.call(this,e);
            })
        },
        hover: function( fnIn, fnOut ) {
            return this.mouseenter( fnIn ).mouseleave( fnOut || fnIn );
        },
        on: function( types, fn, selector, times ) {
            if ( typeof types === "object" ) {
                for (var type in types ) {
                    this.on( type,  types[ type ], selector, times );
                }
                return this;
            }
            if(!types || !fn){//必须指定事件类型与回调
                return this;
            }
            return this.each( function() {//转交dispatch模块去处理
                facade.bind.call( this, types, fn, selector, times );
            });
        },
        off: function( types, fn ) {
            if ( typeof types === "object" ) {
                for ( var type in types ) {
                    this.off( type,types[ type ], fn  );
                }
                return this;
            }
            var args = arguments
            return this.each(function() {
                facade.unbind.apply( this, args );
            });
        },
        one: function( types, fn ) {
            return this.on(  types, fn, null, 1 );
        },
        bind: function( types, fn, times ) {
            return this.on( types, fn, times );
        },
        unbind: function( types, fn ) {
            return this.off( types, fn );
        },

        live: function( types,  fn, times ) {
            $( this.ownerDocument ).on( types, fn, this.selector,times );
            return this;
        },
        die: function( types, fn ) {
            $( this.ownerDocument ).off( types, fn, this.selector || "**" );
            return this;
        },
        undelegate: function( selector, types, fn ) {
            return arguments.length == 1? this.off( selector, "**" ) : this.off( types, fn, selector );
        },

        delegate: function( selector, types, fn, times ) {
            if(typeof selector === "string"){
                selector = quickParse( selector ) || selector;
            }
            return this.on( types, fn, selector, times );
        },
        fire: function(  ) {
            var args = arguments;
            return this.each(function() {
                $.event.fire.apply(this, args );
            });
        }
    })

    types.replace( $.rword, function( type ){
        $.fn[ type ] = function( callback ){
            return callback?  this.bind( type, callback ) : this.fire( type );
        }
    });
});
//2011.10.14 强化delegate 让快捷方法等支持fire 修复delegate BUG
//2011.10.21 修复focusin focsuout的事件代理 增加fixAndDispatch处理事件冒充
//2011.11.23 简化rquickIs
//1. 各浏览器兼容                  2. this指针指向兼容                  3. event参数传递兼容.

<commit_msg>允许change事件可以通过fireEvent("onchange")触发<commit_after>//http://davidwalsh.name/snackjs
//http://microjs.com/
//http://westcoastlogic.com/lawnchair/
//https://github.com/madrobby/emile
//http://www.bobbyvandersluis.com/articles/clientside_scripting/
//==========================================
//  事件模块（包括伪事件对象，事件绑定与事件代理）
//==========================================

$.define("event", "node,target",function(){
    // $.log("加载event模块成功");
    var types = "contextmenu,click,dblclick,mouseout,mouseover,mouseenter,mouseleave,mousemove,mousedown,mouseup,mousewheel," +
    "abort,error,load,unload,resize,scroll,change,input,select,reset,submit,"+"blur,focus,focusin,focusout,"+"keypress,keydown,keyup";
    $.eventSupport = function( eventName,el ) {
        el = el || document.createElement("div");
        eventName = "on" + eventName;
        var ret = eventName in el;
        if (el.setAttribute && !ret ) {
            el.setAttribute(eventName, "return;");
            ret = typeof el[eventName] === "function";
        }
        el = null;
        return ret;
    };

    var facade = $.event,
    adapter = $.eventAdapter = {
        focus: {
            delegateType: "focusin"
        },
        blur: {
            delegateType: "focusout"
        },

        beforeunload: {
            setup: function(src, _, _, fn ) {
                // We only want to do this special case on windows
                if ( $.type(src, "Window") ) {
                    src.onbeforeunload = fn;
                }
            },
            teardown: function( src, _, _, fn ) {
                if ( src.onbeforeunload === fn ) {
                    src.onbeforeunload = null;
                }
            }
        }
    };
    function fixAndDispatch(src, type, e){
        e = facade.fix( e );
        e.type = type;
        facade.dispatch.call( src, e );
    }
    //用于在标准浏览器下模拟mouseenter与mouseleave
    //现在除了IE系列支持mouseenter/mouseleave/focusin/focusout外
    //opera11也支持这四个事件,同时它们也成为w3c DOM3 Event的规范
    //详见http://www.filehippo.com/pl/download_opera/changelog/9476/
    //http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html
    "mouseenter_mouseover,mouseleave_mouseout".replace(/(\w+)_(\w+)/g, function(_,orig, fix){
        adapter[ orig ]  = {
            setup:function(src){//使用事件冒充
                $._data( src, orig+"_handle", $.bind( src, fix, function( e ){
                    var parent = e.relatedTarget;
                    try {
                        while ( parent && parent !== src ) {
                            parent = parent.parentNode;
                        }
                        if ( parent !== src ) {
                            fixAndDispatch(src, orig, e)
                        }
                    } catch(err) { };
                }));
            },
            teardown: function(){
                $.unbind(this, fix, $._data( orig+"_handle" ) || $.noop);
            }
        };
    });
    var checkEls = /radio|checkbox/;
    var delegate = function( fn ){
        return function(src,selector, type){
            var fix = type =="change" && src.tagName === "INPUT" && checkEls.test(src.type)
            if( fix || selector ){
                fn(src, fix);
            }else{
                return false;
            }
        }
    }
    //模拟IE678的reset,submit,change的事件代理
    var submitWhich = $.oneObject("13,108");
    var submitInput = $.oneObject("submit,image");
    var submitType  = $.oneObject("text,password,textarea");
    if(!document.dispatchEvent){
        var changeEls = /^(?:textarea|input|select)$/i
        var changeType = {
            "select-one":"selectedIndex",
            "select-multiple":"selectedIndex",
            "radio":"checked",
            "checkbox":"checked"
        }
        var changeDispatch = function(target, e){
            var sups = $._data( target,"publisher");
            e = facade.fix(e);
            e.type = "change";
            for(var i in sups){
                facade.dispatch.call(sups[i], e);
            }
        }
        var changeNotify = function(e){
            if(e.propertyName === ( changeType[this.type] || "value") ){
                $._data(this,"change_flag",true);
                changeDispatch(this,e);
            }
        }
        var fixChangeFire = function(){
            var el = event.srcElement;
            if( !$._data(el,"change_flag")){
                changeDispatch(el, event);
            }else{
                $.removeData(el,"change_flag",true)
            }
        }
        $.mix(adapter,{
            //reset事件的冒泡情况----FF与opera能冒泡到document,其他浏览器只能到form
            reset:{
                setup: delegate(function(src){
                    facade.bind.call( src, "click._reset keypress._reset", function( e ) {
                        if(  e.target.form && (e.which === 27  ||  e.target.type == "reset") ){
                            fixAndDispatch(src, "reset", e);
                        }
                    });
                }),
                teardown: delegate(function(src){
                    facade.unbind.call( src, "._reset" );
                })
            },
            //submit事件的冒泡情况----IE6-9 :form ;FF: document; chrome: window;safari:window;opera:window
            submit : {
                setup: delegate(function(src){
                    facade.bind.call( src, "click._submit keypress._submit", function( e ) {
                        var el = e.target, type = el.type;
                        if( el.form &&  ( submitInput[type] || submitWhich[ e.which ] && submitType[type]) ){
                            fixAndDispatch( src, "submit", e );
                        }
                    });
                }),
                teardown: delegate(function(src){
                    facade.unbind.call( src, "._submit" );
                })
            },
            change : {
                setup: delegate(function( src, fix ){
                    var subscriber = $._data( src, "subscriber", {} );//用于保存订阅者的UUID
                    $._data( src,"valuechange_setup", $.bind( src, "beforeactivate", function() {
                        var target = event.srcElement;
                        //如果发现孩子是表单元素并且没有注册propertychange事件，则为其注册一个，那么它们在变化时就会发过来通知顶层元素
                        if ( changeEls.test( target.nodeName) && !subscriber[ target.uniqueNumber ] ) {
                            subscriber[ target.uniqueNumber] = target;//表明其已注册
                            var publisher = ($._data( target,"publisher") || $._data(target,"publisher",{}));
                            publisher[ src.uniqueNumber] = src;//此孩子可能同时要向N个顶层元素报告变化
                            facade.bind.call( target,"propertychange._change", changeNotify );
                            target.attachEvent("onchange",fixChangeFire)
                        }
                    }));
                    if(fix){//允许change事件可以通过fireEvent("onchange")触发
                        src.fireEvent("onbeforeactivate")
                    }
                }),
                teardown: delegate(function(src){
                    $.unbind( src, "beforeactive", $._data( src, "valuechange_setup") || $.noop );
                    var els = $.removeData( src, "subscriber", true ) || {};
                    for(var i in els){
                        $.unbind( els[i],"._change" );
                        els[i].detachEvent("onchange", fixChangeFire );
                        var publisher = $._data( els[i], "publisher");
                        if(publisher){
                            delete publisher[src.uniqueNumber];
                        }
                    }
                })
            }
        });
    }
    //我们可以通过change的事件代理来模拟YUI的valuechange事件
    //支持情况 FF2+ chrome 1+ IE9+ safari3+ opera9+11 The built-in Android browser,Dolphin HD browser
    if($.eventSupport("input", document.createElement("input"))){
        //http://blog.danielfriesen.name/2010/02/16/html5-browser-maze-oninput-support/
        adapter.change = {
            setup: delegate(function(src){
                $._data( src,"valuechange_setup", $.bind( src, "input", function( e){
                    fixAndDispatch(src, "change", e);
                },true));
                $._data(src,"selectchange_setup", $.bind( src, "change", function( e){
                    var type = e.target.type;
                    if(type && !submitType[type]){
                        facade.dispatch.call( src, e);
                    }
                },true))
            }),
            teardown: delegate(function(src){
                $.unbind( src, "input", $._data(src,"valuechange_setup") || $.noop);
                $.unbind( src, "change", $._data(src,"selectchange_setup") || $.noop);
            })
        }
    }

    //在标准浏览器里面模拟focusin
    if( !$.eventSupport("focusin") ){
        "focusin_focus,focusout_blur".replace( /(\w+)_(\w+)/g, function(_,$1, $2){
            var notice = 0, focusinNotify = function (e) {
                var src = e.target
                do{//模拟冒泡
                    var events = $._data( src,"events");
                    if(events && events[$1]){
                        fixAndDispatch(src, $1, e);
                    }
                } while (src = src.parentNode );
            }
            adapter[ $1 ] = {
                setup: function( ) {
                    if ( notice++ === 0 ) {
                        document.addEventListener( $2, focusinNotify, true );
                    }
                },
                teardown: function() {
                    if ( --notice === 0 ) {
                        document.removeEventListener( $2, focusinNotify, true );
                    }
                }
            };
        });
    }
    try{
        //FF3使用DOMMouseScroll代替标准的mousewheel事件
        document.createEvent("MouseScrollEvents");
        adapter.mousewheel = {
            bindType    : "DOMMouseScroll",
            delegateType: "DOMMouseScroll"
        }
        try{
            //可能末来FF会支持标准的mousewheel事件，则需要删除此分支
            document.createEvent("WheelEvent");
            delete adapter.mousewheel;
        }catch(e){};
    }catch(e){};
    //当一个元素，或者其内部任何一个元素获得焦点的时候会触发这个事件。
    //这跟focus事件区别在于，他可以在父元素上检测子元素获取焦点的情况。
    var  rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/
    function quickParse( selector ) {
        var quick = rquickIs.exec( selector );
        if ( quick ) {
            //   0  1    2   3
            // [ _, tag, id, class ]
            quick[1] = ( quick[1] || "" ).toLowerCase();
            quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
        }
        return quick;
    }
    $.implement({
        toggle:function(/*fn1,fn2,fn3*/){
            var fns = [].slice.call(arguments), i = 0;
            return this.click(function(e){
                var fn  = fns[i++] || fns[i = 0, i++];
                fn.call(this,e);
            })
        },
        hover: function( fnIn, fnOut ) {
            return this.mouseenter( fnIn ).mouseleave( fnOut || fnIn );
        },
        on: function( types, fn, selector, times ) {
            if ( typeof types === "object" ) {
                for (var type in types ) {
                    this.on( type,  types[ type ], selector, times );
                }
                return this;
            }
            if(!types || !fn){//必须指定事件类型与回调
                return this;
            }
            return this.each( function() {//转交dispatch模块去处理
                facade.bind.call( this, types, fn, selector, times );
            });
        },
        off: function( types, fn ) {
            if ( typeof types === "object" ) {
                for ( var type in types ) {
                    this.off( type,types[ type ], fn  );
                }
                return this;
            }
            var args = arguments
            return this.each(function() {
                facade.unbind.apply( this, args );
            });
        },
        one: function( types, fn ) {
            return this.on(  types, fn, null, 1 );
        },
        bind: function( types, fn, times ) {
            return this.on( types, fn, times );
        },
        unbind: function( types, fn ) {
            return this.off( types, fn );
        },

        live: function( types,  fn, times ) {
            $( this.ownerDocument ).on( types, fn, this.selector,times );
            return this;
        },
        die: function( types, fn ) {
            $( this.ownerDocument ).off( types, fn, this.selector || "**" );
            return this;
        },
        undelegate: function( selector, types, fn ) {
            return arguments.length == 1? this.off( selector, "**" ) : this.off( types, fn, selector );
        },

        delegate: function( selector, types, fn, times ) {
            if(typeof selector === "string"){
                selector = quickParse( selector ) || selector;
            }
            return this.on( types, fn, selector, times );
        },
        fire: function(  ) {
            var args = arguments;
            return this.each(function() {
                $.event.fire.apply(this, args );
            });
        }
    })

    types.replace( $.rword, function( type ){
        $.fn[ type ] = function( callback ){
            return callback?  this.bind( type, callback ) : this.fire( type );
        }
    });
});
//2011.10.14 强化delegate 让快捷方法等支持fire 修复delegate BUG
//2011.10.21 修复focusin focsuout的事件代理 增加fixAndDispatch处理事件冒充
//2011.11.23 简化rquickIs
//1. 各浏览器兼容                  2. this指针指向兼容                  3. event参数传递兼容.

<|endoftext|>


<commit_before>window.onload = function (){

  //lets check request data and see what we should get rid of
  //then transform the data and finish the visuals
  //when transform use two different objects to store
  //one for the score and one for the

  // const data =[
  // //  {name: ['async', 'bluebird', 'webpack', 'request']},
  //   {final: [.84071299, .964345, .9622, .85729]},
  //   {maintenance: [.66663, .75394, .96475, .4392]},
  //   {popularity: [.96706, .85683, .89832, .8952]}
  // ]

  const coors = [
    {x: 45, y: 120},
    {x: 60, y: 120},
    {x: 25, y: 23}
  ]

  const margin = {top: 100, right: 10, bottom: 100, left: 10},
        width = window.innerHeight - margin.left - margin.right,
        height = window.innerWidth - margin.top - margin.bottom,
        line = d3.line(),
        axis = d3.axisLeft(),
        y = d3.scaleLinear()
          .domain([1, 0])
          .range([0, height]);

url = '/datam.json'
d3.request(url)
  .mimeType('application/json')
  .response(function(xhr) { return JSON.parse(xhr.responseText); })
  .get(processData)

  function processData(err, rawData){
    if (err) console.log(err)

    const data = JSON.parse(rawData)
    console.log(data)

  // var i = []
  // json.forEach(function(d){
  //   i.push({
  //     name: d.name,
  //     quality: d.score.detail.quality,
  //     popularity: d.score.detail.popularity,
  //     maintenance: d.score.detail.maintenance,
  //     final: d.score.final
  //   })
  // })

      // const transposeData = function(data){
      //   data.forEach(function(d) {
      //     console.log(d)
      //     console.log('----------------------------')
      //     primary.push({
      //       name: d.name,
      //       quality: d.score.detail.quality,
      //       popularity: d.score.detail.popularity,
      //       maintenance: d.score.detail.maintenance,
      //       final: d.score.final
      //     })
      //   })
      // }

      // transposeData(data)

      const svg = d3.select("body").append("svg")
          .attrs({
              width: width,
              height: height
          });

      const g = svg.append('g')
          .attr('transform', 'translate(' + [100, 10] + ')' )

          //this guy has to seperate the paths functio better
          //its all getting fucked up by the return statements

      const createPaths = function(d){
        //console.log(d)
        let i = 0
        const keys = ['d.score.detail.maintenance', 'd.score.detail.popularity', 'd.score.detail.quality', 'd.score.final']
        //the part where this is called four times
        //for (let i = 0; i < keys.length; i++){

              //return y(keys[value])
            //}).call()
        }

      const path = function(d){
        d3.line()
         .x(function(d, i) {
           return 100 * i; })
         .y(function(d, i) {
           console.log(keys[i])
           return y(.5)
         })
      }

      const paths = g.append('g')
        .attr('class', 'score')
        .selectAll('path')
        .data(data)
        .enter().append('path')
        .attr('transform', 'translate(' + [0, 0] + ')')
        .attr('d', path(data));   //path(data));

        // .attrs({
        //   'transform': 'translate(' + [0,0] + ')',
        //   fill: none,
        //   stroke: steelblue,
        //   'stroke-width': '3px',
        // })
 /////////////start here
        // g.append("g")
        //       .attr("class", "axisOrdinal")
        //       .each(function(d) { d3.select(this).call(axis.scale(x.domain(d3.extent(i, function(d){ return d.name})))); })

        const verticalAxis = g.append('g')
          .attr('class', 'axis')
          .selectAll('axis')
          .data(data)
          .enter()

          .each(function(d, i){
            d3.select(this)
              .append('g')
              .attr('transform', 'translate(' + [(100 * i), 0] + ')')
              .call(axis.scale(y))
          })

      // var i = {}
      // json.forEach(function(d){
      //     i.name = d.name;
      //     i.quality =  d.score.detail.quality;
      //     i.popularity = d.score.detail.popularity;
      //     i.maintenance = d.score.detail.maintenance;
      //     i.final = d.score.final;
      //   })

}
}
<commit_msg>More minor malfunctions<commit_after>window.onload = function (){

  //lets check request data and see what we should get rid of
  //then transform the data and finish the visuals
  //when transform use two different objects to store
  //one for the score and one for the

  // const data =[
  // //  {name: ['async', 'bluebird', 'webpack', 'request']},
  //   {final: [.84071299, .964345, .9622, .85729]},
  //   {maintenance: [.66663, .75394, .96475, .4392]},
  //   {popularity: [.96706, .85683, .89832, .8952]}
  // ]

  const coors = [
    {x: 45, y: 120},
    {x: 60, y: 120},
    {x: 25, y: 23}
  ]

  const margin = {top: 100, right: 10, bottom: 100, left: 10},
        width = window.innerHeight - margin.left - margin.right,
        height = window.innerWidth - margin.top - margin.bottom,
        line = d3.line(),
        axis = d3.axisLeft(),
        y = d3.scaleLinear()
          .domain([1, 0])
          .range([0, height]);

url = '/datam.json'
d3.request(url)
  .mimeType('application/json')
  .response(function(xhr) { return JSON.parse(xhr.responseText); })
  .get(processData)

  function processData(err, rawData){
    if (err) console.log(err)

    const data = JSON.parse(rawData)
    console.log(data)

  // var i = []
  // json.forEach(function(d){
  //   i.push({
  //     name: d.name,
  //     quality: d.score.detail.quality,
  //     popularity: d.score.detail.popularity,
  //     maintenance: d.score.detail.maintenance,
  //     final: d.score.final
  //   })
  // })

      // const transposeData = function(data){
      //   data.forEach(function(d) {
      //     console.log(d)
      //     console.log('----------------------------')
      //     primary.push({
      //       name: d.name,
      //       quality: d.score.detail.quality,
      //       popularity: d.score.detail.popularity,
      //       maintenance: d.score.detail.maintenance,
      //       final: d.score.final
      //     })
      //   })
      // }

      // transposeData(data)

      const svg = d3.select("body").append("svg")
          .attrs({
              width: width,
              height: height
          });

      const g = svg.append('g')
          .attr('transform', 'translate(' + [100, 10] + ')' )

          //this guy has to seperate the paths functio better
          //its all getting fucked up by the return statements

      //const createPaths = function(d){
        //console.log(d)

        //the part where this is called four times
        //for (let i = 0; i < keys.length; i++){

              //return y(keys[value])
            //}).call()
      //  }

      const path = function(data, value){
        const gh = d3.line()
         .x(function(d, i) {
           return 100 * i; })
         .y(function(d, i) {
           //console.log(keys[i])
           return y(d.value)
         })
         return gh(data)

      }

      // const path = d3.line()
      //     .x(function(d) {
      //       return d.final * 200; })
      //     .y(function(d) {
      //       return y(d.maintenanc); });

      const paths = g.append('g')
        .attr('class', 'score')
        .selectAll('path')
        .data(data)
        .enter()
        .attr('d', ()=> {
          let keys = ['score.detail.maintenance', 'score.detail.popularity', 'score.detail.quality', 'score.final']
          for(let i = 0; i < keys.length; i++){
              path(data, keys[i]);
          }
        })

        // .attrs({
        //   'transform': 'translate(' + [0,0] + ')',
        //   fill: none,,
        //   stroke: steelblue,
        //   'stroke-width': '3px',
        // })
 /////////////start here
        // g.append("g")
        //       .attr("class", "axisOrdinal")
        //       .each(function(d) { d3.select(this).call(axis.scale(x.domain(d3.extent(i, function(d){ return d.name})))); })

        const verticalAxis = g.append('g')
          .attr('class', 'axis')
          .selectAll('axis')
          .data(data)
          .enter()

          .each(function(d, i){
            d3.select(this)
              .append('g')
              .attr('transform', 'translate(' + [(100 * i), 0] + ')')
              .call(axis.scale(y))
          })

      // var i = {}
      // json.forEach(function(d){
      //     i.name = d.name;
      //     i.quality =  d.score.detail.quality;
      //     i.popularity = d.score.detail.popularity;
      //     i.maintenance = d.score.detail.maintenance;
      //     i.final = d.score.final;
      //   })

}
}
<|endoftext|>


<commit_before>/**
 *  Copyright (c) 2014, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 */

/*global Session:false, chrome:true */
/* jshint evil:true */

(function() {
  'use strict';

  /**
   * Flo client controller.
   *
   * @class FloClient
   * @private
   */

  function FloClient() {
    var self = this;
    loadConfig(function (config) {
      self.config = config;
      self.session = null;
      self.panelWindow = null;
      self.panelEventBuffer = [];
      self.status = self.status.bind(self);
      self.startNewSession = self.startNewSession.bind(self);
      self.createLogger = Logger(self.triggerEvent.bind(self, 'log'));
      self.loggger = self.createLogger('flo');
      self.createPanel();
      self.start();
    });
  }

  /**
   * Save and optionally set new config.
   *
   * @param {object} config
   * @private
   */

  FloClient.prototype.saveConfig = function() {
    chrome.runtime.sendMessage({
      name : 'localStorage:set',
      key : 'flo-config',
      data : JSON.stringify(this.config)
    });
  };

  /**
   * Listen on the panel window for an event `type`, i.e. receive a message
   * from the panel.
   *
   * @param {string} type
   * @param {function} callback
   * @private
   */

  FloClient.prototype.listenToPanel = function(type, callback) {
    if (!this.panelWindow) {
      throw new Error('Panel not found');
    }
    this.panelWindow.addEventListener('flo_' + type, callback.bind(this));
  };

  /**
   * Trigger an event on the panel window, i.e. send a message to the panel.
   * If the panel wasn't instantiated yet, the event is buffered.
   *
   * @param {string} type
   * @param {object} data
   * @private
   */

  FloClient.prototype.triggerEvent = function(type, data) {
    var event = new Event('flo_' + type);
    event.data = data;
    // Save events for anytime we need to reinit the panel with prev state.
    this.panelEventBuffer.push(event);
    if (this.panelWindow) {
      this.panelWindow.dispatchEvent(event);
    }
    return event;
  };

  /**
   * Create a new panel.
   *
   * @param {function} callback
   * @private
   */

  FloClient.prototype.createPanel = function(callback) {
    var self = this;
    chrome.devtools.panels.create(
      'flo',
      '',
      'configure/configure.html',
      function (panel) {
        panel.onShown.addListener(function(panelWindow) {
          if (!panelWindow.wasShown) {
            self.panelWindow = panelWindow;
            self.initPanel();
            panelWindow.wasShown = true;
          }
        });
      }
    );
  };

  /**
   * Called after the panel is first created to listen on it's events.
   * Will also trigger all buffered events on the panel.
   *
   * @param {object} config
   * @private
   */

  FloClient.prototype.initPanel = function() {
    this.listenToPanel('config_changed', function(e) {
      this.config = e.data;
      this.saveConfig();
      this.startNewSession();
    });
    this.listenToPanel('retry', this.startNewSession);
    this.listenToPanel('enable_for_host', this.enableForHost);
    this.panelEventBuffer.forEach(function(event) {
      this.panelWindow.dispatchEvent(event);
    }, this);
    this.triggerEvent('load', this.config);
  };

  /**
   * Starts the flo client.
   *
   * @private
   */

  FloClient.prototype.start = function() {
    this.status('starting');
    this.startNewSession();
  };

  /**
   * Stops flo client.
   *
   * @private
   */

  FloClient.prototype.stop = function() {
    this.session.destroy();
    this.session = null;
  };

  /**
   * Get the url location of the inspected window.
   *
   * @param {function} callback
   * @private
   */

  FloClient.prototype.getLocation = function(callback) {
    chrome.devtools.inspectedWindow['eval'](
      'location.hostname || location.href',
      callback.bind(this)
    );
  };

  /**
   * Match config patterns against `host` and returns the matched site record.
   *
   * @param {string} host
   * @return {object|null}
   * @private
   */

  FloClient.prototype.getSite = function(host) {
    var config = this.config;
    for (var i = 0; i < config.sites.length; i++) {
      var site = config.sites[i];
      var pattern = parsePattern(site.pattern);
      var matched = false;
      if (pattern instanceof RegExp) {
        matched = pattern.exec(host);
      } else {
        matched = pattern === host;
      }
      if (matched) return site;
    }
    return null;
  };

  /**
   * Instantiates a new `session`.
   *
   * @private
   */

  FloClient.prototype.startNewSession = function() {
    if (this.session) {
      this.stop();
    }

    this.getLocation(
      function (host) {
        var site = this.getSite(host);
        if (site) {
          this.session = new Session(
            site.server || host,
            site.port || this.config.port,
            this.status,
            this.createLogger
          );
          this.session.start();
        } else {
          this.status('disabled');
        }
      }
    );
  };

  /**
   * Enables flo for the current inspected window host.
   *
   * @private
   */

  FloClient.prototype.enableForHost = function() {
    this.getLocation(function(host) {
      if (!this.getSite(host)) {
        this.config.sites.push({
          pattern: host,
          server: host
        });
        this.saveConfig();
        this.triggerEvent('load', this.config);
        this.startNewSession();
      }
    });
  };

  /**
   * Reports status changes to panel.
   *
   * @param {string} status
   * @param {object} aux
   * @private
   */

  FloClient.prototype.status = function(status, aux) {
    var text, action;
    switch (status) {
      case 'starting':
        text = 'Starting';
        break;
      case 'disabled':
        text = 'Disabled for this site';
        action = 'enable';
        break;
      case 'connecting':
        text = 'Connecting';
        break;
      case 'connected':
        text = 'Connected';
        break;
      case 'started':
        text = 'Started';
        break;
      case 'retry':
        text = 'Failed to connect, retrying in ' + (aux / 1000) + 's';
        break;
      case 'error':
        text = 'Error connecting';
        action = 'retry';
        break;
      default:
        throw new Error('Unknown session status.');
    }

    this.triggerEvent('status_change', {
      type: status,
      text: text,
      action: action
    });
  };

  /**
   * Loads config from storage.
   *
   * @private
   */

  function loadConfig(done) {
    var config,
      parseConfig = function (config) {
        try {
          config = JSON.parse(config);
        }
        catch (ex) {
          config = {};
        }

        config.sites = config.sites || [];
        config.port = config.port || 8888;

        done(config);
      };

    if ((config = loadLegacyConfig())) {
      window.setTimeout(parseConfig.bind(null, config), 0);
    }
    else {
      chrome.runtime.sendMessage({
        name : 'localStorage:get',
        key : 'flo-config'
      }, parseConfig);
    }
  }

  function loadLegacyConfig() {
    var config = null;

    try {
      if (window.localStorage && window.localStorage.hasOwnProperty('flo-config')) {
        config = window.localStorage.getItem('flo-config');
        window.localStorage.removeItem('flo-config');
      }
    }
    catch (ex) {}

    return config;
  }

  /**
   * Optionally parses config from JSON to an object.
   * Also, parses patterns into regexp.
   *
   * @private
   * @return {object}
   */

  function parsePattern(pattern) {
    if (!pattern) return null;
    var m = pattern.match(/^\/(.+)\/([gim]{0,3})$/);
    if (m && m[1]) {
      return new RegExp(m[1], m[2]);
    }
    return pattern;
  }

  // Start the app.
  new FloClient();

})();
<commit_msg>cleanup new configuration style<commit_after>/**
 *  Copyright (c) 2014, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 */

/*global Session:false, chrome:true */
/* jshint evil:true */

(function() {
  'use strict';

  /**
   * Constants
   */

  var FLO_CONFIG_KEY = 'flo-config';

  /**
   * Flo client controller.
   *
   * @class FloClient
   * @private
   */

  function FloClient() {
    var self = this;
    loadConfig(function (config) {
      self.config = config;
      self.session = null;
      self.panelWindow = null;
      self.panelEventBuffer = [];
      self.status = self.status.bind(self);
      self.startNewSession = self.startNewSession.bind(self);
      self.createLogger = Logger(self.triggerEvent.bind(self, 'log'));
      self.loggger = self.createLogger('flo');
      self.createPanel();
      self.start();
    });
  }

  /**
   * Save current config to disk.
   *
   * @param {object} config
   * @private
   */

  FloClient.prototype.saveConfig = function() {
    saveConfig(this.config);
  };

  /**
   * Listen on the panel window for an event `type`, i.e. receive a message
   * from the panel.
   *
   * @param {string} type
   * @param {function} callback
   * @private
   */

  FloClient.prototype.listenToPanel = function(type, callback) {
    if (!this.panelWindow) {
      throw new Error('Panel not found');
    }
    this.panelWindow.addEventListener('flo_' + type, callback.bind(this));
  };

  /**
   * Trigger an event on the panel window, i.e. send a message to the panel.
   * If the panel wasn't instantiated yet, the event is buffered.
   *
   * @param {string} type
   * @param {object} data
   * @private
   */

  FloClient.prototype.triggerEvent = function(type, data) {
    var event = new Event('flo_' + type);
    event.data = data;
    // Save events for anytime we need to reinit the panel with prev state.
    this.panelEventBuffer.push(event);
    if (this.panelWindow) {
      this.panelWindow.dispatchEvent(event);
    }
    return event;
  };

  /**
   * Create a new panel.
   *
   * @param {function} callback
   * @private
   */

  FloClient.prototype.createPanel = function(callback) {
    var self = this;
    chrome.devtools.panels.create(
      'flo',
      '',
      'configure/configure.html',
      function (panel) {
        panel.onShown.addListener(function(panelWindow) {
          if (!panelWindow.wasShown) {
            self.panelWindow = panelWindow;
            self.initPanel();
            panelWindow.wasShown = true;
          }
        });
      }
    );
  };

  /**
   * Called after the panel is first created to listen on it's events.
   * Will also trigger all buffered events on the panel.
   *
   * @param {object} config
   * @private
   */

  FloClient.prototype.initPanel = function() {
    this.listenToPanel('config_changed', function(e) {
      this.config = e.data;
      this.saveConfig();
      this.startNewSession();
    });
    this.listenToPanel('retry', this.startNewSession);
    this.listenToPanel('enable_for_host', this.enableForHost);
    this.panelEventBuffer.forEach(function(event) {
      this.panelWindow.dispatchEvent(event);
    }, this);
    this.triggerEvent('load', this.config);
  };

  /**
   * Starts the flo client.
   *
   * @private
   */

  FloClient.prototype.start = function() {
    this.status('starting');
    this.startNewSession();
  };

  /**
   * Stops flo client.
   *
   * @private
   */

  FloClient.prototype.stop = function() {
    this.session.destroy();
    this.session = null;
  };

  /**
   * Get the url location of the inspected window.
   *
   * @param {function} callback
   * @private
   */

  FloClient.prototype.getLocation = function(callback) {
    chrome.devtools.inspectedWindow['eval'](
      'location.hostname || location.href',
      callback.bind(this)
    );
  };

  /**
   * Match config patterns against `host` and returns the matched site record.
   *
   * @param {string} host
   * @return {object|null}
   * @private
   */

  FloClient.prototype.getSite = function(host) {
    var config = this.config;
    for (var i = 0; i < config.sites.length; i++) {
      var site = config.sites[i];
      var pattern = parsePattern(site.pattern);
      var matched = false;
      if (pattern instanceof RegExp) {
        matched = pattern.exec(host);
      } else {
        matched = pattern === host;
      }
      if (matched) return site;
    }
    return null;
  };

  /**
   * Instantiates a new `session`.
   *
   * @private
   */

  FloClient.prototype.startNewSession = function() {
    if (this.session) {
      this.stop();
    }

    this.getLocation(
      function (host) {
        var site = this.getSite(host);
        if (site) {
          this.session = new Session(
            site.server || host,
            site.port || this.config.port,
            this.status,
            this.createLogger
          );
          this.session.start();
        } else {
          this.status('disabled');
        }
      }
    );
  };

  /**
   * Enables flo for the current inspected window host.
   *
   * @private
   */

  FloClient.prototype.enableForHost = function() {
    this.getLocation(function(host) {
      if (!this.getSite(host)) {
        this.config.sites.push({
          pattern: host,
          server: host
        });
        this.saveConfig();
        this.triggerEvent('load', this.config);
        this.startNewSession();
      }
    });
  };

  /**
   * Reports status changes to panel.
   *
   * @param {string} status
   * @param {object} aux
   * @private
   */

  FloClient.prototype.status = function(status, aux) {
    var text, action;
    switch (status) {
      case 'starting':
        text = 'Starting';
        break;
      case 'disabled':
        text = 'Disabled for this site';
        action = 'enable';
        break;
      case 'connecting':
        text = 'Connecting';
        break;
      case 'connected':
        text = 'Connected';
        break;
      case 'started':
        text = 'Started';
        break;
      case 'retry':
        text = 'Failed to connect, retrying in ' + (aux / 1000) + 's';
        break;
      case 'error':
        text = 'Error connecting';
        action = 'retry';
        break;
      default:
        throw new Error('Unknown session status.');
    }

    this.triggerEvent('status_change', {
      type: status,
      text: text,
      action: action
    });
  };

  /**
   * Save passed in config object to disk.
   *
   * @param {object} config
   * @private
   */

  function saveConfig(config) {
    chrome.runtime.sendMessage({
      name: 'localStorage:set',
      key: FLO_CONFIG_KEY,
      data: JSON.stringify(config)
    });
  }

  /**
   * Loads config from storage.
   *
   * @param {function} done
   * @private
   */

  function loadConfig(done) {
    var configJSON = tryToLoadLegacyConfig();

    if (configJSON) {
      var config = parseConfig(configJSON);
      // Persist new config to the new storage.
      saveConfig(config);
      setTimeout(done.bind(null, config), 0);
    }
    else {
      chrome.runtime.sendMessage(
        {
          name : 'localStorage:get',
          key : FLO_CONFIG_KEY
        },
        function (configJSON){
          var config = parseConfig(configJSON);
          done(config);
        }
      );
    }
  }

  /**
   * Parses config and sets sensible defaults.
   *
   * @param {string} config
   * @param {}
   * @private
   */

  function parseConfig(configJSON) {
    var config;

    try {
      config = JSON.parse(configJSON);
    }
    catch (ex) {
      config = {};
    }

    config.sites = config.sites || [];
    config.port = config.port || 8888;

    return config;
  }

  /**
   * Tries to load config from localstorage which was the old way of storing
   * config and returns false if it fails.
   *
   * @return {string} config
   * @private
   */

  function tryToLoadLegacyConfig() {;
    var config = null;

    try {
      var config = window.localStorage && localStorage.getItem(FLO_CONFIG_KEY);
      if (config) {
        localStorage.removeItem(FLO_CONFIG_KEY);
      }
    } catch (e) {
      return false;
    }

    return config;
  }

  /**
   * Optionally parses config from JSON to an object.
   * Also, parses patterns into regexp.
   *
   * @private
   * @return {object}
   */

  function parsePattern(pattern) {
    if (!pattern) return null;
    var m = pattern.match(/^\/(.+)\/([gim]{0,3})$/);
    if (m && m[1]) {
      return new RegExp(m[1], m[2]);
    }
    return pattern;
  }

  // Start the app.
  new FloClient();

})();
<|endoftext|>


<commit_before>//= require jquery/jquery
//= require jquery-mobile-events/jquery-mobile-events
//= require underscore/underscore
//= require backbone/backbone
//= requireTree jst
//= require scoreboard
//= require live
//= require config
//= require request-animation-frame-polyfill
//= require player
//= require drawer
//= require assets

(function () {
  'use strict';

  var $ = window.jQuery;
  var config = window.config;
  var live = window.live;
  var _ = window._;
  var NodeKick = window.NodeKick;
  var Backbone = window.Backbone;

  var app = window.app = {
    users: [],
    usersById: {},
    scores: new Backbone.Collection(null, {
      comparator: function (user) { return -~~user.get('score'); }
    }),

    domReady: function () {
      $('html').addClass(config.mobile ? 'js-mobile' : 'js-desktop');
      new window.ScoresListView({collection: app.scores});
      NodeKick.Drawer.init();
      window.NodeKick.Assets.init();
    },

    draw: function () {

      if (!NodeKick.Drawer.canvas || !NodeKick.Assets.isLoaded) {
        console.log('assets not yet loaded');
        // DOM is not yet loaded or image assets have not loaded,
        // so no need to draw yet!
        return;
      }

      NodeKick.Drawer.drawBackground();
      NodeKick.Drawer.drawUsers(this.users);
    },

    updateUsers: function (users) { app.users = users; },
    updateScoreboard: function (scores) { console.log(scores); app.scores.set(scores); },
    showMessage: function(message) { console.log(message); },

    updateUserData: function (users) {
      _.reduce(users, function (usersById, user) {
        usersById[user.id] = user;
        return usersById;
      }, app.usersById);
    },

    move: function (dir) {
      $.post('/move/' + dir);
      var $ack = $('.js-move-ack');
      $ack.removeClass('js-transition js-up js-left js-right')
        .addClass('js-flash js-' + dir)
        .height();
      $ack.addClass('js-transition').removeClass('js-flash');
    }
  };

  if (!config.mobile) {
    live.connect('ws://' + location.host)
      .on('step', app.updateUsers)
      .on('userData', app.updateUserData)
      .on('message', app.showMessage)
      .on('scores', app.updateScoreboard);
  }

  (function () {
    var x0, y0, dx, dy;
    $(document).on({
      touchstart: function (ev) {
        ev = ev.originalEvent;
        if (ev.touches.length !== 1) return;
        var touch = ev.touches[0];
        x0 = touch.screenX;
        y0 = touch.screenY;
      },
      touchmove: function (ev) {
        ev.preventDefault();
        ev = ev.originalEvent;
        if (ev.touches.length !== 1 || dx !== null || dy !== null) return;
        var touch = ev.touches[0];
        dx = touch.screenX - x0;
        dy = touch.screenY - y0;
        var rightLeft = dx > 0 ? 'right' : 'left';
        var downUp = dy > 0 ? 'down' : 'up';
        var val = Math.abs(dx) > Math.abs(dy) ? rightLeft : downUp;
        app.move(val === 'down' ? rightLeft : val);
      },
      touchend: function (ev) {
        if (!ev.originalEvent.touches.length) dx = dy = null;
      },
      keydown: function (ev) {
        switch (ev.which) {
        case 37:
        case 65:
          app.move('left');
          break;
        case 38:
        case 87:
          app.move('up');
          break;
        case 39:
        case 68:
          app.move('right');
        }
      }
    });
  })();

  $(app.domReady);

  function drawLoop() {
    window.requestAnimationFrame(drawLoop);
    app.draw();
  }

  drawLoop();
})();
<commit_msg>reverted master<commit_after>//= require jquery/jquery
//= require jquery-mobile-events/jquery-mobile-events
//= require underscore/underscore
//= require backbone/backbone
//= requireTree jst
//= require scoreboard
//= require live
//= require config
//= require request-animation-frame-polyfill
//= require player
//= require drawer
//= require assets

(function () {
  'use strict';

  var $ = window.jQuery;
  var config = window.config;
  var live = window.live;
  var _ = window._;
  var NodeKick = window.NodeKick;
  var Backbone = window.Backbone;

  var app = window.app = {
    users: [],
    usersById: {},
    scores: new Backbone.Collection(null, {
      comparator: function (user) { return -~~user.get('score'); }
    }),

    domReady: function () {
      $('html').addClass(config.mobile ? 'js-mobile' : 'js-desktop');
      new window.ScoresListView({collection: app.scores});
      NodeKick.Drawer.init();
      window.NodeKick.Assets.init();
    },

    draw: function () {

      if (!NodeKick.Drawer.canvas || !NodeKick.Assets.isLoaded) {
        console.log('assets not yet loaded');
        // DOM is not yet loaded or image assets have not loaded,
        // so no need to draw yet!
        return;
      }

      NodeKick.Drawer.drawBackground();
      NodeKick.Drawer.drawUsers(this.users);
    },

    updateUsers: function (users) { app.users = users; },
    updateScoreboard: function (scores) {
      _.reduce(scores, function (usersById, user) {
        usersById[user.id] = user;
        return usersById;
      }, app.usersById);
      app.scores.set(scores);
    },

    move: function (dir) {
      $.post('/move/' + dir);
      var $ack = $('.js-move-ack');
      $ack.removeClass('js-transition js-up js-left js-right')
        .addClass('js-flash js-' + dir)
        .height();
      $ack.addClass('js-transition').removeClass('js-flash');
    }
  };

  if (!config.mobile) {
    live.connect('ws://' + location.host)
      .on('step', app.updateUsers)
      .on('scores', app.updateScoreboard);
  }

  (function () {
    var x0, y0, dx, dy;
    var pressed = {};
    var keys = {
      '38': 'up',
      '87': 'up',
      '37': 'left',
      '65': 'left',
      '39': 'right',
      '68': 'right'
    };
    $(document).on({
      touchstart: function (ev) {
        ev = ev.originalEvent;
        if (ev.touches.length !== 1) return;
        var touch = ev.touches[0];
        x0 = touch.screenX;
        y0 = touch.screenY;
      },
      touchmove: function (ev) {
        ev.preventDefault();
        ev = ev.originalEvent;
        if (ev.touches.length !== 1 || dx !== null || dy !== null) return;
        var touch = ev.touches[0];
        dx = touch.screenX - x0;
        dy = touch.screenY - y0;
        var rightLeft = dx > 0 ? 'right' : 'left';
        var downUp = dy > 0 ? 'down' : 'up';
        var val = Math.abs(dx) > Math.abs(dy) ? rightLeft : downUp;
        app.move(val === 'down' ? rightLeft : val);
      },
      touchend: function (ev) {
        if (!ev.originalEvent.touches.length) dx = dy = null;
      },
      keydown: function (ev) {
        var dir = keys[ev.which];
        if (!dir) return;
        if (!pressed[dir]) app.move(dir);
        pressed[dir] = true;
      },
      keyup: function (ev) {
        var dir = keys[ev.which];
        if (dir) pressed[dir] = false;
      }
    });
  })();

  $(app.domReady);

  function drawLoop() {
    window.requestAnimationFrame(drawLoop);
    app.draw();
  }

  drawLoop();
})();
<|endoftext|>


<commit_before>// New client start file
// by PokerDaddy

const network = require('./network.js');
const Display = require('./interface.js');
const Persistence = require('./persistence.js');

const help = `
scaling-potato help by PokerDaddy:
Commands:
/login <server> <nick>      - Asks <server> for a new token associated with <nick>.
/forcelogin <server> <nick> - Gets a new token from the server even if the server accepts your current one with <nick>.
/connect <server>           - Connects to a server using a previously set token. Best used for reconnecting.
/nick <nick>                - Sets your current connected user's nickname to <nick>.
/disconnect                 - Disconnects from the current server.
/help                       - Prints this help message.
`;

class CurrentServerdata {
  constructor(serverName) {
    this.servername = serverName;
    this.lastMessageTime = 0;
  }
}

const pers = new Persistence(process.argv[2] || 'default', ['settings', 'servers']);

let result = pers.load();
if (result != 'Success.') {
  console.log(result);
  process.exit(1);
}

const dis = new Display;

let currentServer = null;
let currentSession = null;
let currentServerData = {};

let updateCheckerId = null;

dis.on('input', (line) => {
  if (line.startsWith('/')) {
    let cmd = line.split(' ');
    switch (cmd[0]) {
      case '/login':
        loginToServer(cmd[1], cmd[2]);
        break;
      case '/forcelogin':
        forceLogin(cmd[1], cmd[2]);
        break;
      case '/connect':
        connectToServer(cmd[1]);
        break;
      case '/msg':
        {
          if (cmd.length < 3) {
            console.log('/msg <user-id> <message>');
            break;
          }
          let str = cmd[2];
          for (let index = 3; index < cmd.length; index++) {
            str += ' ' + cmd[index];
          }
          sendPrivateMessageById(cmd[1], str);
        }
        break;
      case '/msgn':
        {
          if (cmd.length < 3) {
            console.log('/msgn <nick> <message>');
            break;
          }
          let str = cmd[2];
          for (let index = 3; index < cmd.length; index++) {
            str += ' ' + cmd[index];
          }
          sendPrivateMessageByNick(cmd[1], str);
        }
        break;
      case '/nick':
        changeNickname(cmd[1]);
        break;
      case '/disconnect':
        disconnectFromServer();
        break;
      case '/help':
        printHelp();
        break;
      default:
        console.log('Unrecognized command: ' + cmd[0]);
        console.log('Use /help to list commands.');
        break;
    }
  } else {
    sendMessage(line);
  }
}).on('quit', () => {
  pers.save();
  stopUpdateChecker();
  process.exit(0);
});

process.on('uncaughtException', (error) => {
  console.log(error);
  pers.save();
  process.exit(1);
});

function printHelp() {
  console.log(help);
}

function connectToServer(server) {
  let serverData = pers.files.servers[server];
  let serverUrl = `http://${server}:8080`;
  if (serverData) {
    network.getUser(serverUrl, {
      token: serverData.session.token
    }).on('user', (user) => {
      if (user) {
        console.log('Reconnection successful.');
        user.token = serverData.session.token;
        pers.files.servers[server] = {
          session: user
        };
        currentSession = user;
        currentServer = serverUrl;
        currentServerData[serverUrl] = new CurrentServerdata(server);
        startUpdateChecker();
      } else {
        console.log("This server doesn't remember you.");
        console.log('You might want to /login');
      }
    }).on('error', (error) => {
      console.log('Error connecting to ' + server);
    });
  } else {
    console.log('You have never logged into this server before.');
    console.log('Maybe you will want to /login');
  }
}

function forceLogin(server, nick) {
  login(server, nick);
}

function loginToServer(server, nick) {
  let serverData = pers.files.servers[server];
  let serverUrl = `http://${server}:8080`;

  if (serverData) {
    network.getUser(serverUrl, {
      token: serverData.session.token
    }).on('user', (user) => {
      if (user) {
        console.log('This server remembers you. You can just /connect or login again with /forcelogin');
      } else {
        login(server, nick);
      }
    }).on('error', (error) => {
      console.log('Error connecting to ' + server);
    });
  } else {
    login(server, nick);
  }
}

function login(server, nick) {
  let serverUrl = `http://${server}:8080`
  console.log('Logging into: ' + server);
  network.login(serverUrl, nick).on('login', (session) => {
    console.log('You are now logged in as: ' + session.nick + '#' + session.id);
    pers.files.servers[server] = {
      session
    };
    currentSession = session;
    currentServer = serverUrl;
    currentServerData[serverUrl] = new CurrentServerdata(server);
    startUpdateChecker();
  }).on('error', (error) => {
    console.log('Login error.');
  });
}

function disconnectFromServer() {
  stopUpdateChecker();
  currentSession = null;
  currentServer = null;
  console.log('Disconnected.');
}

function sendMessage(message) {
  if (currentSession) {
    network.sendMessage(currentServer, currentSession, message).on('error', (error) => {
      console.log('Error sending the message.');
    });
  } else {
    console.log('You must be connected to a server to send messages.');
  }
}

function startUpdateChecker() {
  if (!updateCheckerId) {
    updateCheckerId = setInterval(checkForUpdates, 1000);
  }
}

function stopUpdateChecker() {
  if (updateCheckerId) {
    clearInterval(updateCheckerId);
    updateCheckerId = null;
  }
}

function checkForUpdates() {
  network.update(currentServer, currentServerData[currentServer].lastMessageTime).on('response', (publicMessages) => {
    network.updateDirects(currentServer, currentSession, currentServerData[currentServer].lastMessageTime).on('response', (directMessages) => {
      let messages;
      if ((publicMessages && publicMessages.length > 0) && (directMessages && directMessages.length > 0)) {
        messages = publicMessages.concat(directMessages.map((e) => {
          e.direct = true;
          return e;
        }));
      } else if (publicMessages && publicMessages.length > 0) {
        messages = publicMessages;
      } else if (directMessages && directMessages.length > 0) {
        messages = directMessages;
      }
      if (messages && typeof(messages) == 'object') {
        messages.sort((a, b) => {
          if (a.timestamp > b.timestamp) return 1;
          else if (a.timestamp < b.timestamp) return -1;
          else return 0;
        });
        messages.forEach((message) => {
          if (message.direct) {
            dis.recieveDirect(message.timestamp, message.nick, message.id, message.body);
          } else {
            dis.recieve(message.timestamp, message.nick, message.id, message.body);
          }
        });
        currentServerData[currentServer].lastMessageTime = messages[messages.length - 1].timestamp;
      }
    }).on('error', (error) => {
      console.log('Server timed out.');
      disconnectFromServer();
    });
  }).on('error', (error) => {
    console.log('Server timed out.');
    disconnectFromServer();
  });
}

function changeNickname(newNickname) {
  if (currentSession) {
    currentSession.nick = newNickname;
    network.changeNickname(currentServer, currentSession).on('response', (response) => {
      console.log(`Nickname set to ${response.nick}`);
    }).on('error', (error) => {
      console.log('Error setting nickname.');
    });
  } else {
    console.log('You must be logged into a server to have a nickname.');
  }
}

function sendPrivateMessageByNick(recipient, message) {
  if (currentSession) {
    network.getUsers(currentServer, {
      nick: recipient
    }).on('users', (users) => {
      if (users && users.length > 0) {
        if (users.length > 1) {
          console.log('Found ' + users.length + ' users with the nick: ' + recipient);
        }
        users.forEach((user) => {
          network.sendDirectMessage(currentServer, currentSession, user.id, message).on('response', (messageObj) => {
            console.log('You sent to [' + user.nick + '#' + user.id + ']: ' + message);
          }).on('error', (error) => {
            console.log('Error sending to: ' + user.nick + '#' + user.id);
          });
        });
      } else {
        console.log('No user with the nick: ' + recipient);
      }
    }).on('error', (error) => {
      console.log('Error getting users from the server.');
    });
  } else {
    console.log('You must be connected to a server to send messages.');
  }
}

function sendPrivateMessageById(recipientId, message) {
  if (currentSession) {
    network.sendDirectMessage(currentServer, currentSession, recipientId, message).on('response', (messageObj) => {
      network.getUser(currentServer, {
        id: recipientId
      }).on('user', (user) => {
        if (user) {
          console.log('You sent to [' + user.nick + '#' + user.id + ']: ' + message);
        } else {
          console.log('No user with the id: ' + recipientId);
        }
      }).on('error', (error) => {
        console.log('You sent to [' + recipientId + '] (they might not exist): ' + message);
      });
    }).on('error', (error) => {
      console.log('Error sending to: ' + recipientId);
    });
  } else {
    console.log('You must be connected to a server to send messages.');
  }
}
<commit_msg>client/index.js: Flesh out help message<commit_after>// New client start file
// by PokerDaddy

const network = require('./network.js');
const Display = require('./interface.js');
const Persistence = require('./persistence.js');

const help = `
scaling-potato help by PokerDaddy:
Commands:
/login <server> <nick>      - Asks <server> for a new token associated with <nick>.
/forcelogin <server> <nick> - Gets a new token from the server even if the server accepts your current one with <nick>.
/connect <server>           - Connects to a server using a previously set token. Best used for reconnecting.
/nick <nick>                - Sets your current connected user's nickname to <nick>.
/disconnect                 - Disconnects from the current server.
/help                       - Prints this help message.
/msg <id> <msg>             - Send <msg> to user with id <id>
/msgn <nick> <msg>          - Send <msg> to all users with nick <nick>
`;

class CurrentServerdata {
  constructor(serverName) {
    this.servername = serverName;
    this.lastMessageTime = 0;
  }
}

const pers = new Persistence(process.argv[2] || 'default', ['settings', 'servers']);

let result = pers.load();
if (result != 'Success.') {
  console.log(result);
  process.exit(1);
}

const dis = new Display;

let currentServer = null;
let currentSession = null;
let currentServerData = {};

let updateCheckerId = null;

dis.on('input', (line) => {
  if (line.startsWith('/')) {
    let cmd = line.split(' ');
    switch (cmd[0]) {
      case '/login':
        loginToServer(cmd[1], cmd[2]);
        break;
      case '/forcelogin':
        forceLogin(cmd[1], cmd[2]);
        break;
      case '/connect':
        connectToServer(cmd[1]);
        break;
      case '/msg':
        {
          if (cmd.length < 3) {
            console.log('/msg <user-id> <message>');
            break;
          }
          let str = cmd[2];
          for (let index = 3; index < cmd.length; index++) {
            str += ' ' + cmd[index];
          }
          sendPrivateMessageById(cmd[1], str);
        }
        break;
      case '/msgn':
        {
          if (cmd.length < 3) {
            console.log('/msgn <nick> <message>');
            break;
          }
          let str = cmd[2];
          for (let index = 3; index < cmd.length; index++) {
            str += ' ' + cmd[index];
          }
          sendPrivateMessageByNick(cmd[1], str);
        }
        break;
      case '/nick':
        changeNickname(cmd[1]);
        break;
      case '/disconnect':
        disconnectFromServer();
        break;
      case '/help':
        printHelp();
        break;
      default:
        console.log('Unrecognized command: ' + cmd[0]);
        console.log('Use /help to list commands.');
        break;
    }
  } else {
    sendMessage(line);
  }
}).on('quit', () => {
  pers.save();
  stopUpdateChecker();
  process.exit(0);
});

process.on('uncaughtException', (error) => {
  console.log(error);
  pers.save();
  process.exit(1);
});

function printHelp() {
  console.log(help);
}

function connectToServer(server) {
  let serverData = pers.files.servers[server];
  let serverUrl = `http://${server}:8080`;
  if (serverData) {
    network.getUser(serverUrl, {
      token: serverData.session.token
    }).on('user', (user) => {
      if (user) {
        console.log('Reconnection successful.');
        user.token = serverData.session.token;
        pers.files.servers[server] = {
          session: user
        };
        currentSession = user;
        currentServer = serverUrl;
        currentServerData[serverUrl] = new CurrentServerdata(server);
        startUpdateChecker();
      } else {
        console.log("This server doesn't remember you.");
        console.log('You might want to /login');
      }
    }).on('error', (error) => {
      console.log('Error connecting to ' + server);
    });
  } else {
    console.log('You have never logged into this server before.');
    console.log('Maybe you will want to /login');
  }
}

function forceLogin(server, nick) {
  login(server, nick);
}

function loginToServer(server, nick) {
  let serverData = pers.files.servers[server];
  let serverUrl = `http://${server}:8080`;

  if (serverData) {
    network.getUser(serverUrl, {
      token: serverData.session.token
    }).on('user', (user) => {
      if (user) {
        console.log('This server remembers you. You can just /connect or login again with /forcelogin');
      } else {
        login(server, nick);
      }
    }).on('error', (error) => {
      console.log('Error connecting to ' + server);
    });
  } else {
    login(server, nick);
  }
}

function login(server, nick) {
  let serverUrl = `http://${server}:8080`
  console.log('Logging into: ' + server);
  network.login(serverUrl, nick).on('login', (session) => {
    console.log('You are now logged in as: ' + session.nick + '#' + session.id);
    pers.files.servers[server] = {
      session
    };
    currentSession = session;
    currentServer = serverUrl;
    currentServerData[serverUrl] = new CurrentServerdata(server);
    startUpdateChecker();
  }).on('error', (error) => {
    console.log('Login error.');
  });
}

function disconnectFromServer() {
  stopUpdateChecker();
  currentSession = null;
  currentServer = null;
  console.log('Disconnected.');
}

function sendMessage(message) {
  if (currentSession) {
    network.sendMessage(currentServer, currentSession, message).on('error', (error) => {
      console.log('Error sending the message.');
    });
  } else {
    console.log('You must be connected to a server to send messages.');
  }
}

function startUpdateChecker() {
  if (!updateCheckerId) {
    updateCheckerId = setInterval(checkForUpdates, 1000);
  }
}

function stopUpdateChecker() {
  if (updateCheckerId) {
    clearInterval(updateCheckerId);
    updateCheckerId = null;
  }
}

function checkForUpdates() {
  network.update(currentServer, currentServerData[currentServer].lastMessageTime).on('response', (publicMessages) => {
    network.updateDirects(currentServer, currentSession, currentServerData[currentServer].lastMessageTime).on('response', (directMessages) => {
      let messages;
      if ((publicMessages && publicMessages.length > 0) && (directMessages && directMessages.length > 0)) {
        messages = publicMessages.concat(directMessages.map((e) => {
          e.direct = true;
          return e;
        }));
      } else if (publicMessages && publicMessages.length > 0) {
        messages = publicMessages;
      } else if (directMessages && directMessages.length > 0) {
        messages = directMessages;
      }
      if (messages && typeof(messages) == 'object') {
        messages.sort((a, b) => {
          if (a.timestamp > b.timestamp) return 1;
          else if (a.timestamp < b.timestamp) return -1;
          else return 0;
        });
        messages.forEach((message) => {
          if (message.direct) {
            dis.recieveDirect(message.timestamp, message.nick, message.id, message.body);
          } else {
            dis.recieve(message.timestamp, message.nick, message.id, message.body);
          }
        });
        currentServerData[currentServer].lastMessageTime = messages[messages.length - 1].timestamp;
      }
    }).on('error', (error) => {
      console.log('Server timed out.');
      disconnectFromServer();
    });
  }).on('error', (error) => {
    console.log('Server timed out.');
    disconnectFromServer();
  });
}

function changeNickname(newNickname) {
  if (currentSession) {
    currentSession.nick = newNickname;
    network.changeNickname(currentServer, currentSession).on('response', (response) => {
      console.log(`Nickname set to ${response.nick}`);
    }).on('error', (error) => {
      console.log('Error setting nickname.');
    });
  } else {
    console.log('You must be logged into a server to have a nickname.');
  }
}

function sendPrivateMessageByNick(recipient, message) {
  if (currentSession) {
    network.getUsers(currentServer, {
      nick: recipient
    }).on('users', (users) => {
      if (users && users.length > 0) {
        if (users.length > 1) {
          console.log('Found ' + users.length + ' users with the nick: ' + recipient);
        }
        users.forEach((user) => {
          network.sendDirectMessage(currentServer, currentSession, user.id, message).on('response', (messageObj) => {
            console.log('You sent to [' + user.nick + '#' + user.id + ']: ' + message);
          }).on('error', (error) => {
            console.log('Error sending to: ' + user.nick + '#' + user.id);
          });
        });
      } else {
        console.log('No user with the nick: ' + recipient);
      }
    }).on('error', (error) => {
      console.log('Error getting users from the server.');
    });
  } else {
    console.log('You must be connected to a server to send messages.');
  }
}

function sendPrivateMessageById(recipientId, message) {
  if (currentSession) {
    network.sendDirectMessage(currentServer, currentSession, recipientId, message).on('response', (messageObj) => {
      network.getUser(currentServer, {
        id: recipientId
      }).on('user', (user) => {
        if (user) {
          console.log('You sent to [' + user.nick + '#' + user.id + ']: ' + message);
        } else {
          console.log('No user with the id: ' + recipientId);
        }
      }).on('error', (error) => {
        console.log('You sent to [' + recipientId + '] (they might not exist): ' + message);
      });
    }).on('error', (error) => {
      console.log('Error sending to: ' + recipientId);
    });
  } else {
    console.log('You must be connected to a server to send messages.');
  }
}
<|endoftext|>


<commit_before>var d3 = require("d3"),
    $ = require("jquery"),
    preview = require("./preview.js"),
    video = require("./video.js"),
    audio = require("./audio.js");

d3.json("/settings/themes.json", function(err, themes){

  if (err) {
    throw err;
  }

  for (var key in themes) {
    themes[key] = $.extend({}, themes.default, themes[key]);
  }

  preloadImages(themes);

});

function submitted() {

  d3.event.preventDefault();

  var theme = preview.theme(),
      caption = preview.caption(),
      selection = preview.selection(),
      file = preview.file();

  if (!file) {
    d3.select("#row-audio").classed("error", true);
    return setClass("error", "No audio file selected.");
  }

  if (theme.maxDuration && selection.duration > theme.maxDuration) {
    return setClass("error", "Your Audiogram must be under " + theme.maxDuration + " seconds.");
  }

  if (!theme || !theme.width || !theme.height) {
    return setClass("error", "No valid theme detected.");
  }

  video.kill();
  audio.pause();

  var formData = new FormData();

  var settings = $.extend({}, theme, {
    caption: caption,
    start: selection.start,
    end: selection.end
  });

  delete settings.backgroundImageFile;

  formData.append("audio", file);
  formData.append("settings", JSON.stringify(settings));

  setClass("loading");
  d3.select("#loading-message").text("Uploading audio...");

	$.ajax({
		url: "/submit/",
		type: "POST",
		data: formData,
		contentType: false,
    dataType: "json",
		cache: false,
		processData: false,
		success: function(data){
      poll(data.id, 0);
		},
    error: error

  });

}

function poll(id) {

  setTimeout(function(){
    $.ajax({
      url: "/status/" + id + "/",
      error: error,
      dataType: "json",
      success: function(result){
        if (result && result.status && result.status === "ready" && result.url) {
          video.update(result.url, preview.theme().name);
          setClass("rendered");
        } else if (result.status === "error") {
          error(result.error);
        } else {
          d3.select("#loading-message").text(statusMessage(result));
          poll(id);
        }
      }
    });

  }, 2500);

}

function error(msg) {

  if (msg.responseText) {
    msg = msg.responseText;
  }

  if (typeof msg !== "string") {
    msg = JSON.stringify(msg);
  }

  if (!msg) {
    msg = "Unknown error";
  }

  d3.select("#loading-message").text("Loading...");
  setClass("error", msg);

}

// Once images are downloaded, set up listeners
function initialize(err, themesWithImages) {

  // Populate dropdown menu
  d3.select("#input-theme")
    .on("change", updateTheme)
    .selectAll("option")
    .data(themesWithImages)
    .enter()
    .append("option")
      .text(function(d){
        return d.name;
      });

  // Get initial theme
  d3.select("#input-theme").each(updateTheme);

  // Get initial caption (e.g. back button)
  d3.select("#input-caption").on("change keyup", updateCaption).each(updateCaption);

  // Space bar listener for audio play/pause
  d3.select(document).on("keypress", function(){
    if (!d3.select("body").classed("rendered") && d3.event.key === " " && !d3.matcher("input, textarea, button, select").call(d3.event.target)) {
      audio.toggle();
    }
  });

  // Button listeners
  d3.selectAll("#play, #pause").on("click", function(){
    d3.event.preventDefault();
    audio.toggle();
  });

  d3.select("#restart").on("click", function(){
    d3.event.preventDefault();
    audio.restart();
  });

  // If there's an initial piece of audio (e.g. back button) load it
  d3.select("#input-audio").on("change", updateAudioFile).each(updateAudioFile);

  d3.select("#return").on("click", function(){
    d3.event.preventDefault();
    video.kill();
    setClass(null);
  });

  d3.select("#submit").on("click", submitted);

}

function updateAudioFile() {

  d3.select("#row-audio").classed("error", false);

  audio.pause();
  video.kill();

  // Skip if empty
  if (!this.files || !this.files[0]) {
    d3.select("#minimap").classed("hidden", true);
    preview.file(null);
    setClass(null);
    return true;
  }

  d3.select("#loading-message").text("Analyzing...");

  setClass("loading");

  preview.loadAudio(this.files[0], function(err){

    if (err) {
      d3.select("#row-audio").classed("error", true);
      setClass("error", "Error decoding audio file");
    } else {
      setClass(null);
    }

    d3.selectAll("#minimap, #submit").classed("hidden", !!err);

  });

}

function updateCaption() {
  preview.caption(this.value);
}

function updateTheme() {
  var extended = d3.select(this.options[this.selectedIndex]).datum();
  preview.theme(extended);
}

function preloadImages(themes) {

  // preload images
  var imageQueue = d3.queue();

  d3.entries(themes).forEach(function(theme){

    if (!theme.value.name) {
      theme.value.name = theme.key;
    }

    if (theme.key !== "default") {
      imageQueue.defer(getImage, theme.value);
    }

  });

  imageQueue.awaitAll(initialize);

  function getImage(theme, cb) {

    if (!theme.backgroundImage) {
      return cb(null, theme);
    }

    theme.backgroundImageFile = new Image();
    theme.backgroundImageFile.onload = function(){
      return cb(null, theme);
    };
    theme.backgroundImageFile.onerror = function(e){
      console.warn(e);
      return cb(null, theme);
    };

    theme.backgroundImageFile.src = "/settings/backgrounds/" + theme.backgroundImage;

  }

}

function setClass(cl, msg) {
  d3.select("body").attr("class", cl || null);
  d3.select("#error").text(msg || "");
}

function statusMessage(result) {

  switch (result.status) {
    case "queued":
      return "Waiting for other jobs to finish, #" + (result.position + 1) + " in queue";
    case "audio-download":
      return "Downloading audio for processing";
    case "trim":
      return "Trimming audio";
    case "duration":
      return "Checking duration";
    case "waveform":
      return "Analyzing waveform";
    case "renderer":
      return "Initializing renderer";
    case "frames":
      var msg = "Generating frames";
      if (result.numFrames) {
        msg += ", " + Math.round(100 * (result.framesComplete || 0) / result.numFrames) + "% complete";
      }
      return msg;
    case "combine":
      return "Combining frames with audio";
    case "ready":
      return "Cleaning up";
    default:
      return JSON.stringify(result);
  }

}
<commit_msg>Cleanup<commit_after>var d3 = require("d3"),
    $ = require("jquery"),
    preview = require("./preview.js"),
    video = require("./video.js"),
    audio = require("./audio.js");

d3.json("/settings/themes.json", function(err, themes){

  if (err) {
    throw err;
  }

  for (var key in themes) {
    themes[key] = $.extend({}, themes.default, themes[key]);
  }

  preloadImages(themes);

});

function submitted() {

  d3.event.preventDefault();

  var theme = preview.theme(),
      caption = preview.caption(),
      selection = preview.selection(),
      file = preview.file();

  if (!file) {
    d3.select("#row-audio").classed("error", true);
    return setClass("error", "No audio file selected.");
  }

  if (theme.maxDuration && selection.duration > theme.maxDuration) {
    return setClass("error", "Your Audiogram must be under " + theme.maxDuration + " seconds.");
  }

  if (!theme || !theme.width || !theme.height) {
    return setClass("error", "No valid theme detected.");
  }

  video.kill();
  audio.pause();

  var formData = new FormData();

  var settings = $.extend({}, theme, {
    caption: caption,
    start: selection.start,
    end: selection.end
  });

  delete settings.backgroundImageFile;

  formData.append("audio", file);
  formData.append("settings", JSON.stringify(settings));

  setClass("loading");
  d3.select("#loading-message").text("Uploading audio...");

	$.ajax({
		url: "/submit/",
		type: "POST",
		data: formData,
		contentType: false,
    dataType: "json",
		cache: false,
		processData: false,
		success: function(data){
      poll(data.id, 0);
		},
    error: error

  });

}

function poll(id) {

  setTimeout(function(){
    $.ajax({
      url: "/status/" + id + "/",
      error: error,
      dataType: "json",
      success: function(result){
        if (result && result.status && result.status === "ready" && result.url) {
          video.update(result.url, preview.theme().name);
          setClass("rendered");
        } else if (result.status === "error") {
          error(result.error);
        } else {
          d3.select("#loading-message").text(statusMessage(result));
          poll(id);
        }
      }
    });

  }, 2500);

}

function error(msg) {

  if (msg.responseText) {
    msg = msg.responseText;
  }

  if (typeof msg !== "string") {
    msg = JSON.stringify(msg);
  }

  if (!msg) {
    msg = "Unknown error";
  }

  d3.select("#loading-message").text("Loading...");
  setClass("error", msg);

}

// Once images are downloaded, set up listeners
function initialize(err, themesWithImages) {

  // Populate dropdown menu
  d3.select("#input-theme")
    .on("change", updateTheme)
    .selectAll("option")
    .data(themesWithImages)
    .enter()
    .append("option")
      .text(function(d){
        return d.name;
      });

  // Get initial theme
  d3.select("#input-theme").each(updateTheme);

  // Get initial caption (e.g. back button)
  d3.select("#input-caption").on("change keyup", updateCaption).each(updateCaption);

  // Space bar listener for audio play/pause
  d3.select(document).on("keypress", function(){
    if (!d3.select("body").classed("rendered") && d3.event.key === " " && !d3.matcher("input, textarea, button, select").call(d3.event.target)) {
      audio.toggle();
    }
  });

  // Button listeners
  d3.selectAll("#play, #pause").on("click", function(){
    d3.event.preventDefault();
    audio.toggle();
  });

  d3.select("#restart").on("click", function(){
    d3.event.preventDefault();
    audio.restart();
  });

  // If there's an initial piece of audio (e.g. back button) load it
  d3.select("#input-audio").on("change", updateAudioFile).each(updateAudioFile);

  d3.select("#return").on("click", function(){
    d3.event.preventDefault();
    video.kill();
    setClass(null);
  });

  d3.select("#submit").on("click", submitted);

}

function updateAudioFile() {

  d3.select("#row-audio").classed("error", false);

  audio.pause();
  video.kill();

  // Skip if empty
  if (!this.files || !this.files[0]) {
    d3.select("#minimap").classed("hidden", true);
    preview.file(null);
    setClass(null);
    return true;
  }

  d3.select("#loading-message").text("Analyzing...");

  setClass("loading");

  preview.loadAudio(this.files[0], function(err){

    if (err) {
      d3.select("#row-audio").classed("error", true);
      setClass("error", "Error decoding audio file");
    } else {
      setClass(null);
    }

    d3.selectAll("#minimap, #submit").classed("hidden", !!err);

  });

}

function updateCaption() {
  preview.caption(this.value);
}

function updateTheme() {
  preview.theme(d3.select(this.options[this.selectedIndex]).datum());
}

function preloadImages(themes) {

  // preload images
  var imageQueue = d3.queue();

  d3.entries(themes).forEach(function(theme){

    if (!theme.value.name) {
      theme.value.name = theme.key;
    }

    if (theme.key !== "default") {
      imageQueue.defer(getImage, theme.value);
    }

  });

  imageQueue.awaitAll(initialize);

  function getImage(theme, cb) {

    if (!theme.backgroundImage) {
      return cb(null, theme);
    }

    theme.backgroundImageFile = new Image();
    theme.backgroundImageFile.onload = function(){
      return cb(null, theme);
    };
    theme.backgroundImageFile.onerror = function(e){
      console.warn(e);
      return cb(null, theme);
    };

    theme.backgroundImageFile.src = "/settings/backgrounds/" + theme.backgroundImage;

  }

}

function setClass(cl, msg) {
  d3.select("body").attr("class", cl || null);
  d3.select("#error").text(msg || "");
}

function statusMessage(result) {

  switch (result.status) {
    case "queued":
      return "Waiting for other jobs to finish, #" + (result.position + 1) + " in queue";
    case "audio-download":
      return "Downloading audio for processing";
    case "trim":
      return "Trimming audio";
    case "duration":
      return "Checking duration";
    case "waveform":
      return "Analyzing waveform";
    case "renderer":
      return "Initializing renderer";
    case "frames":
      var msg = "Generating frames";
      if (result.numFrames) {
        msg += ", " + Math.round(100 * (result.framesComplete || 0) / result.numFrames) + "% complete";
      }
      return msg;
    case "combine":
      return "Combining frames with audio";
    case "ready":
      return "Cleaning up";
    default:
      return JSON.stringify(result);
  }

}
<|endoftext|>


<commit_before>var d = require('../lib/durable');

d.run({
    timer1: {
        r1: {
            when: { start: 'yes' },
            run: function (s) {
                s.start = new Date().toString();
                s.startTimer('myTimer', 5);
            }
        },
        r2: {
            when: { $t: 'myTimer' },
            run: function (s) {
                console.log('started @' + s.start);
                console.log('timeout @' + new Date());
            }
        }
    }
}, '', null, function(host) {
    host.post('timer1', { id: 1, sid: 1, start: 'yes' }, function (err) {
        if (err) {
            console.log(err);
        } else {
            console.log('ok');
        }
    });
});<commit_msg>One more timer test<commit_after>var d = require('../lib/durable');

d.run({
    timer1: {
        r1: {
            when: { start: 'yes' },
            run: function (s) {
                s.start = new Date().toString();
                s.startTimer('myTimer', 5);
            }
        },
        r2: {
            when: { $t: 'myTimer' },
            run: function (s) {
                console.log('started @' + s.start);
                console.log('timeout @' + new Date());
            }
        }
    },
    timer2$state: {
        input: {
            review: {
                when: { subject: 'approve' },
                run: {
                    first$state: {
                        send: {
                            start: {
                                run: function (s) { s.startTimer('first', 4); },
                                to: 'evaluate'
                            }
                        },
                        evaluate: {
                            wait: {
                                when: { $t: 'first' },
                                run: function (s) { s.signal({ id: 2, subject: 'approved' }); },
                                to: 'end'
                            }
                        },
                        end: {
                        }

                    },
                    second$state: {
                        send: {
                            start: {
                                run: function (s) { s.startTimer('second', 3); },
                                to: 'evaluate'
                            }
                        },
                        evaluate: {
                            wait: {
                                when: { $t: 'second' },
                                run: function (s) { s.signal({ id: 3, subject: 'denied' }); },
                                to: 'end'
                            }
                        },
                        end: {
                        }
                    }
                },
                to: 'pending'
            }
        },
        pending: {
            approve: {
                when: { subject: 'approved' },
                run: function (s) { console.log('approved'); },
                to: 'approved'
            },
            deny: {
                when: { subject: 'denied' },
                run: function (s) { console.log('denied'); },
                to: 'denied'
            }
        },
        denied: {
        },
        approved: {
        }
    }
}, '', null, function(host) {
    host.post('timer1', { id: 1, sid: 1, start: 'yes' }, function (err) {
        if (err) {
            console.log(err);
        } else {
            console.log('ok');
        }
    });
    host.post('timer2', { id: '1', sid: 1, subject: 'approve' }, function (err) {
        if (err) {
            console.log(err);
        } else {
            console.log('ok');
        }
    });
});<|endoftext|>