<commit_before>//==========================================
// 特征嗅探模块 by 司徒正美
//==========================================
define("support",["mass"], function( $ ){
    var DOC = document, div = DOC.createElement('div'),TAGS = "getElementsByTagName";
    div.setAttribute("className", "t");
    div.innerHTML = ' <link/>d'+
    '<object><param/></object>

<input type="checkbox" checked/>';
    var a = div[TAGS]("a")[0], style = a.style,
    select = DOC.createElement("select"),
    input = div[TAGS]( "input" )[ 0 ],
    opt = select.appendChild( DOC.createElement("option") );
    //true为正常，false为不正常
    var support = $.support = {
        //标准浏览器只有在table与tr之间不存在tbody的情况下添加tbody，而IE678则笨多了,即在里面为空也乱加tbody
        insertTbody: !div[TAGS]("tbody").length,
        // 在大多数游览器中checkbox的value默认为on，唯有chrome返回空字符串
        checkOn : input.value === "on",
        //当为select添加一个新option元素时，此option会被选中，但IE与早期的safari却没有这样做,需要访问一下其父元素后才能让它处于选中状态（bug）
        optSelected: !!opt.selected,
        //IE67，无法取得用户设定的原始href值
        attrInnateHref: a.getAttribute("href") === "/nasami",
        //IE67，无法取得用户设定的原始style值，只能返回el.style（CSSStyleDeclaration）对象(bug)
        attrInnateStyle: a.getAttribute("style") !== style,
        //IE67, 对于某些固有属性需要进行映射才可以用，如class, for, char，IE8及其他标准浏览器不需要
        attrInnateName:div.className !== "t",
        //IE6-8,对于某些固有属性不会返回用户最初设置的值
        attrInnateValue: input.getAttribute("checked") == "",
        //http://www.cnblogs.com/rubylouvre/archive/2010/05/16/1736535.html
        //是否能正确返回opacity的样式值，IE8返回".25" ，IE9pp2返回0.25，chrome等返回"0.25"
        cssOpacity: style.opacity == "0.25",
        //某些浏览器不支持w3c的cssFloat属性来获取浮动样式，而是使用独家的styleFloat属性
        cssFloat: !!style.cssFloat,
        //IE678的getElementByTagName("*")无法遍历出Object元素下的param元素（bug）
        traverseAll: !!div[TAGS]("param").length,
        //https://prototype.lighthouseapp.com/projects/8886/tickets/264-ie-can-t-create-link-elements-from-html-literals
        //IE678不能通过innerHTML生成link,style,script节点（bug）
        createAll: !!div[TAGS]("link").length,
        //IE6789由于无法识别HTML5的新标签，因此复制这些新元素时也不正确（bug）
        cloneHTML5: DOC.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
        //在标准浏览器下，cloneNode(true)是不复制事件的，以防止循环引用无法释放内存，而IE却没有考虑到这一点，把事件复制了（inconformity）
        cloneNode: true,
        //现在只有firefox不支持focusin,focus事件,并且它也不支持DOMFocusIn,DOMFocusOut,并且此事件无法通过eventSupport来检测
        focusin : $["@bind"] === "attachEvent",//IE肯定支持
        //IE6789的innerHTML对于table,thead,tfoot,tbody,tr,col,colgroup,html,title,style,frameset是只读的（inconformity）
        innerHTML: false,
        //IE的insertAdjacentHTML与innerHTML一样，对于许多元素是只读的，另外FF8之前是不支持此API的
        insertAdjacentHTML: false,
        //是否支持createContextualFragment API，此方法发端于FF3，因此许多浏览器不支持或实现存在BUG，但它是将字符串转换为文档碎片的最高效手段
        fastFragment: false,
        //IE67不支持display:inline-block，需要通过hasLayout方法去模拟（bug）
        inlineBlock: true,
        //http://w3help.org/zh-cn/causes/RD1002
        //在IE678中，非替换元素在设置了大小与hasLayout的情况下，会将其父级元素撑大（inconformity）
        //        keepSize: true,
        //getComputedStyle API是否能支持将left, top的百分比原始值自动转换为像素值
        pixelPosition: true,
        transition: false
    };
    //IE6789的checkbox、radio控件在cloneNode(true)后，新元素没有继承原来的checked属性（bug）
    input.checked = true;
    support.cloneChecked = (input.cloneNode( true ).checked === true);
    support.appendChecked = input.checked;
    //添加对optDisabled,cloneAll,insertAdjacentHTML,innerHTML,fastFragment的特征嗅探
    //判定disabled的select元素内部的option元素是否也有diabled属性，没有才是标准
    //这个特性用来获取select元素的value值，特别是当select渲染为多选框时，需要注意从中去除disabled的option元素，
    //但在Safari中，获取被设置为disabled的select的值时，由于所有option元素都被设置为disabled，会导致无法获取值。
    select.disabled = true;
    support.optDisabled = !opt.disabled;
    var clickFn
    if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
        div.attachEvent("onclick", clickFn = function () {
            support.cloneNode = false;//w3c的节点复制是不复制事件的
        });
        div.cloneNode(true).fireEvent("onclick");
        div.detachEvent( "onclick", clickFn );
    }
    //IE下对div的复制节点设置与背景有关的样式会影响到原样式,说明它在复制节点对此样式并没有深拷贝,还是共享一份内存
    //    div.style.backgroundClip = "content-box";
    //    div.cloneNode( true ).style.backgroundClip = "";
    //    support.cloneBackgroundStyle = div.style.backgroundClip === "content-box";
    var table = div[TAGS]("table")[0]
    try{//检测innerHTML与insertAdjacentHTML在某些元素中是否存在只读（这时会抛错）
        table.innerHTML = "
1
";
        support.innerHTML = true;
        table.insertAdjacentHTML("afterBegin","
2
");
        support.insertAdjacentHTML = true;
    }catch(e){ };

    a = select = table = opt = style =  null;
    $.require("ready",function(){
        var body = DOC.body;
        if(!body)//frameset不存在body标签
            return;
        try{
            var range =  DOC.createRange();
            range.selectNodeContents(body); //fix opera(9.2~11.51) bug,必须对文档进行选取
            support.fastFragment = !!range.createContextualFragment("");
            $.commonRange = range;
        }catch(e){ };
        div.style.cssText = "position:absolute;top:-1000px;left:-1000px;"
        body.insertBefore( div, body.firstChild );
        var ib = '

';
        div.innerHTML = ib + ib;//div默认是block,因此两个DIV会上下排列0,但inline-block会让它们左右排列
        support.inlineBlock = div.offsetHeight < 40;//检测是否支持inlineBlock
        if( window.getComputedStyle ) {
            div.style.top = "1%";
            support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top  !== "1%";
        }
        //        div.style.cssText = "width:20px;"
        //        div.innerHTML = "

";
        //        support.keepSize = div.offsetWidth == 20;//检测是否会被子元素撑大
        //http://stackoverflow.com/questions/7337670/how-to-detect-focusin-support
        div.innerHTML = ""
        if(!support.focusin){
            var a = div.firstChild;
            a.addEventListener('focusin', function(){
                support.focusin = true;
            }, false);
            a.focus();
        }
        div.style.width = div.style.paddingLeft = "10px";//检测是否支持盒子模型
        support.boxModel = div.offsetWidth === 20;
        body.removeChild( div );
        div =  null;
    });
    return $;
});
/**
2011.9.7 优化attrProp判定
2011.9.16所有延时判定的部分现在可以立即判定了
2011.9.23增加fastFragment判定
2012.1.28有些特征嗅探必须连接到DOM树上才能进行
2012.5.22 精简插入DOM树后的五种检测

    var endNames = {
        WebkitTransition : "webkitTransitionEnd",
        MozTransition    : "transitionend" ,
        OTransition      : "oTransitionEnd otransitionend" ,
        transition       : "transitionend"
    }
    for (var name in endNames){
        if (div.style[name] !== undefined) {
            support.transition  = {
                end: endNames[name]
            }
            break
        }
    }
*/<commit_msg>添加对calc的检测<commit_after>//==========================================
// 特征嗅探模块 by 司徒正美
//==========================================
define("support",["mass"], function( $ ){
    var DOC = document, div = DOC.createElement('div'),TAGS = "getElementsByTagName";
    div.setAttribute("className", "t");
    div.innerHTML = ' <link/>d'+
    '<object><param/></object>

<input type="checkbox" checked/>';
    var a = div[TAGS]("a")[0], style = a.style,
    select = DOC.createElement("select"),
    input = div[TAGS]( "input" )[ 0 ],
    opt = select.appendChild( DOC.createElement("option") );
    //true为正常，false为不正常
    var support = $.support = {
        //标准浏览器只有在table与tr之间不存在tbody的情况下添加tbody，而IE678则笨多了,即在里面为空也乱加tbody
        insertTbody: !div[TAGS]("tbody").length,
        // 在大多数游览器中checkbox的value默认为on，唯有chrome返回空字符串
        checkOn : input.value === "on",
        //当为select添加一个新option元素时，此option会被选中，但IE与早期的safari却没有这样做,需要访问一下其父元素后才能让它处于选中状态（bug）
        optSelected: !!opt.selected,
        //IE67，无法取得用户设定的原始href值
        attrInnateHref: a.getAttribute("href") === "/nasami",
        //IE67，无法取得用户设定的原始style值，只能返回el.style（CSSStyleDeclaration）对象(bug)
        attrInnateStyle: a.getAttribute("style") !== style,
        //IE67, 对于某些固有属性需要进行映射才可以用，如class, for, char，IE8及其他标准浏览器不需要
        attrInnateName:div.className !== "t",
        //IE6-8,对于某些固有属性不会返回用户最初设置的值
        attrInnateValue: input.getAttribute("checked") == "",
        //http://www.cnblogs.com/rubylouvre/archive/2010/05/16/1736535.html
        //是否能正确返回opacity的样式值，IE8返回".25" ，IE9pp2返回0.25，chrome等返回"0.25"
        cssOpacity: style.opacity == "0.25",
        //某些浏览器不支持w3c的cssFloat属性来获取浮动样式，而是使用独家的styleFloat属性
        cssFloat: !!style.cssFloat,
        //IE678的getElementByTagName("*")无法遍历出Object元素下的param元素（bug）
        traverseAll: !!div[TAGS]("param").length,
        //https://prototype.lighthouseapp.com/projects/8886/tickets/264-ie-can-t-create-link-elements-from-html-literals
        //IE678不能通过innerHTML生成link,style,script节点（bug）
        createAll: !!div[TAGS]("link").length,
        //IE6789由于无法识别HTML5的新标签，因此复制这些新元素时也不正确（bug）
        cloneHTML5: DOC.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
        //在标准浏览器下，cloneNode(true)是不复制事件的，以防止循环引用无法释放内存，而IE却没有考虑到这一点，把事件复制了（inconformity）
        cloneNode: true,
        //现在只有firefox不支持focusin,focus事件,并且它也不支持DOMFocusIn,DOMFocusOut,并且此事件无法通过eventSupport来检测
        focusin : $["@bind"] === "attachEvent",//IE肯定支持
        //IE6789的innerHTML对于table,thead,tfoot,tbody,tr,col,colgroup,html,title,style,frameset是只读的（inconformity）
        innerHTML: false,
        //IE的insertAdjacentHTML与innerHTML一样，对于许多元素是只读的，另外FF8之前是不支持此API的
        insertAdjacentHTML: false,
        //是否支持createContextualFragment API，此方法发端于FF3，因此许多浏览器不支持或实现存在BUG，但它是将字符串转换为文档碎片的最高效手段
        fastFragment: false,
        //IE67不支持display:inline-block，需要通过hasLayout方法去模拟（bug）
        inlineBlock: true,
        //http://w3help.org/zh-cn/causes/RD1002
        //在IE678中，非替换元素在设置了大小与hasLayout的情况下，会将其父级元素撑大（inconformity）
        //        keepSize: true,
        //getComputedStyle API是否能支持将left, top的百分比原始值自动转换为像素值
        pixelPosition: true,
        transition: false,
        calc: false
    };
    //IE6789的checkbox、radio控件在cloneNode(true)后，新元素没有继承原来的checked属性（bug）
    input.checked = true;
    support.cloneChecked = (input.cloneNode( true ).checked === true);
    support.appendChecked = input.checked;
    //添加对optDisabled,cloneAll,insertAdjacentHTML,innerHTML,fastFragment的特征嗅探
    //判定disabled的select元素内部的option元素是否也有diabled属性，没有才是标准
    //这个特性用来获取select元素的value值，特别是当select渲染为多选框时，需要注意从中去除disabled的option元素，
    //但在Safari中，获取被设置为disabled的select的值时，由于所有option元素都被设置为disabled，会导致无法获取值。
    select.disabled = true;
    support.optDisabled = !opt.disabled;
    var clickFn
    if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
        div.attachEvent("onclick", clickFn = function () {
            support.cloneNode = false;//w3c的节点复制是不复制事件的
        });
        div.cloneNode(true).fireEvent("onclick");
        div.detachEvent( "onclick", clickFn );
    }
    //IE下对div的复制节点设置与背景有关的样式会影响到原样式,说明它在复制节点对此样式并没有深拷贝,还是共享一份内存
    //    div.style.backgroundClip = "content-box";
    //    div.cloneNode( true ).style.backgroundClip = "";
    //    support.cloneBackgroundStyle = div.style.backgroundClip === "content-box";
    var table = div[TAGS]("table")[0]
    try{//检测innerHTML与insertAdjacentHTML在某些元素中是否存在只读（这时会抛错）
        table.innerHTML = "
1
";
        support.innerHTML = true;
        table.insertAdjacentHTML("afterBegin","
2
");
        support.insertAdjacentHTML = true;
    }catch(e){ };

    a = select = table = opt = style =  null;
    $.require("ready",function(){
        var body = DOC.body;
        if(!body)//frameset不存在body标签
            return;
        try{
            var range =  DOC.createRange();
            range.selectNodeContents(body); //fix opera(9.2~11.51) bug,必须对文档进行选取
            support.fastFragment = !!range.createContextualFragment("");
            $.commonRange = range;
        }catch(e){ };
        div.style.cssText = "position:absolute;top:-1000px;left:-1000px;"
        body.insertBefore( div, body.firstChild );
        var ib = '

';
        div.innerHTML = ib + ib;//div默认是block,因此两个DIV会上下排列0,但inline-block会让它们左右排列
        support.inlineBlock = div.offsetHeight < 40;//检测是否支持inlineBlock
        if( window.getComputedStyle ) {
            div.style.top = "1%";
            var computed = window.getComputedStyle( div, null ) || {}
            support.pixelPosition = computed.top  !== "1%";
            div.style.width = "calc(7px + 8px)";//注意+两边有空白
            support.calc = computed.width == "15px";
        }
        //        div.style.cssText = "width:20px;"
        //        div.innerHTML = "

";
        //        support.keepSize = div.offsetWidth == 20;//检测是否会被子元素撑大
        //http://stackoverflow.com/questions/7337670/how-to-detect-focusin-support
        div.innerHTML = ""
        if(!support.focusin){
            var a = div.firstChild;
            a.addEventListener('focusin', function(){
                support.focusin = true;
            }, false);
            a.focus();
        }
        div.style.width = div.style.paddingLeft = "10px";//检测是否支持盒子模型
        support.boxModel = div.offsetWidth === 20;
        body.removeChild( div );
        div =  null;
    });
    return $;
});
/**
2011.9.7 优化attrProp判定
2011.9.16所有延时判定的部分现在可以立即判定了
2011.9.23增加fastFragment判定
2012.1.28有些特征嗅探必须连接到DOM树上才能进行
2012.5.22 精简插入DOM树后的五种检测

    var endNames = {
        WebkitTransition : "webkitTransitionEnd",
        MozTransition    : "transitionend" ,
        OTransition      : "oTransitionEnd otransitionend" ,
        transition       : "transitionend"
    }
    for (var name in endNames){
        if (div.style[name] !== undefined) {
            support.transition  = {
                end: endNames[name]
            }
            break
        }
    }
*/<|endoftext|>


