<commit_before>// Initialize app
function showDivsConnect(){
    if(localStorage.getItem("logged_in")!=""){
        $(".login").show();
        $(".logout").hide();
    }else{
        $(".login").hide();
        $(".logout").show();
    }
}

function checkConnectionFB() {
    facebookConnectPlugin.getLoginStatus(function(response) {
        alert(localStorage.getItem("logged_in"));
        alert('Get login status: ' + JSON.stringify(response, null, 4));
        if (response.status == 'connected') {
            alert('You are connected to Fb');
            var gar = facebookConnectPlugin.getAuthResponse();
            //localStorage.setItem("logged_in",true);
            showDivsConnect();
        } else {
            alert('not connected to FB');
            localStorage.setItem("logged_in",false);
        }
    });
}

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 (userData) {
    //localStorage.setItem("logged_in",true);
    alert("Datos "+JSON.stringify(userData));
    showDivsConnect();
/*    $.ajax({
      method: "POST",
      url: "http://wisi.com.co/api/social/sigin",
      data: { name: "John", location: "Boston" }
    })
    .done(function( msg ) {
        alert( "Data Saved: " + msg );
        //window.open('http://wisi.com.co/public/#/ad', '_system');
    }); */

}

$$("body").on("click", ".button-facebook", function() {
    facebookConnectPlugin.login(["public_profile","email"],
        fbLoginSuccess,
        function (error) { myApp.alert("Problemas conectando con Facebook!", ""); }
    );
});