<commit_before>//==========================================
// 特征嗅探模块 by 司徒正美
//==========================================
define("support", function(){
    $.log("已加载特征嗅探模块",7);
    var DOC = document, div = DOC.createElement('div'),TAGS = "getElementsByTagName";
    div.setAttribute("className", "t");
    div.innerHTML = ' <link/>d'+
    '<object><param/></object>

<input type="checkbox" checked/>';
    var a = div[TAGS]("a")[0], style = a.style,
    select = DOC.createElement("select"),
    input = div[TAGS]( "input" )[ 0 ],
    opt = select.appendChild( DOC.createElement("option") );
    //true为正常，false为不正常
    var support = $.support = {
        //标准浏览器只有在table与tr之间不存在tbody的情况下添加tbody，而IE678则笨多了,即在里面为空也乱加tbody
        insertTbody: !div[TAGS]("tbody").length,
        // 在大多数游览器中checkbox的value默认为on，唯有chrome返回空字符串
        checkOn :  input.value === "on",
        //当为select添加一个新option元素时，此option会被选中，但IE与早期的safari却没有这样做,需要访问一下其父元素后才能让它处于选中状态（bug）
        optSelected: !!opt.selected,
        //IE67无法区分href属性与特性（bug）
        attrInnateHref: a.getAttribute("href") === "/nasami",
        //IE67,是无法取得是没有style特性（特性的值的类型为文本），只有el.style（CSSStyleDeclaration）(bug)
        attrInnateStyle: a.getAttribute("style") !== style,
        //IE67, 对于某些固有属性需要进行映射才可以用，如class, for, char，IE8及其他标准浏览器不需要
        attrInnateName:div.className !== "t",
        //IE6-8,对于某些固有属性不会返回用户最初设置的值
        attrInnateValue: input.getAttribute("checked") == "",
        //http://www.cnblogs.com/rubylouvre/archive/2010/05/16/1736535.html
        //是否能正确返回opacity的样式值，IE8返回".25" ，IE9pp2返回0.25，chrome等返回"0.25"
        cssOpacity: style.opacity == "0.25",
        //某些浏览器不支持w3c的cssFloat属性来获取浮动样式，而是使用独家的styleFloat属性
        cssFloat: !!style.cssFloat,
        //IE678的getElementByTagName("*")无法遍历出Object元素下的param元素（bug）
        traverseAll: !!div[TAGS]("param").length,
        //https://prototype.lighthouseapp.com/projects/8886/tickets/264-ie-can-t-create-link-elements-from-html-literals
        //IE678不能通过innerHTML生成link,style,script节点（bug）
        createAll: !!div[TAGS]("link").length,
        //IE6789由于无法识别HTML5的新标签，因此复制这些新元素时也不正确（bug）
        cloneHTML5: DOC.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
        //在标准浏览器下，cloneNode(true)是不复制事件的，以防止循环引用无法释放内存，而IE却没有考虑到这一点，把事件复制了（inconformity）
        cloneNode: true,
        //现在只有firefox不支持focusin,focus事件,并且它也不支持DOMFocusIn,DOMFocusOut,并且此事件无法通过eventSupport来检测
        focusin : $["@bind"] === "attachEvent",//IE肯定支持
        //IE6789的innerHTML对于table,thead,tfoot,tbody,tr,col,colgroup,html,title,style,frameset是只读的（inconformity）
        innerHTML: false,
        //IE的insertAdjacentHTML与innerHTML一样，对于许多元素是只读的，另外FF8之前是不支持此API的
        insertAdjacentHTML: false,
        //是否支持createContextualFragment API，此方法发端于FF3，因此许多浏览器不支持或实现存在BUG，但它是将字符串转换为文档碎片的最高效手段
        fastFragment: false,
        //IE67不支持display:inline-block，需要通过hasLayout方法去模拟（bug）
        inlineBlock: true,
        //http://w3help.org/zh-cn/causes/RD1002
        //在IE678中，非替换元素在设置了大小与hasLayout的情况下，会将其父级元素撑大（inconformity）
        keepSize: true,
        //getComputedStyle API是否能支持将left, top的百分比原始值自动转换为像素值
        pixelPosition: true,
        transition: false
    };
    //IE6789的checkbox、radio控件在cloneNode(true)后，新元素没有继承原来的checked属性（bug）
    input.checked = true;
    support.cloneChecked = (input.cloneNode( true ).checked === true);
    support.appendChecked = input.checked;
    //添加对optDisabled,cloneAll,insertAdjacentHTML,innerHTML,fastFragment的特征嗅探
    //判定disabled的select元素内部的option元素是否也有diabled属性，没有才是标准
    //这个特性用来获取select元素的value值，特别是当select渲染为多选框时，需要注意从中去除disabled的option元素，
    //但在Safari中，获取被设置为disabled的select的值时，由于所有option元素都被设置为disabled，会导致无法获取值。
    select.disabled = true;
    support.optDisabled = !opt.disabled;
    var clickFn
    if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
        div.attachEvent("onclick", clickFn = function () {
            support.cloneNode = false;//w3c的节点复制是不复制事件的
        });
        div.cloneNode(true).fireEvent("onclick");
        div.detachEvent( "onclick", clickFn );
    }
    var table = div[TAGS]("table")[0]
    try{//检测innerHTML与insertAdjacentHTML在某些元素中是否存在只读（这时会抛错）
        table.innerHTML = "
1
";
        support.innerHTML = true;
        table.insertAdjacentHTML("afterBegin","
2
");
        support.insertAdjacentHTML = true;
    }catch(e){ };
    var endNames = {
        WebkitTransition : "webkitTransitionEnd",
        MozTransition    : "transitionend" ,
        OTransition      : "oTransitionEnd otransitionend" ,
        transition       : "transitionend"
    }
    for (var name in endNames){
        if (div.style[name] !== undefined) {
            support.transition  = {
                end: endNames[name]
            }
            break
        }
    }
    a = select = table = opt = style =  null;
    $.require("ready",function(){
        var body = DOC.body;
        if(!body)//frameset不存在body标签
            return;
        try{
            var range =  DOC.createRange();
            range.selectNodeContents(body); //fix opera(9.2~11.51) bug,必须对文档进行选取
            support.fastFragment = !!range.createContextualFragment("");
            $.commonRange = range;
        }catch(e){ };
        div.style.cssText = "position:absolute;top:-1000px;left:-1000px;"
        body.insertBefore( div, body.firstChild );
        var ib = '

';
        div.innerHTML = ib + ib;//div默认是block,因此两个DIV会上下排列0,但inline-block会让它们左右排列
        support.inlineBlock = div.offsetHeight < 40;//检测是否支持inlineBlock
        if( window.getComputedStyle ) {
            div.style.top = "1%";
            support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top  !== "1%";
        }
        div.style.cssText = "width:20px;"
        div.innerHTML = "

";
        support.keepSize = div.offsetWidth == 20;//检测是否会被子元素撑大
        //http://stackoverflow.com/questions/7337670/how-to-detect-focusin-support
        div.innerHTML = ""
        if(!support.focusin){
            var a = div.firstChild;
            a.addEventListener('focusin', function(){
                support.focusin = true;
            }, false);
            a.focus();
        }
        div.style.width = div.style.paddingLeft = "10px";//检测是否支持盒子模型
        support.boxModel = div.offsetWidth === 20;
        body.removeChild( div );
        div =  null;
    });

    return support;
});
/**
2011.9.7 优化attrProp判定
2011.9.16所有延时判定的部分现在可以立即判定了
2011.9.23增加fastFragment判定
2012.1.28有些特征嗅探必须连接到DOM树上才能进行
2012.5.22 精简插入DOM树后的五种检测
*/<commit_msg>修改一些特性的名字<commit_after>//==========================================
// 特征嗅探模块 by 司徒正美
//==========================================
define("support", function(){
    $.log("已加载特征嗅探模块",7);
    var DOC = document, div = DOC.createElement('div'),TAGS = "getElementsByTagName";
    div.setAttribute("className", "t");
    div.innerHTML = ' <link/>d'+
    '<object><param/></object>

<input type="checkbox" checked/>';
    var a = div[TAGS]("a")[0], style = a.style,
    select = DOC.createElement("select"),
    input = div[TAGS]( "input" )[ 0 ],
    opt = select.appendChild( DOC.createElement("option") );
    //true为正常，false为不正常
    var support = $.support = {
        //标准浏览器只有在table与tr之间不存在tbody的情况下添加tbody，而IE678则笨多了,即在里面为空也乱加tbody
        insertTbody: !div[TAGS]("tbody").length,
        // 在大多数游览器中checkbox的value默认为on，唯有chrome返回空字符串
        checkOn : input.value === "on",
        //当为select添加一个新option元素时，此option会被选中，但IE与早期的safari却没有这样做,需要访问一下其父元素后才能让它处于选中状态（bug）
        optSelected: !!opt.selected,
        //IE67，无法取得用户设定的原始href值
        attrInnateHref: a.getAttribute("href") === "/nasami",
        //IE67，无法取得用户设定的原始style值，只能返回el.style（CSSStyleDeclaration）对象(bug)
        attrInnateStyle: a.getAttribute("style") !== style,
        //IE67, 对于某些固有属性需要进行映射才可以用，如class, for, char，IE8及其他标准浏览器不需要
        attrInnateName:div.className !== "t",
        //IE6-8,对于某些固有属性不会返回用户最初设置的值
        attrInnateValue: input.getAttribute("checked") == "",
        //http://www.cnblogs.com/rubylouvre/archive/2010/05/16/1736535.html
        //是否能正确返回opacity的样式值，IE8返回".25" ，IE9pp2返回0.25，chrome等返回"0.25"
        cssOpacity: style.opacity == "0.25",
        //某些浏览器不支持w3c的cssFloat属性来获取浮动样式，而是使用独家的styleFloat属性
        cssFloat: !!style.cssFloat,
        //IE678的getElementByTagName("*")无法遍历出Object元素下的param元素（bug）
        traverseAll: !!div[TAGS]("param").length,
        //https://prototype.lighthouseapp.com/projects/8886/tickets/264-ie-can-t-create-link-elements-from-html-literals
        //IE678不能通过innerHTML生成link,style,script节点（bug）
        createAll: !!div[TAGS]("link").length,
        //IE6789由于无法识别HTML5的新标签，因此复制这些新元素时也不正确（bug）
        cloneHTML5: DOC.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
        //在标准浏览器下，cloneNode(true)是不复制事件的，以防止循环引用无法释放内存，而IE却没有考虑到这一点，把事件复制了（inconformity）
        cloneNode: true,
        //现在只有firefox不支持focusin,focus事件,并且它也不支持DOMFocusIn,DOMFocusOut,并且此事件无法通过eventSupport来检测
        focusin : $["@bind"] === "attachEvent",//IE肯定支持
        //IE6789的innerHTML对于table,thead,tfoot,tbody,tr,col,colgroup,html,title,style,frameset是只读的（inconformity）
        innerHTML: false,
        //IE的insertAdjacentHTML与innerHTML一样，对于许多元素是只读的，另外FF8之前是不支持此API的
        insertAdjacentHTML: false,
        //是否支持createContextualFragment API，此方法发端于FF3，因此许多浏览器不支持或实现存在BUG，但它是将字符串转换为文档碎片的最高效手段
        fastFragment: false,
        //IE67不支持display:inline-block，需要通过hasLayout方法去模拟（bug）
        inlineBlock: true,
        //http://w3help.org/zh-cn/causes/RD1002
        //在IE678中，非替换元素在设置了大小与hasLayout的情况下，会将其父级元素撑大（inconformity）
        keepSize: true,
        //getComputedStyle API是否能支持将left, top的百分比原始值自动转换为像素值
        pixelPosition: true,
        transition: false
    };
    //IE6789的checkbox、radio控件在cloneNode(true)后，新元素没有继承原来的checked属性（bug）
    input.checked = true;
    support.cloneChecked = (input.cloneNode( true ).checked === true);
    support.appendChecked = input.checked;
    //添加对optDisabled,cloneAll,insertAdjacentHTML,innerHTML,fastFragment的特征嗅探
    //判定disabled的select元素内部的option元素是否也有diabled属性，没有才是标准
    //这个特性用来获取select元素的value值，特别是当select渲染为多选框时，需要注意从中去除disabled的option元素，
    //但在Safari中，获取被设置为disabled的select的值时，由于所有option元素都被设置为disabled，会导致无法获取值。
    select.disabled = true;
    support.optDisabled = !opt.disabled;
    var clickFn
    if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
        div.attachEvent("onclick", clickFn = function () {
            support.cloneNode = false;//w3c的节点复制是不复制事件的
        });
        div.cloneNode(true).fireEvent("onclick");
        div.detachEvent( "onclick", clickFn );
    }
    var table = div[TAGS]("table")[0]
    try{//检测innerHTML与insertAdjacentHTML在某些元素中是否存在只读（这时会抛错）
        table.innerHTML = "
1
";
        support.innerHTML = true;
        table.insertAdjacentHTML("afterBegin","
2
");
        support.insertAdjacentHTML = true;
    }catch(e){ };
    var endNames = {
        WebkitTransition : "webkitTransitionEnd",
        MozTransition    : "transitionend" ,
        OTransition      : "oTransitionEnd otransitionend" ,
        transition       : "transitionend"
    }
    for (var name in endNames){
        if (div.style[name] !== undefined) {
            support.transition  = {
                end: endNames[name]
            }
            break
        }
    }
    a = select = table = opt = style =  null;
    $.require("ready",function(){
        var body = DOC.body;
        if(!body)//frameset不存在body标签
            return;
        try{
            var range =  DOC.createRange();
            range.selectNodeContents(body); //fix opera(9.2~11.51) bug,必须对文档进行选取
            support.fastFragment = !!range.createContextualFragment("");
            $.commonRange = range;
        }catch(e){ };
        div.style.cssText = "position:absolute;top:-1000px;left:-1000px;"
        body.insertBefore( div, body.firstChild );
        var ib = '

';
        div.innerHTML = ib + ib;//div默认是block,因此两个DIV会上下排列0,但inline-block会让它们左右排列
        support.inlineBlock = div.offsetHeight < 40;//检测是否支持inlineBlock
        if( window.getComputedStyle ) {
            div.style.top = "1%";
            support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top  !== "1%";
        }
        div.style.cssText = "width:20px;"
        div.innerHTML = "

";
        support.keepSize = div.offsetWidth == 20;//检测是否会被子元素撑大
        //http://stackoverflow.com/questions/7337670/how-to-detect-focusin-support
        div.innerHTML = ""
        if(!support.focusin){
            var a = div.firstChild;
            a.addEventListener('focusin', function(){
                support.focusin = true;
            }, false);
            a.focus();
        }
        div.style.width = div.style.paddingLeft = "10px";//检测是否支持盒子模型
        support.boxModel = div.offsetWidth === 20;
        body.removeChild( div );
        div =  null;
    });

    return support;
});
/**
2011.9.7 优化attrProp判定
2011.9.16所有延时判定的部分现在可以立即判定了
2011.9.23增加fastFragment判定
2012.1.28有些特征嗅探必须连接到DOM树上才能进行
2012.5.22 精简插入DOM树后的五种检测
*/<|endoftext|>