var mainView = myApp.addView(".view-main", {
    dynamicNavbar: !0
});
$$(document).on("pageInit", function(e) {
    checkConnectionFB();
    var page = e.detail.page;
    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");
            }
        });
    }), $(".zoom").swipebox(), $(".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", ".js-form-submit", function() {
        var form = $(this).parents("form"), valid = form.valid();
        if ("contact" === page.name && valid) {
            var data = form.serializeObject();
            myApp.showPreloader(), $.post("/email.php", data).done(function(data) {
                myApp.hidePreloader();
                var response = JSON.parse(data);
                response.error ? myApp.alert(response.msg, "") : (myApp.alert(response.msg, ""),
                    form.find("input[type=text], input[type=email], textarea").val(""));
            });
        }
    });
    // Conversation flag
    var conversationStarted = !1, myMessages = myApp.messages(".messages", {
        autoLayout: !0
    }), myMessagebar = myApp.messagebar(".messagebar");
    // Handle message
    $$(".messagebar .link").on("click", function() {
        // 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 = "Kate"), // 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();
    localStorage.setItem("logged_in",false);
    alert(localStorage.getItem("logged_in"));
    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>get data<commit_after>// Initialize app
function showDivsConnect(){
    if(localStorage.getItem("logged_in")!=""){
        $(".login").show();
        $(".logout").hide();
    }else{
        $(".login").hide();
        $(".logout").show();
    }
}

function checkConnectionFB() {
    facebookConnectPlugin.getLoginStatus(function(response) {
        alert(localStorage.getItem("logged_in"));
        alert('Get login status: ' + JSON.stringify(response, null, 4));
        if (response.status == 'connected') {
            alert('You are connected to Fb');
            var gar = facebookConnectPlugin.getAuthResponse();
            //localStorage.setItem("logged_in",true);
            showDivsConnect();
        } else {
            alert('not connected to FB');
            localStorage.setItem("logged_in",false);
        }
    });
}

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 (userData) {
    //localStorage.setItem("logged_in",true);
    alert("Datos "+JSON.stringify(userData));
    facebookConnectPlugin.api("<user-id>/?fields=id,email", ["user_birthday"],
    function (result) {
        alert("Result: " + JSON.stringify(result));
        //showDivsConnect();
    },
    function (error) {
        alert("Failed: " + error);
    });

/*    $.ajax({
      method: "POST",
      url: "http://wisi.com.co/api/social/sigin",
      data: { name: "John", location: "Boston" }
    })
    .done(function( msg ) {
        alert( "Data Saved: " + msg );
        //window.open('http://wisi.com.co/public/#/ad', '_system');
    }); */

}

$$("body").on("click", ".button-facebook", function() {
    facebookConnectPlugin.login(["public_profile","email"],
        fbLoginSuccess,
        function (error) { myApp.alert("Problemas conectando con Facebook!", ""); }
    );
});

var mainView = myApp.addView(".view-main", {
    dynamicNavbar: !0
});
$$(document).on("pageInit", function(e) {
    checkConnectionFB();
    var page = e.detail.page;
    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");
            }
        });
    }), $(".zoom").swipebox(), $(".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", ".js-form-submit", function() {
        var form = $(this).parents("form"), valid = form.valid();
        if ("contact" === page.name && valid) {
            var data = form.serializeObject();
            myApp.showPreloader(), $.post("/email.php", data).done(function(data) {
                myApp.hidePreloader();
                var response = JSON.parse(data);
                response.error ? myApp.alert(response.msg, "") : (myApp.alert(response.msg, ""),
                    form.find("input[type=text], input[type=email], textarea").val(""));
            });
        }
    });
    // Conversation flag
    var conversationStarted = !1, myMessages = myApp.messages(".messages", {
        autoLayout: !0
    }), myMessagebar = myApp.messagebar(".messagebar");
    // Handle message
    $$(".messagebar .link").on("click", function() {
        // 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 = "Kate"), // 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();
    localStorage.setItem("logged_in",false);
    alert(localStorage.getItem("logged_in"));
    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>"use strict";

const debug = require("debug")("controller");
const moment = require("moment");

const EventEmitter = require("events");

class Controller extends EventEmitter {
  constructor(param) {
    super();
    const {
      parallel,
      limit,
      errorlimit,
      errhandler
    } = param;
    this.sleeper = 0;
    this.open = new Map();
    this.running = 0;
    this.limit = limit || 999999999;
    this.parallel = parallel || 20;
    this.collector = [];
    this.errcollector = [];
    this.errorlimit = errorlimit || 1;
    this.errhandler = errhandler || ((err) => err);
  }

  startOne(fun, c) { //start function with object and supply event emit after end
    const temp = this.running++;

    if (temp >= this.limit) {
      this.done = true;
    }

    this.open.set(temp, c); //store running object
    return fun(c)
      .then((res) => this.emit("arbeiten", null, res, temp)) // emit result
      .catch((err) => this.emit("arbeiten", err, null, temp)); // emit error

  }

  *
  startAll(webber, fun) { //start  function with an iterator n times
    this.sleepval = null;
    for (const c of webber) {
      yield this.startOne(fun, c);

    }
  }

  *
  waiter(starttim) { //block with a sleep function, if starttime is not yet reached
    const timeouter = (p) => new Promise((resolve) => setTimeout(resolve, p));

    if ((this.sleepval = (starttim - moment.now("X"))) > 0) {
      this.sleeper++;
      yield timeouter(this.sleepval)
        .then(() => this.emit("arbeiten")); // after sleeping emit event
    }

  }

  /* run controlled by a generator function, which supplies the promises*/

  waiterEnd() {

    return new Promise((resolve, reject) => this.once("arbeiten", (err, result, pos) => err ? reject({
          err,
          pos
        }) :
        resolve({
          result,
          pos
        })))
      .catch((err) => {
        debug("caughterr %d", this.errcollector.length, err);
        //store error

        if (this.errcollector.push(err.err) >= this.errorlimit) {
          //stop working, too many errors, but wait until finished
          this.done = true;
        }
        return this.errhandler(err); //repeat

      })
      .then((obj) => {

        if ("pos" in obj && obj.pos != undefined) {
          //     debug("caught",  obj);
          if ("result" in obj) {
            this.collector[obj.pos] = obj.result; //store endresult in order of start like Promise.all
          }

          this.open.delete(obj.pos); //remove from map of running
        } else { // no work, only sleep function
          this.sleeper--;
        }

        //check for endcondition of the run

        if (this.sleeper === 0 && this.open.size === 0 && this.done) {
          this.removeAllListeners("newrun");
          if (this.errcollector.length >= this.errorlimit) { //throw with error
            debug("finished with error %d", this.errcollector.length);
            throw {
              errors: this.errcollector,
              position: this.running
            };
          } else { // return the array of results
            debug("finished with gen", this.collector.length);
            return Promise.resolve(this.collector);
          }

        } else if (this.done) {
          debug("warten auf ende");
          return this.waiterEnd();

        } else { // repeat if end conditition is not reached
          /*          if (iter === this.running) {
                    debug("no new started", iter);
                  }
                  */
          if (this.emit("newrun")) {
            return this.waiterEnd(); //wait for new results
          } else {
            debug("error");
          }

        }
      });
  }

  run(startgen) {

    while (!this.done && this.sleeper === 0 && this.open.size < this.parallel) {
      const done = startgen.next();
      debug("starting %d %j %d %d", this.open.size, done, this.done, this.running);
      if (!this.done) {
        this.done = done.done;
      }

    }
  }

  runner(startgen) {
    // wait for finished promise,
    // catch the promise after run and do end handling of the promise

    // fetch promises from generator with limited parallelism

    this.done = false;
    this.on("newrun", this.run.bind(this, startgen));
    this.emit("newrun"); //start the run

    return this.waiterEnd();

  }

  tester(x) { // supply test function
    return new Promise((resolve, reject) => setTimeout(() => {
      if (Math.random() < 0.00) {
        return reject({
          message: "kaputti" + this.running
        });
      } else {
        return resolve(x);
      }
    }, Math.random() * 5 + 1));
  }

  statistik() { //current statistics of  run
    return {
      limit: this.limit,
      parallel: this.parallel,
      errorlimit: this.errorlimit,
      notReady: this.running - this.collector.length, //number still in work
      openrun: [...this.open.keys()], // ids which are still running (oldest first)
      finished: this.collector.length, //number of finished
      errors: this.errcollector.length, //number of errors
      lastStarted: this.running, //last id which was started
      sleeps: this.sleeper, //number of sleep functions which are blocking
      done: this.done
        //cpu: this.startUsage=process.cpuUsage(this.startUsage)
    };

  }
}

module.exports = function factory(options) {

  return new Controller(options);
};
<commit_msg>Update controller.js<commit_after>"use strict";

const debug = require("debug")("controller");
const moment = require("moment");

const EventEmitter = require("events");

class Controller extends EventEmitter {
  constructor(param) {
    super();
    const {
      parallel,
      limit,
      errorlimit,
      errhandler,
      collect
    } = param;
    this.sleeper = 0;
    this.open = new Map();
    this.running = 0;
    this.limit = limit || 999999999;
    this.parallel = parallel || 20;
    this.collect = collect;
    if ( this.collect === undefined ){
      this.collect = true;
    }
    this.collector = [];
    this.errcollector = [];
    this.errorlimit = errorlimit || 1;
    this.errhandler = errhandler || ((err) => err);
  }

  startOne(fun, c) { //start function with object and supply event emit after end
    const temp = this.running++;

    if (temp >= this.limit) {
      this.done = true;
    }

    this.open.set(temp, c); //store running object
    return fun(c)
    .catch((err) => this.emit("arbeiten", err, null, temp))
      .then((res) => this.emit("arbeiten", null, res, temp)) // emit result
      ; // emit error

  }

  *
  startAll(webber, fun) { //start  function with an iterator n times
    this.sleepval = null;
    for (const c of webber) {
      yield this.startOne(fun, c);

    }
  }

  *
  waiter(starttim) { //block with a sleep function, if starttime is not yet reached
    const timeouter = (p) => new Promise((resolve) => setTimeout(resolve, p));

    if ((this.sleepval = (starttim - moment.now("X"))) > 0) {
      this.sleeper++;
      yield timeouter(this.sleepval)
        .then(() => this.emit("arbeiten")); // after sleeping emit event
    }

  }

  /* run controlled by a generator function, which supplies the promises*/

  waiterEnd(err,obj,pos) {

    //debug("hier da", obj,err,pos);
  if (err){
        debug("caughterr %d", this.errcollector.length, err);
        //store error

        if (this.errcollector.push(err.err) >= this.errorlimit) {
          //stop working, too many errors, but wait until finished
          this.done = true;
        }
  //      return this.errhandler(err); //repeat
      }
        if (pos !== undefined ) {
          //     debug("caught",  obj);
          if ( obj  && this.collect) {
            this.collector[pos] = obj; //store endresult in order of start like Promise.all
          }

          this.open.delete(pos); //remove from map of running
        } else { // no work, only sleep function
          this.sleeper--;
        }

        //check for endcondition of the run

        if (this.sleeper === 0 && this.open.size === 0 && this.done) {
          this.removeAllListeners("newrun");
          if (this.errcollector.length >= this.errorlimit) { //throw with error
            debug("finished with error %d", this.errcollector.length);
            this.emit("ende", this.errcollector );
            /*
            throw {
              errors: this.errcollector,
              position: this.running
            };
            */
          } else { // return the array of results
            debug("finished with gen", this.collector.length);
            //return Promise.resolve(this.collector);
            this.emit("ende", null,this.collector );
          }

        } else if (this.done) {
          debug("warten auf ende");
        //  return this.waiterEnd();

        } else { // repeat if end conditition is not reached
          /*          if (iter === this.running) {
                    debug("no new started", iter);
                  }
                  */
          if (this.emit("newrun")) {
          //  return this.waiterEnd(); //wait for new results
          } else {
            debug("error");
          }

        }
      }

  run(startgen) {
    while (!this.done && this.sleeper === 0 && this.open.size < this.parallel) {
      const done = startgen.next();
      debug("starting %d %j %d %d", this.open.size, done, this.done, this.running);
      if (!this.done) {
        this.done = done.done;
      }

    }
  }

  runner(startgen) {
    // wait for finished promise,
    // catch the promise after run and do end handling of the promise

    // fetch promises from generator with limited parallelism

    this.done = false;
    this.on("newrun", this.run.bind(this, startgen));
    this.on("arbeiten",this.waiterEnd.bind(this) );
    this.emit("newrun"); //start the run

    return new Promise((resolve, reject) => this.once("ende", (err, result) => err ? reject({
      errors: err,
      position: this.running
    }) :
            resolve(result)));

  }

  tester(x) { // supply test function
    return new Promise((resolve, reject) => setTimeout(() => {
      if (Math.random() < 0.00) {
        return reject({
          message: "kaputti" + this.running
        });
      } else {
        return resolve(x);
      }
    }, Math.random() * 5 + 1));
  }

  statistik() { //current statistics of  run
    return {
      limit: this.limit,
      parallel: this.parallel,
      errorlimit: this.errorlimit,
      notReady: this.running - this.collector.length, //number still in work
      openrun: [...this.open.keys()], // ids which are still running (oldest first)
      finished: this.collector.length, //number of finished
      errors: this.errcollector.length, //number of errors
      lastStarted: this.running, //last id which was started
      sleeps: this.sleeper, //number of sleep functions which are blocking
      done: this.done
        //cpu: this.startUsage=process.cpuUsage(this.startUsage)
    };

  }
}

module.exports = function factory(options) {

  return new Controller(options);
};
<|endoftext|>


<commit_before>var dashboard_ctrl = function($scope, $timeout, address_service) {

    function PieChart(obj) {
        this.title = obj.title || ''
        this.name = obj.name || ''
        this.detail1 = obj.detail1 || ''
        this.detail2 = obj.detail2 || ''
        this.current_value = obj.current_value || 0
        this.address_map = obj.address_map || {}
        this.reference = obj.reference || undefined
        this.datafn = obj.datafn || function() {
            return null
        }
        this.data = obj.data || []
    }

    $scope.pies = [
        new PieChart({
            title: 'Messages',
            name: 'pieMessages',
            detail1: 'Total messages processed',
            detail2: 'for all addresses',
            datafn: function(item) {
                return item.messages_out
            },
        }),
        new PieChart({
            title: 'Senders',
            name: 'pieSenders',
            detail1: 'Number of senders',
            datafn: function(item) {
                return item.senders
            },
        }),
        new PieChart({
            title: 'Receivers',
            name: 'pieReceivers',
            detail1: 'Number of receivers',
            datafn: function(item) {
                return item.receivers
            },
        }),
    ];

    // called by address_service each time an address' data changes
    var on_update = function (reason) {
        $timeout(function () {
          if (!reason) reason = '';
          if (reason.split(':')[0] !== 'address') {
              return;
          }
          $scope.pies.forEach(function(pie, i) {
              pie.update()
          })
        })
    };

    // ensure all pie charts use same color for each address
    var pieColors = [$.pfPaletteColors.red, $.pfPaletteColors.blue, $.pfPaletteColors.orange,
        $.pfPaletteColors.green, $.pfPaletteColors.red200
    ]
    var address_color_map = {}
    var color4Address = function(a) {
        if (address_color_map[a])
            return address_color_map[a]
        var index = Object.keys(address_color_map).length
        // always use grey for 'other' pie slice
        if (index >= pieColors.length)
            address_color_map[a] = $.pfPaletteColors.black400
        else
            address_color_map[a] = pieColors[index]
        return address_color_map[a]
    }

    PieChart.prototype.update = function (piedata) {
        var piedata = 0
        this.address_map = {}
        items.forEach(function(item) {
            var data = this.datafn(item)
            // accumulate data for line chart
            piedata += data
            // catagorize data for pie chart
            if (data)
                this.address_map[item.address] = this.address_map[item.address] ? this.address_map[item.address] + data : data;
        }, this)
        this.current_value = piedata;
        // store up to 10 values for line chart
        this.data.push(this.current_value)
        while (this.data.length > 10) {
            this.data.shift()
        }
        this.draw_pie()
        this.draw_lines()
    }

    PieChart.prototype.draw_lines = function() {
        var data = {
            columns: [
                [this.title]
            ],
            type: 'area'
        };
        Array.prototype.push.apply(data.columns[0], this.data)

        if (!this.spark_reference) {
            var sparklineChartConfig = $().c3ChartDefaults().getDefaultSparklineConfig();
            sparklineChartConfig.bindto = '#chart-pf-sparkline-' + this.name;
            sparklineChartConfig.data = data
            this.spark_reference = c3.generate(sparklineChartConfig);
        } else {
            this.spark_reference.load(data)
        }
    }

    PieChart.prototype.draw_pie = function() {
        var pieData = {
            type: 'pie',
            colors: {},
            columns: [],
        };
        var addressvals = Object.keys(this.address_map).map(function(address) {
            return {
                address: address,
                value: this.address_map[address]
            }
        }, this)
        addressvals.sort(function(a, b) {
            return b.value - a.value
        })
        // if there are 6 or more addresses, collapse those not in top 4 into 'other'
        if (addressvals.length >= 6) {
            for (var i = 4, other = 0; i < addressvals.length; ++i) {
                other += addressvals[i].value
            }
            while (addressvals.length > 4)
                addressvals.pop()
            addressvals.push({
                address: 'Other',
                value: other
            })
        }
        addressvals.forEach(function(av) {
            pieData.colors[av.address] = color4Address(av.address)
            pieData.columns.push([av.address, av.value])
        })

        // only call c3.generate() once. after that call .load()
        // otherwise c3 will leak memory. https://github.com/c3js/c3/issues/926
        if (!this.reference) {
            var c3ChartDefaults = $().c3ChartDefaults();
            var pieChartSmallConfig = c3ChartDefaults.getDefaultPieConfig();
            pieChartSmallConfig.bindto = '#pie-chart-' + this.name;
            pieChartSmallConfig.data = pieData;
            pieChartSmallConfig.legend = {
                show: true,
                position: 'right'
            };
            pieChartSmallConfig.size = {
                width: 260,
                height: 115
            };
            this.reference = c3.generate(pieChartSmallConfig);
        } else {
            this.reference.load(pieData)
        }
    }
    $scope.$on('$destroy', function() {
        $scope.pies.forEach(function(pie) {
            if (pie.reference) pie.reference.destroy()
            if (pie.spark_reference) pie.spark_reference.destroy()
        })
    })

    var items = address_service.addresses;
    address_service.on_update(on_update)

    // draw charts without waiting for on_update event from address_service
    on_update("address")
}

angular.module('patternfly.toolbars').controller('DashCtrl', ['$scope', '$timeout', 'address_service', dashboard_ctrl])<commit_msg>Display message when no active senders/receivers are found<commit_after>var dashboard_ctrl = function($scope, $timeout, address_service) {

    function PieChart(obj) {
        this.title = obj.title || ''
        this.name = obj.name || ''
        this.detail1 = obj.detail1 || ''
        this.detail2 = obj.detail2 || ''
        this.current_value = obj.current_value || 0
        this.address_map = obj.address_map || {}
        this.reference = obj.reference || undefined
        this.datafn = obj.datafn || function() {
            return null
        }
        this.data = obj.data || []
    }

    $scope.pies = [
        new PieChart({
            title: 'Messages',
            name: 'pieMessages',
            detail1: 'Total messages processed',
            detail2: 'for all active clients',
            datafn: function(item) {
                return item.messages_out
            },
        }),
        new PieChart({
            title: 'Senders',
            name: 'pieSenders',
            detail1: 'Number of senders',
            datafn: function(item) {
                return item.senders
            },
        }),
        new PieChart({
            title: 'Receivers',
            name: 'pieReceivers',
            detail1: 'Number of receivers',
            datafn: function(item) {
                return item.receivers
            },
        }),
    ];

    // called by address_service each time an address' data changes
    var on_update = function (reason) {
        $timeout(function () {
          if (!reason) reason = '';
          if (reason.split(':')[0] !== 'address') {
              return;
          }
          $scope.pies.forEach(function(pie, i) {
              pie.update()
          })
        })
    };

    // ensure all pie charts use same color for each address
    var pieColors = [$.pfPaletteColors.red, $.pfPaletteColors.blue, $.pfPaletteColors.orange,
        $.pfPaletteColors.green, $.pfPaletteColors.red200
    ]
    var address_color_map = {}
    var color4Address = function(a) {
        if (address_color_map[a])
            return address_color_map[a]
        var index = Object.keys(address_color_map).length
        // always use grey for 'other' pie slice
        if (index >= pieColors.length)
            address_color_map[a] = $.pfPaletteColors.black400
        else
            address_color_map[a] = pieColors[index]
        return address_color_map[a]
    }

    PieChart.prototype.update = function (piedata) {
        var piedata = 0
        this.address_map = {}
        items.forEach(function(item) {
            var data = this.datafn(item)
            // accumulate data for line chart
            piedata += data
            // catagorize data for pie chart
            if (data)
                this.address_map[item.address] = this.address_map[item.address] ? this.address_map[item.address] + data : data;
        }, this)
        this.current_value = piedata;
        // store up to 10 values for line chart
        this.data.push(this.current_value)
        while (this.data.length > 10) {
            this.data.shift()
        }
        this.draw_pie()
        this.draw_lines()
    }

    PieChart.prototype.draw_lines = function() {
        var data = {
            columns: [
                [this.title]
            ],
            type: 'area'
        };
        Array.prototype.push.apply(data.columns[0], this.data)

        if (!this.spark_reference) {
            var sparklineChartConfig = $().c3ChartDefaults().getDefaultSparklineConfig();
            sparklineChartConfig.bindto = '#chart-pf-sparkline-' + this.name;
            sparklineChartConfig.data = data
            this.spark_reference = c3.generate(sparklineChartConfig);
        } else {
            this.spark_reference.load(data)
        }
    }

    PieChart.prototype.draw_pie = function() {
        var pieData = {
            type: 'pie',
            colors: {},
            columns: [],
            empty: { label: { text: "No Data Available" }},
        };
        var addressvals = Object.keys(this.address_map).map(function(address) {
            return {
                address: address,
                value: this.address_map[address]
            }
        }, this)
        addressvals.sort(function(a, b) {
            return b.value - a.value
        })
        // if there are 6 or more addresses, collapse those not in top 4 into 'other'
        if (addressvals.length >= 6) {
            for (var i = 4, other = 0; i < addressvals.length; ++i) {
                other += addressvals[i].value
            }
            while (addressvals.length > 4)
                addressvals.pop()
            addressvals.push({
                address: 'Other',
                value: other
            })
        }
        addressvals.forEach(function(av) {
            pieData.colors[av.address] = color4Address(av.address)
            pieData.columns.push([av.address, av.value])
        })

        // only call c3.generate() once. after that call .load()
        // otherwise c3 will leak memory. https://github.com/c3js/c3/issues/926
        if (!this.reference) {
            var c3ChartDefaults = $().c3ChartDefaults();
            var pieChartSmallConfig = c3ChartDefaults.getDefaultPieConfig();
            pieChartSmallConfig.bindto = '#pie-chart-' + this.name;
            pieChartSmallConfig.data = pieData;
            pieChartSmallConfig.legend = {
                show: true,
                position: 'right'
            };
            pieChartSmallConfig.size = {
                width: 260,
                height: 115
            };
            this.reference = c3.generate(pieChartSmallConfig);
        } else {
            this.reference.load(pieData)
        }
    }
    $scope.$on('$destroy', function() {
        $scope.pies.forEach(function(pie) {
            if (pie.reference) pie.reference.destroy()
            if (pie.spark_reference) pie.spark_reference.destroy()
        })
    })

    var items = address_service.addresses;
    address_service.on_update(on_update)

    // draw charts without waiting for on_update event from address_service
    on_update("address")
}

angular.module('patternfly.toolbars').controller('DashCtrl', ['$scope', '$timeout', 'address_service', dashboard_ctrl])<|endoftext|>


<commit_before>var path = require("path"),
    fs = require("fs"),
    uuid = require("uuid").v1,
    tmpDir = require("os").tmpdir(),
    _ = require('lodash');

 var options;
function writeHtmlFile(opt, type, id, cb) {
    if (!opt[type])
        return cb();

    var htmlPath = path.resolve(path.join(options.tmpDir, id + type + ".html"));
    opt[type + "File"] = path.resolve(htmlPath);
    fs.writeFile(htmlPath, opt[type], cb);
}

function writeHtml(opt, id, cb) {
    writeHtmlFile(opt, "html", id, function (err) {
        if (err)
            return cb(err);

        writeHtmlFile(opt, "header", id, function (err) {
            if (err)
                return cb(err);

            writeHtmlFile(opt, "footer", id, function (err) {
                if (err)
                    return cb(err);

                cb();
            });
        });
    });
}

function convert(options, cb) {
    var opt = _.cloneDeep(options);
    if (typeof opt == 'string' || opt instanceof String) {
        opt = {
            html: opt
        }
    }

    opt.viewportSize = opt.viewportSize || {};
    opt.paperSize = opt.paperSize || {};
    opt.settings = opt.settings || {};
    opt.waitForJSVarName = opt.waitForJSVarName  || 'PHANTOM_HTML_TO_PDF_READY';

    if (opt.waitForJS && opt.settings.javascriptEnabled === false) {
        throw new Error('can\'t use waitForJS option if settings.javascriptEnabled is not activated');
    }

    var id = uuid();

    writeHtml(opt, id, function (err) {
        if (err) {
            return cb(err);
        }

        opt.url = opt.url || "file:///" + encodeURIComponent(opt.htmlFile);
        opt.output = path.resolve(path.join(options.tmpDir, id + ".pdf"));

        delete opt.html;

        if (options.strategy === "phantom-server")
            return require("./serverStrategy.js")(options, opt, id, cb);
        if (options.strategy === "dedicated-process")
            return require("./dedicatedProcessStrategy.js")(options, opt, id, cb);

        cb(new Error("Unsupported strategy " + options.strategy));
    });
}

function kill() {
    require("./serverStrategy.js").kill();
}

module.exports = function (opt) {
    options = opt || {};
    options.timeout = options.timeout || 180000;
    options.numberOfWorkers = options.numberOfWorkers || 2;
    options.pathToPhantomScript = options.pathToPhantomScript || path.join(__dirname, "scripts", "serverScript.js");
    options.tmpDir = options.tmpDir || tmpDir;
    options.strategy = options.strategy || "phantom-server";

    // always set env var names for phantom-workers (don't let the user override this config)
    options.hostEnvVarName = 'PHANTOM_WORKER_HOST';
    options.portEnvVarName = 'PHANTOM_WORKER_PORT';

    convert.options = options;
    convert.kill = kill;

    return convert;
};

<commit_msg>fix for unit tests<commit_after>var path = require("path"),
    fs = require("fs"),
    uuid = require("uuid").v1,
    tmpDir = require("os").tmpdir(),
    _ = require('lodash');

 var options;
function writeHtmlFile(opt, type, id, cb) {
    if (!opt[type])
        return cb();

    var htmlPath = path.resolve(path.join(options.tmpDir, id + type + ".html"));
    opt[type + "File"] = path.resolve(htmlPath);
    fs.writeFile(htmlPath, opt[type], cb);
}

function writeHtml(opt, id, cb) {
    writeHtmlFile(opt, "html", id, function (err) {
        if (err)
            return cb(err);

        writeHtmlFile(opt, "header", id, function (err) {
            if (err)
                return cb(err);

            writeHtmlFile(opt, "footer", id, function (err) {
                if (err)
                    return cb(err);

                cb();
            });
        });
    });
}

function convert(conversionOptions, cb) {
    var opt = _.cloneDeep(conversionOptions);
    if (typeof opt == 'string' || opt instanceof String) {
        opt = {
            html: opt
        }
    }

    opt.viewportSize = opt.viewportSize || {};
    opt.paperSize = opt.paperSize || {};
    opt.settings = opt.settings || {};
    opt.waitForJSVarName = opt.waitForJSVarName  || 'PHANTOM_HTML_TO_PDF_READY';

    if (opt.waitForJS && opt.settings.javascriptEnabled === false) {
        throw new Error('can\'t use waitForJS option if settings.javascriptEnabled is not activated');
    }

    var id = uuid();

    writeHtml(opt, id, function (err) {
        if (err) {
            return cb(err);
        }

        opt.url = opt.url || "file:///" + encodeURIComponent(opt.htmlFile);
        opt.output = path.resolve(path.join(options.tmpDir, id + ".pdf"));

        delete opt.html;

        if (options.strategy === "phantom-server")
            return require("./serverStrategy.js")(options, opt, id, cb);
        if (options.strategy === "dedicated-process")
            return require("./dedicatedProcessStrategy.js")(options, opt, id, cb);

        cb(new Error("Unsupported strategy " + options.strategy));
    });
}

function kill() {
    require("./serverStrategy.js").kill();
}

module.exports = function (opt) {
    options = opt || {};
    options.timeout = options.timeout || 180000;
    options.numberOfWorkers = options.numberOfWorkers || 2;
    options.pathToPhantomScript = options.pathToPhantomScript || path.join(__dirname, "scripts", "serverScript.js");
    options.tmpDir = options.tmpDir || tmpDir;
    options.strategy = options.strategy || "phantom-server";

    // always set env var names for phantom-workers (don't let the user override this config)
    options.hostEnvVarName = 'PHANTOM_WORKER_HOST';
    options.portEnvVarName = 'PHANTOM_WORKER_PORT';

    convert.options = options;
    convert.kill = kill;

    return convert;
};

<|endoftext|>


<commit_before>var _ = require('lodash');

module.exports = function (config, callback) {

  config.hooks = {
    run: function (name, args) {
      console.log('trying to run hook: ' + name);
      // for all plugins
      _.each(config.plugins, function (plugin) {
        // find if has hook `name`
        if (plugin.hooks[name]) {
          // call the hook
          return plugin.hooks[name].apply(config, args);
        } else {
          return false;
        }
      });
    }
  };

  return callback(null, config);
};
<commit_msg>[hooks] make sure we call all hooks for all registered plugins<commit_after>var _ = require('lodash');

module.exports = function (config, callback) {

  config.hooks = {
    run: function (name, args) {
      console.log('trying to run hook: ' + name);
      // for all plugins
      var ran = false;
      _.each(config.plugins, function (plugin) {
        // find if has hook `name`
        if (plugin.hooks[name]) {
          // call the hook
          plugin.hooks[name].apply(config, args);
          ran = true;
        }
      });
      return ran;
    }
  };

  return callback(null, config);
};
<|endoftext|>


<commit_before>/* globals Clipboard */
(function (angular, undefined) {
    'use strict';
    // module: hq.list_exports

    /* This module is for helping fetching and showing a list of exports,
     * and activating bulk export download, as well as single export download.
      * */

    var list_exports = angular.module('hq.list_exports', [
        'ngResource',
        'ngRoute',
        'ng.django.rmi',
        'ngMessages',
    ]);

    list_exports.config(['$httpProvider', function ($httpProvider) {
        $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
    }]);

    var exportsControllers = {};
    exportsControllers.ListExportsController = function (
        $scope, djangoRMI, bulk_download_url, legacy_bulk_download_url, $rootScope, modelType, $timeout
    ) {
        /**
         * This controller fetches a list of saved exports from
         * subclasses of BaseExportListView.
         *
         * It also generates a list of exports selected for bulk exports.
         */
        var self = {};
        $scope._ = _;  // allow use of underscore.js within the template
        $scope.exports = hqImport('hqwebapp/js/initial_page_data').get('exports');
        $scope.bulk_download_url = bulk_download_url;
        $scope.legacy_bulk_download_url = legacy_bulk_download_url;

        $scope.myExports = $scope.exports.filter(function (val) { return !!val.my_export; });
        $scope.notMyExports = $scope.exports.filter(function (val) { return !val.my_export; });
        _.each($scope.exports, function (exp) {
            if (exp.emailedExport && exp.emailedExport.taskStatus.inProgress) {
                $rootScope.pollProgressBar(exp);
            }
        });

        // For Bulk Export
        $scope.showBulkExportDownload = false;
        $scope.bulkExportList = '[]';

        $scope.updateBulkStatus = function () {
            var selectedExports = _.filter($scope.exports, function (exp) {
                return !!exp.addedToBulk;
            });
            $scope.showBulkExportDownload = !_.isEmpty(selectedExports);
            $scope.bulkExportList = JSON.stringify(selectedExports);
            var input = $('input[name="export_list"]');
            input.val(JSON.stringify(selectedExports));

            var useLegacyBulkExportUrl = _.every(selectedExports, function (e) {
                return e.isLegacy;
            });
            var currentUrl = useLegacyBulkExportUrl ? $scope.legacy_bulk_download_url : $scope.bulk_download_url;
            input.closest("form").attr("action", currentUrl);
        };
        $scope.downloadRequested = function ($event) {
            var $btn = $($event.target);
            $btn.addClass('disabled');
            $btn.text(gettext('Download Requested'));
        };
        $scope.copyLinkRequested = function ($event, export_) {
            export_.showLink = true;
            var clipboard = new Clipboard($event.target, {
                target: function (trigger) {
                    return trigger.nextElementSibling;
                },
            });
            clipboard.onClick($event);
            clipboard.destroy();
        };
        $scope.selectAll = function () {
            _.each($scope.exports, function (exp) {
                exp.addedToBulk = true;
            });
            $scope.updateBulkStatus();
        };
        $scope.selectNone = function () {
            _.each($scope.exports, function (exp) {
                exp.addedToBulk = false;
            });
            $scope.updateBulkStatus();
        };
        $scope.sendExportAnalytics = function () {
            hqImport('analytix/js/kissmetrix').track.event("Clicked Export button");
        };

        $rootScope.pollProgressBar = function (exp) {
            exp.emailedExport.updatingData = false;
            exp.emailedExport.taskStatus = {
                'percentComplete': 0,
                'inProgress': true,
                'success': false,
            };
            var tick = function () {
                djangoRMI.get_saved_export_progress({
                    'export_instance_id': exp.id,
                }).success(function (data) {
                    exp.emailedExport.taskStatus = data.taskStatus;
                    if (!data.taskStatus.success) {
                        // The first few ticks don't yet register the task
                        exp.emailedExport.taskStatus.inProgress = true;
                        $timeout(tick, 1500);
                    } else {
                        exp.emailedExport.taskStatus.justFinished = true;
                    }
                });
            };
            tick();
        };

        $scope.updateEmailedExportData = function (component, exp) {
            $('#modalRefreshExportConfirm-' + exp.id + '-' + (component.groupId ? component.groupId : '')).modal('hide');
            component.updatingData = true;
            djangoRMI.update_emailed_export_data({
                'component': component,
                'export': exp,
            })
                .success(function (data) {
                    if (data.success) {
                        var exportType = hqImport('export/js/utils').capitalize(exp.exportType);
                        hqImport('analytix/js/google').track.event(exportType + " Exports", "Update Saved Export", "Saved");
                        $rootScope.pollProgressBar(exp);
                    }
                });
        };
        $scope.updateDisabledState = function (component, exp) {
            $('#modalEnableDisableAutoRefresh-' + exp.id + '-' + (component.groupId ? component.groupId : '')).modal('hide');
            component.savingAutoRebuildChange = true;
            djangoRMI.toggle_saved_export_enabled_state({
                'component': component,
                'export': exp,
            })
                .success(function (data) {
                    if (data.success) {
                        var exportType = hqImport('export/js/utils').capitalize(exp.exportType);
                        var event = (exp.isAutoRebuildEnabled ? "Disable" : "Enable") + " Saved Export";
                        hqImport('analytix/js/google').track.event(exportType + " Exports", event, "Saved");
                        exp.isAutoRebuildEnabled = data.isAutoRebuildEnabled;
                        component.savingAutoRebuildChange = false;
                    }
                });
        };
        $scope.setFilterModalExport = function (export_) {
            // The filterModalExport is used as context for the FeedFilterFormController
            $rootScope.filterModalExport = export_;
        };
        $scope.isLocationSafeForUser = function (export_) {
            return (!export_.emailedExport) || export_.emailedExport.isLocationSafeForUser;
        };

        trackExportPageEnter();

        /**
         * Send a Kissmetrics event, depending on model type
         */
        function trackExportPageEnter() {
            switch (modelType) {
                case 'form':
                    hqImport('analytix/js/kissmetrix').track.event('Visited Export Forms Page');
                    break;
                case 'case':
                    hqImport('analytix/js/kissmetrix').track.event('Visited Export Cases Page');
                    break;
                default:
                    break;
            }
        }
    };
    exportsControllers.FeedFilterFormController = function (
        $scope, $rootScope, djangoRMI, filterFormElements, filterFormModalElement
    ) {
        var self = {};
        $scope._ = _;   // make underscore.js available
        $scope.formData = {};
        $scope.modelType = null;  // "form" or "case" - corresponding to the type of export selected.
        // A list a location names. The export will be restricted to these locations.
        $scope.locationRestrictions = [];
        $scope.isSubmittingForm = false;
        $scope.hasFormSubmitError = false;
        $scope.formSubmitErrorMessage = null;
        $scope.dateRegex = '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]';
        self.nonPristineExportFilters = {};
        $scope.formElement = filterFormElements;

        $rootScope.$watch("filterModalExport", function (newSelectedExport) {
            if (!newSelectedExport) {
                return;
            }
            if (!(newSelectedExport.id in self.nonPristineExportFilters)) {
                // Mark the form as pristine if we are editing filters of a different export than before
                self.nonPristineExportFilters[newSelectedExport.id] = true;
                $scope.feedFiltersForm.$setPristine();

            }

            $scope.formData = newSelectedExport.emailedExport.filters;
            $scope.locationRestrictions = newSelectedExport.emailedExport.locationRestrictions;
            $scope.modelType = newSelectedExport.exportType;
            // select2s require programmatic update
            $scope.formElement.emwf_case_filter().select2("data", newSelectedExport.emailedExport.filters.emwf_case_filter);
            $scope.formElement.emwf_form_filter().select2("data", newSelectedExport.emailedExport.filters.emwf_form_filter);
        });

        $scope.$watch("formData.date_range", function (newDateRange) {
            if (!newDateRange) {
                $scope.formData.date_range = "since";
            } else {
                self._clearSubmitError();
            }
        });

        $scope.commitFilters = function () {
            var export_ = $rootScope.filterModalExport;
            $scope.isSubmittingForm = true;

            // Put the data from the select2 into the formData object
            if ($scope.modelType === 'form') {
                $scope.formData.emwf_form_filter = $scope.formElement.emwf_form_filter().select2("data");
                $scope.formData.emwf_case_filter = null;
            }
            if ($scope.modelType === 'case') {
                $scope.formData.emwf_case_filter = $scope.formElement.emwf_case_filter().select2("data");
                $scope.formData.emwf_form_filter = null;
            }

            djangoRMI.commit_filters({
                export: export_,
                form_data: $scope.formData,
            }).success(function (data) {
                $scope.isSubmittingForm = false;
                if (data.success) {
                    self._clearSubmitError();
                    export_.emailedExport.filters = $scope.formData;
                    $rootScope.pollProgressBar(export_);
                    filterFormModalElement().modal('hide');
                } else {
                    self._handleSubmitError(data);
                }
            }).error(function (data) {
                $scope.isSubmittingForm = false;
                self._handleSubmitError(data);
            });
        };

        self._handleSubmitError = function (data) {
            $scope.hasFormSubmitError = true;
            $scope.formSubmitErrorMessage = data.error;
        };
        self._clearSubmitError = function () {
            $scope.hasFormSubmitError = false;
            $scope.formSubmitErrorMessage = null;
        };
    };

    list_exports.controller(exportsControllers);

}(window.angular));
<commit_msg>Move pollProgressBar to be defined before it's called<commit_after>/* globals Clipboard */
(function (angular, undefined) {
    'use strict';
    // module: hq.list_exports

    /* This module is for helping fetching and showing a list of exports,
     * and activating bulk export download, as well as single export download.
      * */

    var list_exports = angular.module('hq.list_exports', [
        'ngResource',
        'ngRoute',
        'ng.django.rmi',
        'ngMessages',
    ]);

    list_exports.config(['$httpProvider', function ($httpProvider) {
        $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
    }]);

    var exportsControllers = {};
    exportsControllers.ListExportsController = function (
        $scope, djangoRMI, bulk_download_url, legacy_bulk_download_url, $rootScope, modelType, $timeout
    ) {
        /**
         * This controller fetches a list of saved exports from
         * subclasses of BaseExportListView.
         *
         * It also generates a list of exports selected for bulk exports.
         */
        $rootScope.pollProgressBar = function (exp) {
            exp.emailedExport.updatingData = false;
            exp.emailedExport.taskStatus = {
                'percentComplete': 0,
                'inProgress': true,
                'success': false,
            };
            var tick = function () {
                djangoRMI.get_saved_export_progress({
                    'export_instance_id': exp.id,
                }).success(function (data) {
                    exp.emailedExport.taskStatus = data.taskStatus;
                    if (!data.taskStatus.success) {
                        // The first few ticks don't yet register the task
                        exp.emailedExport.taskStatus.inProgress = true;
                        $timeout(tick, 1500);
                    } else {
                        exp.emailedExport.taskStatus.justFinished = true;
                    }
                });
            };
            tick();
        };

        var self = {};
        $scope._ = _;  // allow use of underscore.js within the template
        $scope.exports = hqImport('hqwebapp/js/initial_page_data').get('exports');
        $scope.bulk_download_url = bulk_download_url;
        $scope.legacy_bulk_download_url = legacy_bulk_download_url;

        $scope.myExports = $scope.exports.filter(function (val) { return !!val.my_export; });
        $scope.notMyExports = $scope.exports.filter(function (val) { return !val.my_export; });
        _.each($scope.exports, function (exp) {
            if (exp.emailedExport && exp.emailedExport.taskStatus.inProgress) {
                $rootScope.pollProgressBar(exp);
            }
        });

        // For Bulk Export
        $scope.showBulkExportDownload = false;
        $scope.bulkExportList = '[]';

        $scope.updateBulkStatus = function () {
            var selectedExports = _.filter($scope.exports, function (exp) {
                return !!exp.addedToBulk;
            });
            $scope.showBulkExportDownload = !_.isEmpty(selectedExports);
            $scope.bulkExportList = JSON.stringify(selectedExports);
            var input = $('input[name="export_list"]');
            input.val(JSON.stringify(selectedExports));

            var useLegacyBulkExportUrl = _.every(selectedExports, function (e) {
                return e.isLegacy;
            });
            var currentUrl = useLegacyBulkExportUrl ? $scope.legacy_bulk_download_url : $scope.bulk_download_url;
            input.closest("form").attr("action", currentUrl);
        };
        $scope.downloadRequested = function ($event) {
            var $btn = $($event.target);
            $btn.addClass('disabled');
            $btn.text(gettext('Download Requested'));
        };
        $scope.copyLinkRequested = function ($event, export_) {
            export_.showLink = true;
            var clipboard = new Clipboard($event.target, {
                target: function (trigger) {
                    return trigger.nextElementSibling;
                },
            });
            clipboard.onClick($event);
            clipboard.destroy();
        };
        $scope.selectAll = function () {
            _.each($scope.exports, function (exp) {
                exp.addedToBulk = true;
            });
            $scope.updateBulkStatus();
        };
        $scope.selectNone = function () {
            _.each($scope.exports, function (exp) {
                exp.addedToBulk = false;
            });
            $scope.updateBulkStatus();
        };
        $scope.sendExportAnalytics = function () {
            hqImport('analytix/js/kissmetrix').track.event("Clicked Export button");
        };

        $scope.updateEmailedExportData = function (component, exp) {
            $('#modalRefreshExportConfirm-' + exp.id + '-' + (component.groupId ? component.groupId : '')).modal('hide');
            component.updatingData = true;
            djangoRMI.update_emailed_export_data({
                'component': component,
                'export': exp,
            })
                .success(function (data) {
                    if (data.success) {
                        var exportType = hqImport('export/js/utils').capitalize(exp.exportType);
                        hqImport('analytix/js/google').track.event(exportType + " Exports", "Update Saved Export", "Saved");
                        $rootScope.pollProgressBar(exp);
                    }
                });
        };
        $scope.updateDisabledState = function (component, exp) {
            $('#modalEnableDisableAutoRefresh-' + exp.id + '-' + (component.groupId ? component.groupId : '')).modal('hide');
            component.savingAutoRebuildChange = true;
            djangoRMI.toggle_saved_export_enabled_state({
                'component': component,
                'export': exp,
            })
                .success(function (data) {
                    if (data.success) {
                        var exportType = hqImport('export/js/utils').capitalize(exp.exportType);
                        var event = (exp.isAutoRebuildEnabled ? "Disable" : "Enable") + " Saved Export";
                        hqImport('analytix/js/google').track.event(exportType + " Exports", event, "Saved");
                        exp.isAutoRebuildEnabled = data.isAutoRebuildEnabled;
                        component.savingAutoRebuildChange = false;
                    }
                });
        };
        $scope.setFilterModalExport = function (export_) {
            // The filterModalExport is used as context for the FeedFilterFormController
            $rootScope.filterModalExport = export_;
        };
        $scope.isLocationSafeForUser = function (export_) {
            return (!export_.emailedExport) || export_.emailedExport.isLocationSafeForUser;
        };

        trackExportPageEnter();

        /**
         * Send a Kissmetrics event, depending on model type
         */
        function trackExportPageEnter() {
            switch (modelType) {
                case 'form':
                    hqImport('analytix/js/kissmetrix').track.event('Visited Export Forms Page');
                    break;
                case 'case':
                    hqImport('analytix/js/kissmetrix').track.event('Visited Export Cases Page');
                    break;
                default:
                    break;
            }
        }
    };
    exportsControllers.FeedFilterFormController = function (
        $scope, $rootScope, djangoRMI, filterFormElements, filterFormModalElement
    ) {
        var self = {};
        $scope._ = _;   // make underscore.js available
        $scope.formData = {};
        $scope.modelType = null;  // "form" or "case" - corresponding to the type of export selected.
        // A list a location names. The export will be restricted to these locations.
        $scope.locationRestrictions = [];
        $scope.isSubmittingForm = false;
        $scope.hasFormSubmitError = false;
        $scope.formSubmitErrorMessage = null;
        $scope.dateRegex = '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]';
        self.nonPristineExportFilters = {};
        $scope.formElement = filterFormElements;

        $rootScope.$watch("filterModalExport", function (newSelectedExport) {
            if (!newSelectedExport) {
                return;
            }
            if (!(newSelectedExport.id in self.nonPristineExportFilters)) {
                // Mark the form as pristine if we are editing filters of a different export than before
                self.nonPristineExportFilters[newSelectedExport.id] = true;
                $scope.feedFiltersForm.$setPristine();

            }

            $scope.formData = newSelectedExport.emailedExport.filters;
            $scope.locationRestrictions = newSelectedExport.emailedExport.locationRestrictions;
            $scope.modelType = newSelectedExport.exportType;
            // select2s require programmatic update
            $scope.formElement.emwf_case_filter().select2("data", newSelectedExport.emailedExport.filters.emwf_case_filter);
            $scope.formElement.emwf_form_filter().select2("data", newSelectedExport.emailedExport.filters.emwf_form_filter);
        });

        $scope.$watch("formData.date_range", function (newDateRange) {
            if (!newDateRange) {
                $scope.formData.date_range = "since";
            } else {
                self._clearSubmitError();
            }
        });

        $scope.commitFilters = function () {
            var export_ = $rootScope.filterModalExport;
            $scope.isSubmittingForm = true;

            // Put the data from the select2 into the formData object
            if ($scope.modelType === 'form') {
                $scope.formData.emwf_form_filter = $scope.formElement.emwf_form_filter().select2("data");
                $scope.formData.emwf_case_filter = null;
            }
            if ($scope.modelType === 'case') {
                $scope.formData.emwf_case_filter = $scope.formElement.emwf_case_filter().select2("data");
                $scope.formData.emwf_form_filter = null;
            }

            djangoRMI.commit_filters({
                export: export_,
                form_data: $scope.formData,
            }).success(function (data) {
                $scope.isSubmittingForm = false;
                if (data.success) {
                    self._clearSubmitError();
                    export_.emailedExport.filters = $scope.formData;
                    $rootScope.pollProgressBar(export_);
                    filterFormModalElement().modal('hide');
                } else {
                    self._handleSubmitError(data);
                }
            }).error(function (data) {
                $scope.isSubmittingForm = false;
                self._handleSubmitError(data);
            });
        };

        self._handleSubmitError = function (data) {
            $scope.hasFormSubmitError = true;
            $scope.formSubmitErrorMessage = data.error;
        };
        self._clearSubmitError = function () {
            $scope.hasFormSubmitError = false;
            $scope.formSubmitErrorMessage = null;
        };
    };

    list_exports.controller(exportsControllers);

}(window.angular));
<|endoftext|>


<commit_before>module.exports = createApp

const express = require('express')
const session = require('express-session')
const handlebars = require('express-handlebars')
const uuid = require('uuid')
const cors = require('cors')
const LDP = require('./ldp')
const LdpMiddleware = require('./ldp-middleware')
const corsProxy = require('./handlers/cors-proxy')
const authProxy = require('./handlers/auth-proxy')
const SolidHost = require('./models/solid-host')
const AccountManager = require('./models/account-manager')
const vhost = require('vhost')
const EmailService = require('./models/email-service')
const TokenService = require('./models/token-service')
const capabilityDiscovery = require('./capability-discovery')
const API = require('./api')
const errorPages = require('./handlers/error-pages')
const config = require('./server-config')
const defaults = require('../config/defaults')
const options = require('./handlers/options')
const debug = require('./debug').authentication
const path = require('path')

const corsSettings = cors({
  methods: [
    'OPTIONS', 'HEAD', 'GET', 'PATCH', 'POST', 'PUT', 'DELETE'
  ],
  exposedHeaders: 'Authorization, User, Location, Link, Vary, Last-Modified, ETag, Accept-Patch, Accept-Post, Updates-Via, Allow, WAC-Allow, Content-Length, WWW-Authenticate',
  credentials: true,
  maxAge: 1728000,
  origin: true,
  preflightContinue: true
})

function createApp (argv = {}) {
  // Override default configs (defaults) with passed-in params (argv)
  argv = Object.assign({}, defaults, argv)

  argv.host = SolidHost.from({ port: argv.port, serverUri: argv.serverUri })

  const configPath = config.initConfigDir(argv)
  argv.templates = config.initTemplateDirs(configPath)

  const ldp = new LDP(argv)

  const app = express()

  initAppLocals(app, argv, ldp)
  initHeaders(app)
  initViews(app, configPath)

  // Serve the public 'common' directory (for shared CSS files, etc)
  app.use('/common', express.static(path.join(__dirname, '../common')))

  // Add CORS proxy
  if (argv.proxy) {
    console.warn('The proxy configuration option has been renamed to corsProxy.')
    argv.corsProxy = argv.corsProxy || argv.proxy
    delete argv.proxy
  }
  if (argv.corsProxy) {
    corsProxy(app, argv.corsProxy)
  }

  // Options handler
  app.options('/*', options)

  // Set up API
  if (argv.apiApps) {
    app.use('/api/apps', express.static(argv.apiApps))
  }

  // Authenticate the user
  if (argv.webid) {
    initWebId(argv, app, ldp)
  }
  // Add Auth proxy (requires authentication)
  if (argv.authProxy) {
    authProxy(app, argv.authProxy)
  }

  // Attach the LDP middleware
  app.use('/', LdpMiddleware(corsSettings))

  // Errors
  app.use(errorPages.handler)

  return app
}

/**
 * Initializes `app.locals` parameters for downstream use (typically by route
 * handlers).
 *
 * @param app {Function} Express.js app instance
 * @param argv {Object} Config options hashmap
 * @param ldp {LDP}
 */
function initAppLocals (app, argv, ldp) {
  app.locals.ldp = ldp
  app.locals.appUrls = argv.apps  // used for service capability discovery
  app.locals.host = argv.host
  app.locals.authMethod = argv.auth
  app.locals.localAuth = argv.localAuth
  app.locals.tokenService = new TokenService()

  if (argv.email && argv.email.host) {
    app.locals.emailService = new EmailService(argv.templates.email, argv.email)
  }
}

/**
 * Sets up headers common to all Solid requests (CORS-related, Allow, etc).
 *
 * @param app {Function} Express.js app instance
 */
function initHeaders (app) {
  app.use(corsSettings)

  app.use((req, res, next) => {
    res.set('X-Powered-By', 'solid-server')

    // Cors lib adds Vary: Origin automatically
    res.set('Vary', 'Accept, Authorization')

    // Set default Allow methods
    res.set('Allow', 'OPTIONS, HEAD, GET, PATCH, POST, PUT, DELETE')
    next()
  })

  app.use('/', capabilityDiscovery())
}

/**
 * Sets up the express rendering engine and views directory.
 *
 * @param app {Function} Express.js app
 * @param configPath {string}
 */
function initViews (app, configPath) {
  const viewsPath = config.initDefaultViews(configPath)

  app.set('views', viewsPath)
  app.engine('.hbs', handlebars({
    extname: '.hbs',
    partialsDir: viewsPath
  }))
  app.set('view engine', '.hbs')
}

/**
 * Sets up WebID-related functionality (account creation and authentication)
 *
 * @param argv {Object}
 * @param app {Function}
 * @param ldp {LDP}
 */
function initWebId (argv, app, ldp) {
  config.ensureWelcomePage(argv)

  // Store the user's session key in a cookie
  // (for same-domain browsing by people only)
  const useSecureCookies = !!argv.sslKey // use secure cookies when over HTTPS
  const sessionHandler = session(sessionSettings(useSecureCookies, argv.host))
  app.use((req, res, next) => {
    sessionHandler(req, res, () => {
      // Reject cookies from third-party applications.
      // Otherwise, when a user is logged in to their Solid server,
      // any third-party application could perform authenticated requests
      // without permission by including the credentials set by the Solid server.
      const origin = req.headers.origin
      const userId = req.session.userId
      if (!argv.host.allowsSessionFor(userId, origin)) {
        debug(`Rejecting session for ${userId} from ${origin}`)
        // Destroy session data
        delete req.session.userId
        // Ensure this modified session is not saved
        req.session.save = (done) => done()
      }
      next()
    })
  })

  let accountManager = AccountManager.from({
    authMethod: argv.auth,
    emailService: app.locals.emailService,
    tokenService: app.locals.tokenService,
    host: argv.host,
    accountTemplatePath: argv.templates.account,
    store: ldp,
    multiuser: argv.multiuser
  })
  app.locals.accountManager = accountManager

  // Account Management API (create account, new cert)
  app.use('/', API.accounts.middleware(accountManager))

  // Set up authentication-related API endpoints and app.locals
  initAuthentication(app, argv)

  if (argv.multiuser) {
    app.use(vhost('*', LdpMiddleware(corsSettings)))
  }
}

/**
 * Sets up authentication-related routes and handlers for the app.
 *
 * @param app {Object} Express.js app instance
 * @param argv {Object} Config options hashmap
 */
function initAuthentication (app, argv) {
  const auth = argv.forceUser ? 'forceUser' : argv.auth
  if (!(auth in API.authn)) {
    throw new Error(`Unsupported authentication scheme: ${auth}`)
  }
  API.authn[auth].initialize(app, argv)
}

/**
 * Returns a settings object for Express.js sessions.
 *
 * @param secureCookies {boolean}
 * @param host {SolidHost}
 *
 * @return {Object} `express-session` settings object
 */
function sessionSettings (secureCookies, host) {
  let sessionSettings = {
    secret: uuid.v1(),
    saveUninitialized: false,
    resave: false,
    rolling: true,
    cookie: {
      maxAge: 24 * 60 * 60 * 1000
    }
  }
  // Cookies should set to be secure if https is on
  if (secureCookies) {
    sessionSettings.cookie.secure = true
  }

  // Determine the cookie domain
  sessionSettings.cookie.domain = host.cookieDomain

  return sessionSettings
}
<commit_msg>Add Origin header in our code<commit_after>module.exports = createApp

const express = require('express')
const session = require('express-session')
const handlebars = require('express-handlebars')
const uuid = require('uuid')
const cors = require('cors')
const LDP = require('./ldp')
const LdpMiddleware = require('./ldp-middleware')
const corsProxy = require('./handlers/cors-proxy')
const authProxy = require('./handlers/auth-proxy')
const SolidHost = require('./models/solid-host')
const AccountManager = require('./models/account-manager')
const vhost = require('vhost')
const EmailService = require('./models/email-service')
const TokenService = require('./models/token-service')
const capabilityDiscovery = require('./capability-discovery')
const API = require('./api')
const errorPages = require('./handlers/error-pages')
const config = require('./server-config')
const defaults = require('../config/defaults')
const options = require('./handlers/options')
const debug = require('./debug').authentication
const path = require('path')

const corsSettings = cors({
  methods: [
    'OPTIONS', 'HEAD', 'GET', 'PATCH', 'POST', 'PUT', 'DELETE'
  ],
  exposedHeaders: 'Authorization, User, Location, Link, Vary, Last-Modified, ETag, Accept-Patch, Accept-Post, Updates-Via, Allow, WAC-Allow, Content-Length, WWW-Authenticate',
  credentials: true,
  maxAge: 1728000,
  origin: true,
  preflightContinue: true
})

function createApp (argv = {}) {
  // Override default configs (defaults) with passed-in params (argv)
  argv = Object.assign({}, defaults, argv)

  argv.host = SolidHost.from({ port: argv.port, serverUri: argv.serverUri })

  const configPath = config.initConfigDir(argv)
  argv.templates = config.initTemplateDirs(configPath)

  const ldp = new LDP(argv)

  const app = express()

  initAppLocals(app, argv, ldp)
  initHeaders(app)
  initViews(app, configPath)

  // Serve the public 'common' directory (for shared CSS files, etc)
  app.use('/common', express.static(path.join(__dirname, '../common')))

  // Add CORS proxy
  if (argv.proxy) {
    console.warn('The proxy configuration option has been renamed to corsProxy.')
    argv.corsProxy = argv.corsProxy || argv.proxy
    delete argv.proxy
  }
  if (argv.corsProxy) {
    corsProxy(app, argv.corsProxy)
  }

  // Options handler
  app.options('/*', options)

  // Set up API
  if (argv.apiApps) {
    app.use('/api/apps', express.static(argv.apiApps))
  }

  // Authenticate the user
  if (argv.webid) {
    initWebId(argv, app, ldp)
  }
  // Add Auth proxy (requires authentication)
  if (argv.authProxy) {
    authProxy(app, argv.authProxy)
  }

  // Attach the LDP middleware
  app.use('/', LdpMiddleware(corsSettings))

  // Errors
  app.use(errorPages.handler)

  return app
}

/**
 * Initializes `app.locals` parameters for downstream use (typically by route
 * handlers).
 *
 * @param app {Function} Express.js app instance
 * @param argv {Object} Config options hashmap
 * @param ldp {LDP}
 */
function initAppLocals (app, argv, ldp) {
  app.locals.ldp = ldp
  app.locals.appUrls = argv.apps  // used for service capability discovery
  app.locals.host = argv.host
  app.locals.authMethod = argv.auth
  app.locals.localAuth = argv.localAuth
  app.locals.tokenService = new TokenService()

  if (argv.email && argv.email.host) {
    app.locals.emailService = new EmailService(argv.templates.email, argv.email)
  }
}

/**
 * Sets up headers common to all Solid requests (CORS-related, Allow, etc).
 *
 * @param app {Function} Express.js app instance
 */
function initHeaders (app) {
  app.use(corsSettings)

  app.use((req, res, next) => {
    res.set('X-Powered-By', 'solid-server')

    // Cors lib adds Vary: Origin automatically, but inreliably
    res.set('Vary', 'Accept, Authorization, Origin')

    // Set default Allow methods
    res.set('Allow', 'OPTIONS, HEAD, GET, PATCH, POST, PUT, DELETE')
    next()
  })

  app.use('/', capabilityDiscovery())
}

/**
 * Sets up the express rendering engine and views directory.
 *
 * @param app {Function} Express.js app
 * @param configPath {string}
 */
function initViews (app, configPath) {
  const viewsPath = config.initDefaultViews(configPath)

  app.set('views', viewsPath)
  app.engine('.hbs', handlebars({
    extname: '.hbs',
    partialsDir: viewsPath
  }))
  app.set('view engine', '.hbs')
}

/**
 * Sets up WebID-related functionality (account creation and authentication)
 *
 * @param argv {Object}
 * @param app {Function}
 * @param ldp {LDP}
 */
function initWebId (argv, app, ldp) {
  config.ensureWelcomePage(argv)

  // Store the user's session key in a cookie
  // (for same-domain browsing by people only)
  const useSecureCookies = !!argv.sslKey // use secure cookies when over HTTPS
  const sessionHandler = session(sessionSettings(useSecureCookies, argv.host))
  app.use((req, res, next) => {
    sessionHandler(req, res, () => {
      // Reject cookies from third-party applications.
      // Otherwise, when a user is logged in to their Solid server,
      // any third-party application could perform authenticated requests
      // without permission by including the credentials set by the Solid server.
      const origin = req.headers.origin
      const userId = req.session.userId
      if (!argv.host.allowsSessionFor(userId, origin)) {
        debug(`Rejecting session for ${userId} from ${origin}`)
        // Destroy session data
        delete req.session.userId
        // Ensure this modified session is not saved
        req.session.save = (done) => done()
      }
      next()
    })
  })

  let accountManager = AccountManager.from({
    authMethod: argv.auth,
    emailService: app.locals.emailService,
    tokenService: app.locals.tokenService,
    host: argv.host,
    accountTemplatePath: argv.templates.account,
    store: ldp,
    multiuser: argv.multiuser
  })
  app.locals.accountManager = accountManager

  // Account Management API (create account, new cert)
  app.use('/', API.accounts.middleware(accountManager))

  // Set up authentication-related API endpoints and app.locals
  initAuthentication(app, argv)

  if (argv.multiuser) {
    app.use(vhost('*', LdpMiddleware(corsSettings)))
  }
}

/**
 * Sets up authentication-related routes and handlers for the app.
 *
 * @param app {Object} Express.js app instance
 * @param argv {Object} Config options hashmap
 */
function initAuthentication (app, argv) {
  const auth = argv.forceUser ? 'forceUser' : argv.auth
  if (!(auth in API.authn)) {
    throw new Error(`Unsupported authentication scheme: ${auth}`)
  }
  API.authn[auth].initialize(app, argv)
}

/**
 * Returns a settings object for Express.js sessions.
 *
 * @param secureCookies {boolean}
 * @param host {SolidHost}
 *
 * @return {Object} `express-session` settings object
 */
function sessionSettings (secureCookies, host) {
  let sessionSettings = {
    secret: uuid.v1(),
    saveUninitialized: false,
    resave: false,
    rolling: true,
    cookie: {
      maxAge: 24 * 60 * 60 * 1000
    }
  }
  // Cookies should set to be secure if https is on
  if (secureCookies) {
    sessionSettings.cookie.secure = true
  }

  // Determine the cookie domain
  sessionSettings.cookie.domain = host.cookieDomain

  return sessionSettings
}
<|endoftext|>