<commit_before>/**
 * Tests that color values are backed by a variable
 */
var async = require("async");
var parseColor = require("parse-color");
var traverse = require("traverse");

var indexToLocation = require("./index-to-location");
var walk = require("./walker").walk;

// Extract color values from a given rule
function getColorValues(rule) {
    var colors = [];

    // Scan the `rule.value` subtree for color values, and add them to the
    // colors array as 4-arrays (red, green, blue, and alpha).
    traverse(rule.value).forEach(function(node) {
        // Detect #RGB and #RRGGBB values, which are leaves in the tree.
        if (this.isLeaf) {
            if (/(#[0-9A-Fa-f]{3,6})/.test(node)) {
                // TODO: Can we point to this #?
                colors.push(parseColor(RegExp.$1).rgba);
            }
        } else {
            try {
                function getArgValue(arg) {
                    // Arguments are listed in the form:
                    //   {"args": [{"value": [{"value": X}]}, ...]}
                    var value = arg.value[0].value;

                    // If they're not, such as mathematical arguments pass to
                    // rgb() like "10 * 4", throw an error that we'll catch
                    // and ignore.
                    if (Number.isNaN(value) || !Number.isFinite(value)) {
                        throw new Error(
                            "Non-numeric value found for argument");
                    } else {
                        return value;
                    }
                }

                // Detect rgb() functions
                if (node.name === "rgb") {
                    var rgb = node.args.map(getArgValue);
                    // Concat an alpha value of 1
                    colors.push(rgb.concat([1]));

                // Detect rgba() functions
                } else if (node.name === "rgba") {
                    var rgba = node.args.map(getArgValue);
                    colors.push(rgba);

                // Detect {"rgb": [...], "alpha": X} nodes, which appear when
                // colors are passed as an argument to functions like mix()
                // and lighten()
                } else if (node.rgb) {
                    var rgba = node.rgb.concat([node.alpha]);
                    colors.push(rgba);
                }
            } catch (e) {
                // We assume the structure of rgb()/rgba() nodes. Which is the
                // case for normal usage such as rgb(0, 0, 0). Edge cases such
                // as rgb(10 + 20, 0, 0) we do not account for.
                //
                // Catch any exceptions and ignore them.
            }
        }
    });

    return colors;
}

// Walk the AST and store references to any color variables
function readColorVariables(root, storeColor, callback) {
    walk(root, function(rule, depth, done) {
        if (rule.variable) {
            getColorValues(rule).forEach(function(color) {
                storeColor(rule.name, rule.index, color);
            });
        }

        done();
    }, callback);
}

// Walk the AST and report any inline colors
function findInlineColors(root, reportInlineColor, callback) {
    walk(root, function(rule, depth, done) {
        // Ignore variables
        if (!rule.variable) {
            // Extract the colors from the rule and invoke
            // `reportInlineColor()` on each one.
            getColorValues(rule).forEach(function(inlineColor) {
                reportInlineColor(inlineColor, rule.index);
            });
        }

        done();
    }, callback);
}

// A very naive color distance formula, using the euclidean distance in
// 4-space
function euclideanColorDistance(colorA, colorB) {
    return Math.sqrt(
        // RGB
        Math.pow(colorA[0] - colorB[0], 2) +
        Math.pow(colorA[1] - colorB[1], 2) +
        Math.pow(colorA[2] - colorB[2], 2) +

        // Alpha, multiplied by 255 to give it the same importance as an
        // individual channel value
        Math.pow(colorA[3] * 255 - colorB[3] * 255, 2)
    );
}

// Find the closest match to a given color from a list of colors as extracted
// from color variables
function findClosestColor(inlineColor, storedColors) {
    var closestColor, closestColorDistance;

    // Cycle through the stored colors, keeping track of the closest color
    // via a 4-space euclidean distance, and its distance
    storedColors.forEach(function(storedColor) {
        var distance = euclideanColorDistance(
            storedColor.color, inlineColor);

        if (closestColorDistance === undefined ||
                distance < closestColorDistance) {
            closestColorDistance = distance;
            closestColor = storedColor;
        }
    });

    return {
        color: closestColor,
        distance: closestColorDistance,
    };
}

function colorVariableLint(code, ast, callback) {
    var storedColors = [];
    var violations = [];

    // Run two tasks in series
    async.series([

        // First, read (and store) any color variables in the AST. We'll use
        // these values to suggest colors close to the ones found inline.
        function(done) {
            readColorVariables(ast, function(name, index, color) {
                storedColors.push({
                    name: name,
                    location: indexToLocation(code, index),
                    color: color,
                });
            }, done);
        },

        // Then, scan the AST for inline colors, and attempt to suggest a
        // matching color backed by a variable.
        function(done) {
            // TODO: Use the inline color as it's written, instead of its
            // conversion to rgba.
            findInlineColors(ast, function(inlineColor, index) {
                var location = indexToLocation(code, index);
                var message = "Inline color rgba(" + inlineColor + ") found";

                // See if there is a matching color from our stored colors.
                // A distance of "35" is chosen somewhat arbitrarily.
                var match = findClosestColor(inlineColor, storedColors);
                if (match && match.distance < 35) {
                    message += ". Did you mean " + match.color.name +
                        " from line " + match.color.location.line + "?";
                }

                violations.push({
                    line: location.line,
                    character: location.column,
                    code: -1,
                    reason: message,
                });
            }, done);
        },
    ], function(err) {
        callback(err, violations);
    });
}

module.exports = colorVariableLint;
<commit_msg>break early if we find an exact match<commit_after>/**
 * Tests that color values are backed by a variable
 */
var async = require("async");
var parseColor = require("parse-color");
var traverse = require("traverse");

var indexToLocation = require("./index-to-location");
var walk = require("./walker").walk;

// Extract color values from a given rule
function getColorValues(rule) {
    var colors = [];

    // Scan the `rule.value` subtree for color values, and add them to the
    // colors array as 4-arrays (red, green, blue, and alpha).
    traverse(rule.value).forEach(function(node) {
        // Detect #RGB and #RRGGBB values, which are leaves in the tree.
        if (this.isLeaf) {
            if (/(#[0-9A-Fa-f]{3,6})/.test(node)) {
                // TODO: Can we point to this #?
                colors.push(parseColor(RegExp.$1).rgba);
            }
        } else {
            try {
                function getArgValue(arg) {
                    // Arguments are listed in the form:
                    //   {"args": [{"value": [{"value": X}]}, ...]}
                    var value = arg.value[0].value;

                    // If they're not, such as mathematical arguments pass to
                    // rgb() like "10 * 4", throw an error that we'll catch
                    // and ignore.
                    if (Number.isNaN(value) || !Number.isFinite(value)) {
                        throw new Error(
                            "Non-numeric value found for argument");
                    } else {
                        return value;
                    }
                }

                // Detect rgb() functions
                if (node.name === "rgb") {
                    var rgb = node.args.map(getArgValue);
                    // Concat an alpha value of 1
                    colors.push(rgb.concat([1]));

                // Detect rgba() functions
                } else if (node.name === "rgba") {
                    var rgba = node.args.map(getArgValue);
                    colors.push(rgba);

                // Detect {"rgb": [...], "alpha": X} nodes, which appear when
                // colors are passed as an argument to functions like mix()
                // and lighten()
                } else if (node.rgb) {
                    var rgba = node.rgb.concat([node.alpha]);
                    colors.push(rgba);
                }
            } catch (e) {
                // We assume the structure of rgb()/rgba() nodes. Which is the
                // case for normal usage such as rgb(0, 0, 0). Edge cases such
                // as rgb(10 + 20, 0, 0) we do not account for.
                //
                // Catch any exceptions and ignore them.
            }
        }
    });

    return colors;
}

// Walk the AST and store references to any color variables
function readColorVariables(root, storeColor, callback) {
    walk(root, function(rule, depth, done) {
        if (rule.variable) {
            getColorValues(rule).forEach(function(color) {
                storeColor(rule.name, rule.index, color);
            });
        }

        done();
    }, callback);
}

// Walk the AST and report any inline colors
function findInlineColors(root, reportInlineColor, callback) {
    walk(root, function(rule, depth, done) {
        // Ignore variables
        if (!rule.variable) {
            // Extract the colors from the rule and invoke
            // `reportInlineColor()` on each one.
            getColorValues(rule).forEach(function(inlineColor) {
                reportInlineColor(inlineColor, rule.index);
            });
        }

        done();
    }, callback);
}

// A very naive color distance formula, using the euclidean distance in
// 4-space
function euclideanColorDistance(colorA, colorB) {
    return Math.sqrt(
        // RGB
        Math.pow(colorA[0] - colorB[0], 2) +
        Math.pow(colorA[1] - colorB[1], 2) +
        Math.pow(colorA[2] - colorB[2], 2) +

        // Alpha, multiplied by 255 to give it the same importance as an
        // individual channel value
        Math.pow(colorA[3] * 255 - colorB[3] * 255, 2)
    );
}

// Find the closest match to a given color from a list of colors as extracted
// from color variables
function findClosestColor(inlineColor, storedColors) {
    var closestColor, closestColorDistance;

    // Cycle through the stored colors, keeping track of the closest color
    // via a 4-space euclidean distance, and its distance
    for (var i = 0; i < storedColors.length; i++) {
        var distance = euclideanColorDistance(
            storedColors[i].color, inlineColor);

        if (closestColorDistance === undefined ||
                distance < closestColorDistance) {
            closestColorDistance = distance;
            closestColor = storedColors[i];
        }

        // Break if we find an exact color
        if (closestColorDistance === 0) {
            break;
        }
    }

    return {
        color: closestColor,
        distance: closestColorDistance,
    };
}

function colorVariableLint(code, ast, callback) {
    var storedColors = [];
    var violations = [];

    // Run two tasks in series
    async.series([

        // First, read (and store) any color variables in the AST. We'll use
        // these values to suggest colors close to the ones found inline.
        function(done) {
            readColorVariables(ast, function(name, index, color) {
                storedColors.push({
                    name: name,
                    location: indexToLocation(code, index),
                    color: color,
                });
            }, done);
        },

        // Then, scan the AST for inline colors, and attempt to suggest a
        // matching color backed by a variable.
        function(done) {
            // TODO: Use the inline color as it's written, instead of its
            // conversion to rgba.
            findInlineColors(ast, function(inlineColor, index) {
                var location = indexToLocation(code, index);
                var message = "Inline color rgba(" + inlineColor + ") found";

                // See if there is a matching color from our stored colors.
                // A distance of "35" is chosen somewhat arbitrarily.
                var match = findClosestColor(inlineColor, storedColors);
                if (match && match.distance < 35) {
                    message += ". Did you mean " + match.color.name +
                        " from line " + match.color.location.line + "?";
                }

                violations.push({
                    line: location.line,
                    character: location.column,
                    code: -1,
                    reason: message,
                });
            }, done);
        },
    ], function(err) {
        callback(err, violations);
    });
}

module.exports = colorVariableLint;
<|endoftext|>


<commit_before>var NYC
try {
  NYC = require('../../index.covered.js')
} catch (e) {
  NYC = require('../../index.js')
}

exports.command = 'instrument <input> [output]'

exports.describe = 'instruments a file or a directory tree and writes the instrumented code to the desired output location'

exports.builder = function (yargs) {
  return yargs
    .usage('$0 instrument <input> [output]')
    .option('require', {
      alias: 'i',
      default: [],
      describe: 'a list of additional modules that nyc should attempt to require in its subprocess, e.g., babel-register, babel-polyfill.'
    })
    .option('extension', {
      alias: 'e',
      default: [],
      describe: 'a list of extensions that nyc should handle in addition to .js'
    })
    .option('source-map', {
      default: true,
      type: 'boolean',
      description: 'should nyc detect and handle source maps?'
    })
    .option('instrument', {
      default: true,
      type: 'boolean',
      description: 'should nyc handle instrumentation?'
    })
    .example('$0 instrument ./lib ./output', 'instrument all .js files in ./lib with coverage and output in ./output')
}

exports.handler = function (argv) {
  // if instrument is set to false,
  // enable a noop instrumenter.
  if (!argv.instrument) argv.instrumenter = './lib/instrumenters/noop'
  else argv.instrumenter = './lib/instrumenters/istanbul'

  var nyc = new NYC({
    instrumenter: argv.instrumenter,
    sourceMap: argv.sourceMap,
    extension: argv.extension,
    require: argv.require
  })

  nyc.instrumentAllFiles(argv.input, argv.output, function (err) {
    if (err) console.error(err.message)
    process.exit(1)
  })
}
<commit_msg>feat: allow instrument-only to produce sourcemaps (#674)<commit_after>var NYC
try {
  NYC = require('../../index.covered.js')
} catch (e) {
  NYC = require('../../index.js')
}

exports.command = 'instrument <input> [output]'

exports.describe = 'instruments a file or a directory tree and writes the instrumented code to the desired output location'

exports.builder = function (yargs) {
  return yargs
    .usage('$0 instrument <input> [output]')
    .option('require', {
      alias: 'i',
      default: [],
      describe: 'a list of additional modules that nyc should attempt to require in its subprocess, e.g., babel-register, babel-polyfill.'
    })
    .option('extension', {
      alias: 'e',
      default: [],
      describe: 'a list of extensions that nyc should handle in addition to .js'
    })
    .option('source-map', {
      default: true,
      type: 'boolean',
      description: 'should nyc detect and handle source maps?'
    })
    .option('produce-source-map', {
      default: false,
      type: 'boolean',
      description: "should nyc's instrumenter produce source maps?"
    })
    .option('instrument', {
      default: true,
      type: 'boolean',
      description: 'should nyc handle instrumentation?'
    })
    .example('$0 instrument ./lib ./output', 'instrument all .js files in ./lib with coverage and output in ./output')
}

exports.handler = function (argv) {
  // if instrument is set to false,
  // enable a noop instrumenter.
  if (!argv.instrument) argv.instrumenter = './lib/instrumenters/noop'
  else argv.instrumenter = './lib/instrumenters/istanbul'

  var nyc = new NYC({
    instrumenter: argv.instrumenter,
    sourceMap: argv.sourceMap,
    produceSourceMap: argv.produceSourceMap,
    extension: argv.extension,
    require: argv.require
  })

  nyc.instrumentAllFiles(argv.input, argv.output, function (err) {
    if (err) console.error(err.message)
    process.exit(1)
  })
}
<|endoftext|>


<commit_before>// Copyright 2014, Renasar Technologies Inc.
/* jshint node: true */

'use strict';

var di = require('di');

module.exports = SerializableFactory;

di.annotate(SerializableFactory, new di.Provide('Serializable'));
di.annotate(SerializableFactory,
    new di.Inject(
        'Q',
        'Assert',
        'Util',
        'Validatable',
        '_'
    )
);

function SerializableFactory (Q, assert, util, Validatable, _) {
    function Serializable(schema, defaults) {
        Validatable.call(this, schema);

        _.defaults(this, defaults);
    }

    util.inherits(Serializable, Validatable);

    Serializable.register = function (factory, constructor) {
        constructor.provides = util.provides(factory);
    };

    Serializable.prototype.serialize = function (target) {
        target = target || this;

        return Q.resolve()
            .then(function() {
                return _.cloneDeep(target)
            });
    };

    Serializable.prototype.deserialize = function (target) {
        _.defaults(this, target || {});

        return Q.resolve(this);
    };

    return Serializable;
}
<commit_msg>fix lint error in serializable<commit_after>// Copyright 2014, Renasar Technologies Inc.
/* jshint node: true */

'use strict';

var di = require('di');

module.exports = SerializableFactory;

di.annotate(SerializableFactory, new di.Provide('Serializable'));
di.annotate(SerializableFactory,
    new di.Inject(
        'Q',
        'Assert',
        'Util',
        'Validatable',
        '_'
    )
);

function SerializableFactory (Q, assert, util, Validatable, _) {
    function Serializable(schema, defaults) {
        Validatable.call(this, schema);

        _.defaults(this, defaults);
    }

    util.inherits(Serializable, Validatable);

    Serializable.register = function (factory, constructor) {
        constructor.provides = util.provides(factory);
    };

    Serializable.prototype.serialize = function (target) {
        target = target || this;

        return Q.resolve()
            .then(function() {
                return _.cloneDeep(target);
            });
    };

    Serializable.prototype.deserialize = function (target) {
        _.defaults(this, target || {});

        return Q.resolve(this);
    };

    return Serializable;
}
<|endoftext|>


<commit_before>//
// release_initializer.js - read user's program and eval it (if it exists)
//
// This file is put on the end the lib/biwascheme.js.
//
(function(){ //local namespace

  // readAttribute (taken from prototype.js 1.6.0)
  var readAttribute = function(element, name) {
    if (/*Prototype.Browser.IE*/ !!(window.attachEvent && !window.opera)){
      var t = {
        names: {
          'class': 'className',
          'for':   'htmlFor'
        },
        values: {
          _getAttr: function(element, attribute) {
            return element.getAttribute(attribute, 2);
          },
          _getAttrNode: function(element, attribute) {
            var node = element.getAttributeNode(attribute);
            return node ? node.value : "";
          },
          _getEv: function(element, attribute) {
            var attribute = element.getAttribute(attribute);
            return attribute ? attribute.toString().slice(23, -2) : null;
          },
          _flag: function(element, attribute) {
            return $(element).hasAttribute(attribute) ? attribute : null;
          },
          style: function(element) {
            return element.style.cssText.toLowerCase();
          },
          title: function(element) {
            return element.title;
          }
        }
      };
      if (t.values[name]) return t.values[name](element, name);
      if (t.names[name]) name = t.names[name];
      if (name.indexOf(':') > -1){
        return (!element.attributes || !element.attributes[name]) ? null :
         element.attributes[name].value;
      }
    }
    return element.getAttribute(name);
  }

  // Find the script tag
  var find_script_tag = function(e){
    if (e == null) {
	return e;
    }
    else if(e.nodeName.toLowerCase() == 'script'){
      return e;
    }
    else if(e.id == '_firebugConsole'){
      if(e.previousSibling.nodeName.toLowerCase() == 'script')
        return e.previousSibling;
      else
        console.error("BiwaScheme could not find the script tag... please use firebug 1.5.0")
    }
    else{
      return find_script_tag(e.lastChild);
    }
  };
  var script = find_script_tag(document);

  // Error handler (show message to console div)
  var onError = function(e, state){
    puts(e.message);
    if($("biwascheme-debugger")){
      var dumper = new BiwaScheme.Dumper($("biwascheme-debugger"));
      dumper.dump(new Hash(state));
      dumper.dump_move(1);
    }
    throw(e);
  }

  // Start user's program
  if (!script) {
    var intp = new BiwaScheme.Interpreter(onError);
    try{
      intp.evaluate(script.innerHTML, Prototype.emptyFunction);
    }
    catch(e){
      onError(e);
    }
  }
})();
<commit_msg>Fix a typo: evaluate script only if script tag is AVAILABLE.<commit_after>//
// release_initializer.js - read user's program and eval it (if it exists)
//
// This file is put on the end the lib/biwascheme.js.
//
(function(){ //local namespace

  // readAttribute (taken from prototype.js 1.6.0)
  var readAttribute = function(element, name) {
    if (/*Prototype.Browser.IE*/ !!(window.attachEvent && !window.opera)){
      var t = {
        names: {
          'class': 'className',
          'for':   'htmlFor'
        },
        values: {
          _getAttr: function(element, attribute) {
            return element.getAttribute(attribute, 2);
          },
          _getAttrNode: function(element, attribute) {
            var node = element.getAttributeNode(attribute);
            return node ? node.value : "";
          },
          _getEv: function(element, attribute) {
            var attribute = element.getAttribute(attribute);
            return attribute ? attribute.toString().slice(23, -2) : null;
          },
          _flag: function(element, attribute) {
            return $(element).hasAttribute(attribute) ? attribute : null;
          },
          style: function(element) {
            return element.style.cssText.toLowerCase();
          },
          title: function(element) {
            return element.title;
          }
        }
      };
      if (t.values[name]) return t.values[name](element, name);
      if (t.names[name]) name = t.names[name];
      if (name.indexOf(':') > -1){
        return (!element.attributes || !element.attributes[name]) ? null :
         element.attributes[name].value;
      }
    }
    return element.getAttribute(name);
  }

  // Find the script tag
  var find_script_tag = function(e){
    if (e == null) {
	return e;
    }
    else if(e.nodeName.toLowerCase() == 'script'){
      return e;
    }
    else if(e.id == '_firebugConsole'){
      if(e.previousSibling.nodeName.toLowerCase() == 'script')
        return e.previousSibling;
      else
        console.error("BiwaScheme could not find the script tag... please use firebug 1.5.0")
    }
    else{
      return find_script_tag(e.lastChild);
    }
  };
  var script = find_script_tag(document);

  // Error handler (show message to console div)
  var onError = function(e, state){
    puts(e.message);
    if($("biwascheme-debugger")){
      var dumper = new BiwaScheme.Dumper($("biwascheme-debugger"));
      dumper.dump(new Hash(state));
      dumper.dump_move(1);
    }
    throw(e);
  }

  // Start user's program
  if (script) {
    var intp = new BiwaScheme.Interpreter(onError);
    try{
      intp.evaluate(script.innerHTML, Prototype.emptyFunction);
    }
    catch(e){
      onError(e);
    }
  }
})();
<|endoftext|>


<commit_before>'use strict';
const ms = require('ms');
const EVENTS = ['on', 'run', 'success', 'error'];

module.exports = function controlledSchedule(task) {
  if (!task)
    throw new Error('Task not provided');
  if (typeof task !== 'function')
    throw new Error('Task has to be a function');

  return createSchedule(task);
};

function createSchedule(_task) {
  let self = {};
  let task = _task;
  let milliseconds = 0;
  let currentTimeout = null;
  let stopped = true;
  let callbacks = {};

  function every(duration) {
    milliseconds = isNaN(duration) ? ms(duration) : duration;
    return self;
  }

  function start() {
    stopped = false;
    startSchedule(task, milliseconds);
    return self;
  }

  function startIn(time) {
    stopped = false;
    currentTimeout =
      setTimeout(function() {
        startSchedule(task, milliseconds);
      }, (isNaN(time) ? ms(time) : time));
    return self;
  }

  function stop() {
    clearTimeout(currentTimeout);
    currentTimeout = null;
    stopped = true;
    return self;
  }

  function stopAfter(time) {
    let stopTime = isNaN(time) ? ms(time) : time;

    setTimeout(function() {
      stop();
    }, stopTime);

    return self;
  }

  function startSchedule(task, milliseconds) {
    task()
      .then(function(value) {
        triggerSuccessCallbacks(value);

        if (stopped) return;

        currentTimeout =
          setTimeout(function() {
            startSchedule(task, milliseconds);
          }, milliseconds);
      })
      .catch(triggerErrorCallbacks);
  }

  function triggerSuccessCallbacks(value) {
    if (callbacks['run'])
      callbacks['run'](null, value);

    if (callbacks['success'])
      callbacks['success'](value);
  }

  function triggerErrorCallbacks(err) {
    if (callbacks['run'])
      callbacks['run'](err);

    if (callbacks['error'])
      callbacks['error'](err);
  }

  function on(eventName, callback) {
    if (EVENTS.indexOf(eventName) === -1)
      throw new Error(`Event ${eventName} does not exist`);
    callbacks[eventName] = callback;
  }

  Object.assign(self, {
    start,
    startIn,
    every,
    stop,
    stopAfter,
    on
  });

  return self;
}
<commit_msg>Added return on 'on' method to allow chaining<commit_after>'use strict';
const ms = require('ms');
const EVENTS = ['on', 'run', 'success', 'error'];

module.exports = function controlledSchedule(task) {
  if (!task)
    throw new Error('Task not provided');
  if (typeof task !== 'function')
    throw new Error('Task has to be a function');

  return createSchedule(task);
};

function createSchedule(_task) {
  let self = {};
  let task = _task;
  let milliseconds = 0;
  let currentTimeout = null;
  let stopped = true;
  let callbacks = {};

  function every(duration) {
    milliseconds = isNaN(duration) ? ms(duration) : duration;
    return self;
  }

  function start() {
    stopped = false;
    startSchedule(task, milliseconds);
    return self;
  }

  function startIn(time) {
    stopped = false;
    currentTimeout =
      setTimeout(function() {
        startSchedule(task, milliseconds);
      }, (isNaN(time) ? ms(time) : time));
    return self;
  }

  function stop() {
    clearTimeout(currentTimeout);
    currentTimeout = null;
    stopped = true;
    return self;
  }

  function stopAfter(time) {
    let stopTime = isNaN(time) ? ms(time) : time;

    setTimeout(function() {
      stop();
    }, stopTime);

    return self;
  }

  function startSchedule(task, milliseconds) {
    task()
      .then(function(value) {
        triggerSuccessCallbacks(value);

        if (stopped) return;

        currentTimeout =
          setTimeout(function() {
            startSchedule(task, milliseconds);
          }, milliseconds);
      })
      .catch(triggerErrorCallbacks);
  }

  function triggerSuccessCallbacks(value) {
    if (callbacks['run'])
      callbacks['run'](null, value);

    if (callbacks['success'])
      callbacks['success'](value);
  }

  function triggerErrorCallbacks(err) {
    if (callbacks['run'])
      callbacks['run'](err);

    if (callbacks['error'])
      callbacks['error'](err);
  }

  function on(eventName, callback) {
    if (EVENTS.indexOf(eventName) === -1)
      throw new Error(`Event ${eventName} does not exist`);
    callbacks[eventName] = callback;
    return self;
  }

  Object.assign(self, {
    start,
    startIn,
    every,
    stop,
    stopAfter,
    on
  });

  return self;
}
<|endoftext|>


<commit_before>module.exports.insertDocs = function(req, res, next) {
  req.collection.insert(req.body, {}, function(e, results){
    if (e) {
      res.send("Failed to insert docs", e)
    }
    else {
      res.send(results)
    }
    next()
  })
}

module.exports.insertPlaces = function(req, res, next) {
  req.collection.ensureIndex( {loc: '2dsphere'}, {}, function(e) {
    if (e) {
      res.send("Failed to insert locations", e)
    }
    else {
      req.collection.insert(req.body, {}, function(e, results){
        if (e) {
          res.send("Failed to insert locations", e)
        }
        else {
          res.send(results)
        }
        next()
      })
    }
  })
}

module.exports.insertById = function(req, res, next) {
  var obj = req.body
  obj._id = req.params.id
  req.collection.insert(obj, {forceServerObjectId: true}, function(e, results){
    if (e) {
      res.send("Failed to insert doc", e)
    }
    else {
      res.send(results)
    }
    next()
  })
}

module.exports.updateById = function(req, res, next) {
  req.collection.updateById(req.params.id, {$set:req.body}, {safe:true, multi:false}, function(e, result){
    if (e) {
      res.send("Failed to update doc", e)
    }
    else {
      res.send((result===1)?{msg:'success'}:{msg:'error'})
    }
    next()
  })
}

module.exports.deleteById = function(req, res, next) {
  req.collection.removeById(req.params.id, function(e, result){
    if (e) {
      res.send("Failed to delete doc", e)
    }
    else {
      res.send((result===1)?{msg:'success'}:{msg:'error'})
    }
    next()
  })
}

module.exports.createCollection = function(req, res, next) {
  req.db.createCollection(req.params.colName, function(e, result) {
    if (!e) {
      res.send({msg:'success'})
    }
    else {
      res.send({msg:'error'})
    }
    next()
  })
}

module.exports.deleteCollection = function(req, res, next) {
  req.db.dropCollection(req.params.colName, function(e, result) {
    if (e) {
      res.send("Failed to delete collection", e)
    }
    else {
      res.send((result===true)?{msg:'success'}:{msg:'error'})
    }
    next()
  })
}

module.exports.renameCollection = function(req, res, next) {
  req.db.renameCollection(req.params.colName, req.body.name, function(e, result) {
    if (!e) {
      res.send({msg:'success'})
    }
    else {
      res.send({msg:'error'})
    }
    next()
  })
}

module.exports.patchDocs = function(req, res, next) {
  req.collection.update(req.body[0], {$set:req.body[1]}, {safe:true, multi:true}, function(e, result){
    if (e) {
      res.send("Failed to patch docs", e)
    }
    else {
      res.send((result===1)?{msg:'success'}:{msg:'error'})
    }
    next()
  })
}

module.exports.patchPlaces = function(req, res, next) {
  req.collection.update({$and:[req.body[0], {"loc": {"$exists": true}}]}, {$set:req.body[1]}, {safe:true, multi:true}, function(e, result){
    if (e) {
      res.send("Failed to patch docs", e)
    }
    else {
      res.send((result===1)?{msg:'success'}:{msg:'error'})
    }
    next()
  })
}

module.exports.deleteDocs = function(req, res, next) {
  req.collection.remove(req.body, function(e, result){
    if (e) {
      res.send("Failed to delete docs", e)
    }
    else {
      res.send((!e)?{msg:'success'}:{msg:'error'})
    }
    next()
  })
}

module.exports.deletePlaces = function(req, res, next) {
  req.collection.remove({$and:[req.body, {"loc": {"$exists": true}}]}, function(e, result){
    if (e) {
      res.send("Failed to delete docs", e)
    }
    else {
      res.send((!e)?{msg:'success'}:{msg:'error'})
    }
    next()
  })
}
<commit_msg>add close db in command<commit_after>module.exports.insertDocs = function(req, res, next) {
  req.collection.insert(req.body, {}, function(e, results){
    if (e) {
      res.send("Failed to insert docs", e)
    }
    else {
      res.send(results)
    }
    req.db.close()
    next()
  })
}

module.exports.insertPlaces = function(req, res, next) {
  req.collection.ensureIndex( {loc: '2dsphere'}, {}, function(e) {
    if (e) {
      res.send("Failed to insert locations", e)
    }
    else {
      req.collection.insert(req.body, {}, function(e, results){
        if (e) {
          res.send("Failed to insert locations", e)
        }
        else {
          res.send(results)
        }
        next()
      })
    }
    req.db.close()
  })
}

module.exports.insertById = function(req, res, next) {
  var obj = req.body
  obj._id = req.params.id
  req.collection.insert(obj, {forceServerObjectId: true}, function(e, results){
    if (e) {
      res.send("Failed to insert doc", e)
    }
    else {
      res.send(results)
    }
    req.db.close()
    next()
  })
}

module.exports.updateById = function(req, res, next) {
  req.collection.updateById(req.params.id, {$set:req.body}, {safe:true, multi:false}, function(e, result){
    if (e) {
      res.send("Failed to update doc", e)
    }
    else {
      res.send((result===1)?{msg:'success'}:{msg:'error'})
    }
    req.db.close()
    next()
  })
}

module.exports.deleteById = function(req, res, next) {
  req.collection.removeById(req.params.id, function(e, result){
    if (e) {
      res.send("Failed to delete doc", e)
    }
    else {
      res.send((result===1)?{msg:'success'}:{msg:'error'})
    }
    req.db.close()
    next()
  })
}

module.exports.createCollection = function(req, res, next) {
  req.db.createCollection(req.params.colName, function(e, result) {
    if (!e) {
      res.send({msg:'success'})
    }
    else {
      res.send({msg:'error'})
    }
    req.db.close()
    next()
  })
}

module.exports.deleteCollection = function(req, res, next) {
  req.db.dropCollection(req.params.colName, function(e, result) {
    if (e) {
      res.send("Failed to delete collection", e)
    }
    else {
      res.send((result===true)?{msg:'success'}:{msg:'error'})
    }
    req.db.close()
    next()
  })
}

module.exports.renameCollection = function(req, res, next) {
  req.db.renameCollection(req.params.colName, req.body.name, function(e, result) {
    if (!e) {
      res.send({msg:'success'})
    }
    else {
      res.send({msg:'error'})
    }
    req.db.close()
    next()
  })
}

module.exports.patchDocs = function(req, res, next) {
  req.collection.update(req.body[0], {$set:req.body[1]}, {safe:true, multi:true}, function(e, result){
    if (e) {
      res.send("Failed to patch docs", e)
    }
    else {
      res.send((result===1)?{msg:'success'}:{msg:'error'})
    }
    req.db.close()
    next()
  })
}

module.exports.patchPlaces = function(req, res, next) {
  req.collection.update({$and:[req.body[0], {"loc": {"$exists": true}}]}, {$set:req.body[1]}, {safe:true, multi:true}, function(e, result){
    if (e) {
      res.send("Failed to patch docs", e)
    }
    else {
      res.send((result===1)?{msg:'success'}:{msg:'error'})
    }
    req.db.close()
    next()
  })
}

module.exports.deleteDocs = function(req, res, next) {
  req.collection.remove(req.body, function(e, result){
    if (e) {
      res.send("Failed to delete docs", e)
    }
    else {
      res.send((!e)?{msg:'success'}:{msg:'error'})
    }
    req.db.close()
    next()
  })
}

module.exports.deletePlaces = function(req, res, next) {
  req.collection.remove({$and:[req.body, {"loc": {"$exists": true}}]}, function(e, result){
    if (e) {
      res.send("Failed to delete docs", e)
    }
    else {
      res.send((!e)?{msg:'success'}:{msg:'error'})
    }
    req.db.close()
    next()
  })
}
<|endoftext|>


<commit_before>/*jslint node: true */
'use strict';

var __ = require('lodash');
var async = require('async');

var Response = require('../models/Response');
var Survey = require('../models/Survey');
var User = require('../models/User');
var util = require('../util');

exports.list = function list(req, res) {
  var query;
  if(req.user) {
    query = {
      users: req.user._id
    };
  }else {
    res.send(401);
    return;
  }

  Survey.find(query)
  .lean()
  .exec(function (error, surveys) {
    if (util.handleError(error, res)) { return; }
    res.send({ surveys: surveys });
  });
};

exports.get = function get(req, res) {
  var surveyId = req.params.surveyId;
  var survey;

  // TODO: We can get the count and bounds in parallel and maybe even roll them
  // into one aggregation pipeline.
  async.waterfall([
    function (next) {
      Survey.findOne({ id: surveyId }).lean().exec(next);
    },
    function (result, next) {
      if (!result) {
        res.send(404);
        return;
      }
      survey = result;
      Response.countEntries({ 'properties.survey': surveyId }, next);
    },
    function (count, next) {
      survey.responseCount = count;
      Response.getBounds(surveyId, next);
    }
  ], function (error, bounds) {
    if (util.handleError(error, res)) { return; }

    survey.responseBounds = bounds;
    res.send({ survey: survey });
  });
};

// Get all users belonging to a survey
exports.users = function users(req, res) {
  var surveyId = req.params.surveyId;
  var survey;

  // Find the user IDs
  Survey.findOne({ id: surveyId })
        .select('users')
        .lean()
        .exec(function(error, survey) {

    // Now get the data for each of these users
    User.find({ "_id": { $in: survey.users}})
        .lean()
        .select('name _id email')
        .exec(function(error, users){

      if (util.handleError(error, res)) { return; }
      res.send({ users: users });
    });
  });
};

exports.addUser = function addUser(req, res) {
  var surveyId = req.params.surveyId;
  var email = req.params.email;
  email = email.toLowerCase();

  Survey.findOne({ id: surveyId }).select('users').exec(function(error, survey){
    User.findOne({ email: email }, function (error, user) {

      if (error) {
        res.send({ name: 'UserQueryError', message: 'We were not able to add the user at this time' }, 400);
        return;
      }
      if(!user) {
        res.send({ name: 'UserNotFoundError', message: 'User not found' }, 400);
        return;
      }

      // Add the user to the survey users
      if(! __.contains(survey.users, user._id)) {
        survey.users.push(user._id.toString());
      }

      // Save the survey
      Survey.update({ id: surveyId}, { users: survey.users}, function(err, doc) {
        if (err) {
          res.send({ name: 'SurveySaveError', message: "We couldn't add the user" }, 400);
          return;
        }
        res.send({ survey: doc });
        return;
      });
    });
  });
};

exports.removeUser = function addUser(req, res) {
  var surveyId = req.params.surveyId;
  var email = req.params.email;
  email = email.toLowerCase();

  Survey.findOne({ id: surveyId }).select('users').exec(function(error, survey){
    User.findOne({ email: email }, function (error, user) {
      if (error) {
        res.send({ name: 'UserQueryError', message: 'We were not able to add the user at this time' }, 400);
        return;
      }
      if(!user) {
        res.send({ name: 'UserNotFoundError', message: 'User not found' }, 400);
        return;
      }

      // Remove the user ID from the list
      survey.users = __.without(survey.users, user._id.toString());

      //Save the survey
      Survey.update({ id: surveyId }, { users: survey.users }, function(error, success) {
        if (error) {
          res.send({ name: 'SurveySaveError', message: "We couldn't add the user" }, 400);
          return;
        }
        res.send(204);
        return;
      });
    });
  });
};

/**
 * Get statistics for a survey
 *
 * Add the comma-separated coordinates of a polygon to limit the
 * stats to a geographic area
 *
 * https://localhost:3001/api/surveys/123/stats
 * https://localhost:3001/api/surveys/123/stats?intersects=[GeoJSON Polygon]
 */
exports.stats = function getStats(req, res) {
  var stats = {
    Collectors: {}
  };
  var count = 0;

  var surveyId = req.params.surveyId;
  var intersects = req.query.intersects;

  function summer(memo, num) {
    return memo + num;
  }

  function handleDoc(doc) {
    var key,
        val;

    count += 1;

    var index = doc.entries.length - 1;
    var entry = doc.entries[index];

    // If the latest entry has no responses, then find the most recent entry
    // that has data.
    while (!entry.responses) {
      index -= 1;
      // If there are no responses at all, then we do nothing with this doc.
      if (index < 0) {
        return;
      }
      entry = doc.entries[index];
    }

    // Record the collector
    key = entry.source.collector;
    val = stats.Collectors[key];
    if (val !== undefined) {
      val += 1;
    } else {
      val = 1;
    }
    stats.Collectors[key] = val;

    // Count the answers
    var r = entry.responses;
    Object.keys(r).forEach(function (key) {
      var val = r[key];
      var question = stats[key];
      if (question === undefined) {
        question = stats[key] = {};
        question[val] = 1;
      } else {
        var tally = question[val];
        if (tally === undefined) {
          tally = 1;
        } else {
          tally += 1;
        }
        question[val] = tally;
      }
    });
  }

  var query = {
    'properties.survey': surveyId
  };

  // Decode any geospatial limits
  if (intersects !== undefined) {
    decodeURIComponent(intersects);
    var polygon = JSON.parse(intersects);

    query.indexedGeometry = {
      $geoIntersects: {
        $geometry: polygon
      }
    };
  }

  function getChunk(start, done) {
    var length = 5000;
    Response.find(query, 'entries')
    .skip(start).limit(length)
    .lean()
    .exec(function (error, chunk) {
      if (error) {
        done(error);
        return;
      }

      var i;
      for (i = 0; i < chunk.length; i += 1) {
        handleDoc(chunk[i]);
      }

      if (chunk.length === length) {
        getChunk(start + length, done);
      } else {
        done(null);
      }
    });
  }

  getChunk(0, function (error) {
    if (error) {
      console.log(error);
      console.log(error.stack);
      res.send(500);
      return;
    }

    if (count === 0) {
      // Make sure the survey exists. We don't check beforehand because it
      // saves a query in the most common case.
      Survey.findOne({
        id: surveyId
      })
      .lean()
      .exec(function (error, survey) {
        if (util.handleError(error, res)) { return; }
        if (survey === null) {
          res.send(404);
        } else {
          res.send({
            stats: stats
          });
        }
      });
      return;
    }

    // Calculate "no response" count for each question
    Object.keys(stats).forEach(function (key) {
      var stat = stats[key];
      var sum = __.reduce(stat, summer, 0);
      var remainder = count - sum;

      stats[key]['no response'] = remainder;
    });

    res.send({
      stats: stats
    });

  });
};

exports.post = function post(req, response) {
  var i;
  var data = req.body.surveys;
  var output = [];
  var count = data.length;
  var itemError = null;

  for (i = 0; i < data.length; i++) {
    data[i].users = [req.user._id];
  }

  Survey.create(data, function (error) {
    if (error) {
      itemError = error;
      console.log(error);
      if (error.name === 'ValidationError') {
        response.send(400, error);
      } else {
        response.send(500);
      }
      return;
    }

    var output = Array.prototype.slice.call(arguments, 1).map(function (doc) {
      return doc.toObject();
    });

    var name = req.user.name;
    var link =  'https://' + req.headers.host + '/#surveys/' + output[0].slug;
    console.info('INFO: Survey created. User: ' + name + '; Link: ' + link);
    response.send(201, { surveys: output });
  });
};

exports.put = function put(req, response) {
  var surveyId = req.params.surveyId;
  var survey = req.body.survey;

  // Update the survey, asking MongoDB to return the updated document.
  Survey.findOneAndUpdate({ id: surveyId }, survey, function (error, updated) {
    if (error) {
      console.log(error);
      response.send(500);
      return;
    }

    response.send({ survey: updated.toObject() });
  });
};

// Get the survey ID associated with a slug
// Not authenticated.
exports.getSlug = function getSlug(req, res) {
  Survey.findOne({
    slug: req.params.slug
  })
  .lean()
  .exec(function (error, survey) {
    if (util.handleError(error, res)) { return; }
    if (survey === null) {
      res.send(404);
    } else {
      res.send({ survey: survey.id });
    }
  });
};
<commit_msg>Use 500 error code instead of 400 for survey save errors<commit_after>/*jslint node: true */
'use strict';

var __ = require('lodash');
var async = require('async');

var Response = require('../models/Response');
var Survey = require('../models/Survey');
var User = require('../models/User');
var util = require('../util');

exports.list = function list(req, res) {
  var query;
  if(req.user) {
    query = {
      users: req.user._id
    };
  }else {
    res.send(401);
    return;
  }

  Survey.find(query)
  .lean()
  .exec(function (error, surveys) {
    if (util.handleError(error, res)) { return; }
    res.send({ surveys: surveys });
  });
};

exports.get = function get(req, res) {
  var surveyId = req.params.surveyId;
  var survey;

  // TODO: We can get the count and bounds in parallel and maybe even roll them
  // into one aggregation pipeline.
  async.waterfall([
    function (next) {
      Survey.findOne({ id: surveyId }).lean().exec(next);
    },
    function (result, next) {
      if (!result) {
        res.send(404);
        return;
      }
      survey = result;
      Response.countEntries({ 'properties.survey': surveyId }, next);
    },
    function (count, next) {
      survey.responseCount = count;
      Response.getBounds(surveyId, next);
    }
  ], function (error, bounds) {
    if (util.handleError(error, res)) { return; }

    survey.responseBounds = bounds;
    res.send({ survey: survey });
  });
};

// Get all users belonging to a survey
exports.users = function users(req, res) {
  var surveyId = req.params.surveyId;
  var survey;

  // Find the user IDs
  Survey.findOne({ id: surveyId })
        .select('users')
        .lean()
        .exec(function(error, survey) {

    // Now get the data for each of these users
    User.find({ "_id": { $in: survey.users}})
        .lean()
        .select('name _id email')
        .exec(function(error, users){

      if (util.handleError(error, res)) { return; }
      res.send({ users: users });
    });
  });
};

exports.addUser = function addUser(req, res) {
  var surveyId = req.params.surveyId;
  var email = req.params.email;
  email = email.toLowerCase();

  Survey.findOne({ id: surveyId }).select('users').exec(function(error, survey){
    User.findOne({ email: email }, function (error, user) {

      if (error) {
        res.send({ name: 'UserQueryError', message: 'We were not able to add the user at this time' }, 500);
        return;
      }
      if(!user) {
        res.send({ name: 'UserNotFoundError', message: 'User not found' }, 400);
        return;
      }

      // Add the user to the survey users
      if(! __.contains(survey.users, user._id)) {
        survey.users.push(user._id.toString());
      }

      // Save the survey
      Survey.update({ id: surveyId}, { users: survey.users}, function(err, doc) {
        if (err) {
          res.send({ name: 'SurveySaveError', message: "We were not able to add the user at this time" }, 500);
          return;
        }
        res.send({ survey: doc });
        return;
      });
    });
  });
};

exports.removeUser = function addUser(req, res) {
  var surveyId = req.params.surveyId;
  var email = req.params.email;
  email = email.toLowerCase();

  Survey.findOne({ id: surveyId }).select('users').exec(function(error, survey){
    User.findOne({ email: email }, function (error, user) {
      if (error) {
        res.send({ name: 'UserQueryError', message: 'We were not able to add the user at this time' }, 500);
        return;
      }
      if(!user) {
        res.send({ name: 'UserNotFoundError', message: 'User not found' }, 400);
        return;
      }

      // Remove the user ID from the list
      survey.users = __.without(survey.users, user._id.toString());

      //Save the survey
      Survey.update({ id: surveyId }, { users: survey.users }, function(error, success) {
        if (error) {
          res.send({ name: 'SurveySaveError', message: "We were not able to remove the user at this time" }, 500);
          return;
        }
        res.send(204);
        return;
      });
    });
  });
};

/**
 * Get statistics for a survey
 *
 * Add the comma-separated coordinates of a polygon to limit the
 * stats to a geographic area
 *
 * https://localhost:3001/api/surveys/123/stats
 * https://localhost:3001/api/surveys/123/stats?intersects=[GeoJSON Polygon]
 */
exports.stats = function getStats(req, res) {
  var stats = {
    Collectors: {}
  };
  var count = 0;

  var surveyId = req.params.surveyId;
  var intersects = req.query.intersects;

  function summer(memo, num) {
    return memo + num;
  }

  function handleDoc(doc) {
    var key,
        val;

    count += 1;

    var index = doc.entries.length - 1;
    var entry = doc.entries[index];

    // If the latest entry has no responses, then find the most recent entry
    // that has data.
    while (!entry.responses) {
      index -= 1;
      // If there are no responses at all, then we do nothing with this doc.
      if (index < 0) {
        return;
      }
      entry = doc.entries[index];
    }

    // Record the collector
    key = entry.source.collector;
    val = stats.Collectors[key];
    if (val !== undefined) {
      val += 1;
    } else {
      val = 1;
    }
    stats.Collectors[key] = val;

    // Count the answers
    var r = entry.responses;
    Object.keys(r).forEach(function (key) {
      var val = r[key];
      var question = stats[key];
      if (question === undefined) {
        question = stats[key] = {};
        question[val] = 1;
      } else {
        var tally = question[val];
        if (tally === undefined) {
          tally = 1;
        } else {
          tally += 1;
        }
        question[val] = tally;
      }
    });
  }

  var query = {
    'properties.survey': surveyId
  };

  // Decode any geospatial limits
  if (intersects !== undefined) {
    decodeURIComponent(intersects);
    var polygon = JSON.parse(intersects);

    query.indexedGeometry = {
      $geoIntersects: {
        $geometry: polygon
      }
    };
  }

  function getChunk(start, done) {
    var length = 5000;
    Response.find(query, 'entries')
    .skip(start).limit(length)
    .lean()
    .exec(function (error, chunk) {
      if (error) {
        done(error);
        return;
      }

      var i;
      for (i = 0; i < chunk.length; i += 1) {
        handleDoc(chunk[i]);
      }

      if (chunk.length === length) {
        getChunk(start + length, done);
      } else {
        done(null);
      }
    });
  }

  getChunk(0, function (error) {
    if (error) {
      console.log(error);
      console.log(error.stack);
      res.send(500);
      return;
    }

    if (count === 0) {
      // Make sure the survey exists. We don't check beforehand because it
      // saves a query in the most common case.
      Survey.findOne({
        id: surveyId
      })
      .lean()
      .exec(function (error, survey) {
        if (util.handleError(error, res)) { return; }
        if (survey === null) {
          res.send(404);
        } else {
          res.send({
            stats: stats
          });
        }
      });
      return;
    }

    // Calculate "no response" count for each question
    Object.keys(stats).forEach(function (key) {
      var stat = stats[key];
      var sum = __.reduce(stat, summer, 0);
      var remainder = count - sum;

      stats[key]['no response'] = remainder;
    });

    res.send({
      stats: stats
    });

  });
};

exports.post = function post(req, response) {
  var i;
  var data = req.body.surveys;
  var output = [];
  var count = data.length;
  var itemError = null;

  for (i = 0; i < data.length; i++) {
    data[i].users = [req.user._id];
  }

  Survey.create(data, function (error) {
    if (error) {
      itemError = error;
      console.log(error);
      if (error.name === 'ValidationError') {
        response.send(400, error);
      } else {
        response.send(500);
      }
      return;
    }

    var output = Array.prototype.slice.call(arguments, 1).map(function (doc) {
      return doc.toObject();
    });

    var name = req.user.name;
    var link =  'https://' + req.headers.host + '/#surveys/' + output[0].slug;
    console.info('INFO: Survey created. User: ' + name + '; Link: ' + link);
    response.send(201, { surveys: output });
  });
};

exports.put = function put(req, response) {
  var surveyId = req.params.surveyId;
  var survey = req.body.survey;

  // Update the survey, asking MongoDB to return the updated document.
  Survey.findOneAndUpdate({ id: surveyId }, survey, function (error, updated) {
    if (error) {
      console.log(error);
      response.send(500);
      return;
    }

    response.send({ survey: updated.toObject() });
  });
};

// Get the survey ID associated with a slug
// Not authenticated.
exports.getSlug = function getSlug(req, res) {
  Survey.findOne({
    slug: req.params.slug
  })
  .lean()
  .exec(function (error, survey) {
    if (util.handleError(error, res)) { return; }
    if (survey === null) {
      res.send(404);
    } else {
      res.send({ survey: survey.id });
    }
  });
};
<|endoftext|>


<commit_before>module.exports = function initExpressApp () {
	if (this.app) return this;
	this.initDatabase();
	this.initExpressSession();
	this.app = require('../../server/createApp')(this);
	return this;
};
<commit_msg>Fixed #2584: initExpressApp can receive the express app<commit_after>module.exports = function initExpressApp (customApp) {
	if (this.app) return this;
	this.initDatabase();
	this.initExpressSession();
	if (customApp) {
		this.app = customApp;
		require('../../server/createApp')(this);
	} else {
		this.app = require('../../server/createApp')(this);
	}
	return this;
};
<|endoftext|>