<commit_before>$(document).ready(function () {
    bindEvents();
});

function bindEvents(){
    $('select').material_select();
    $('.question').on('click', '.updateQuestion', updateQuestion);

    $('.makeQuestion').on('click', makeQuestion);
    $('.questions').on('click', '.newanswer', addNewAnswer);
    $('.questions').on('click', '.removeanswer', removeAnswer);
    $('body').on('click', '.markcorrect', markCorrect);
    $('.question').on('click','.removeQuestion',removeQuestion);
    $(".dropdown-button").dropdown();
    $(".button-collapse").sideNav();
    $('form').on('change',updateQuestion);
    $('body').on('change','#difficulty',redirect);
    $('body').on('change','#category',redirect);
}

var redirect = function(){
    if($(this).prop('selectedIndex') == 1) window.location = this.value;
}

var updateQuestion = function(){
  ////console.log("updating question");
  //getting data
  //console.log("updating");

  var questionId = $(this).closest('.question').attr("questionid");
  var question = $(this).closest('.question').find("[name='question']").val();
  var difficulty = $(this).closest('.question').find("[name='difficulty']").val();
  var category = $(this).closest('.question').find("[name='category']").val();

  var img = $(this).closest('.question').find("[name='image']").attr("src");
  var imgLink="";
  if(img != "images/No-image-found.jpg"){
    imgLink = "imageQuestion_"+questionId+".png";
  }

  var ajaxurl = 'dbaction.php',
  data =  {
    'action': 'updateQuestion',
    'questionId': questionId,
    'question': question,
    'difficulty': difficulty,
    'category':category,
    'imgLink': imgLink
  };
  $.post(ajaxurl, data, function (response) {
      if(response == "success") {
          Materialize.toast("Vraag opgeslagen!",1000);
      } else if(response == "error") {
          Materialize.toast("Fout bij het opslaan van vraag!",1000);
      }
  });

 var answerlist = $(this).find('.answer li');
 //console.log("before");
  ////console.log($(this).parent().parent().parent().find(".answers"));
  var ul = $(this).closest(".collapsible-body").find(".answers");
  $(ul).find(".answer").each(function(){

   var answerId = $(this).attr("answerid");
   var answer = $(this).find("input").val();
   var correct = $(this).attr("correct");
   //console.log("answerid:"+answerId );
   //console.log("answer:"+answer);
   //console.log("correct:"+correct );

   var ajaxurl = 'dbaction.php',
   data =  {
     'action': 'updateAnswer',
     'answerId':answerId,
     'answer': answer,
     'correct': correct
   };
   $.post(ajaxurl, data, function (response) {
       if(response == "success") {
           Materialize.toast("Antwoord opgeslagen!",1000);
       } else if(response == "error") {
           Materialize.toast("Fout bij het opslaan van antwoord!",1000);
       }
   });

 });

}

var makeQuestion = function(){
  //console.log("making question");

    var url_string = window.location.href;
    var url = new URL(url_string);
    var quizId = url.searchParams.get("id");
    //console.log("quizId:"+ quizId);
    quizId = parseInt(quizId);

  var ajaxurl = 'dbaction.php',
  data =  {
    'action': 'createQuestion',
    'question': 'nieuwe vraag',
    'difficulty': null,
    'imgLink': '',
    'category': null,
    'quizId':quizId
  };
  ////console.log(quizId)

  $.post(ajaxurl, data, function (response) {
        if(response == "success") {
            Materialize.toast("Nieuwe vraag aangemaakt!",1000);
            location.reload();
        } else if(response == "error") {
            Materialize.toast("Fout bij het opslaan van vraag!",1000);
        }

  });

}

var removeQuestion = function(e){
    e.preventDefault();

    var currentQuestion = $(this).closest('.question');
    var questionId = currentQuestion.attr('questionid');

    var ajaxurl = 'dbaction.php',
      data =  {
      'action': 'deleteQuestion',
      'questionId': questionId
    };
    $.post(ajaxurl, data, function (response) {

        if(response == "success") {
            Materialize.toast("Vraag verwijderd",1000);
            location.reload();
        } else if(response == "error") {
            Materialize.toast("Fout bij het verwijderen van vraag!",1000);
        }

    });

}
var addNewAnswer = function (e) {
    e.preventDefault();
    var newInput = '

' +
        '<input placeholder="Antwoord " type="text" class="validate">' +
        'delete' +
        ' done' +
        '

';
     $(this).closest('.question').find('.answers').append(newInput);

    var questionId = $(this).closest('.question').attr("questionid");
    var answer = "Nieuw antwoord";
    var correct = 0;
    var that = this;

    var ajaxurl = 'dbaction.php',
      data =  {
      'action': 'makeAnswer',
      'questionId': questionId,
      'answer': answer,
      'correct': correct
    };

    $.post(ajaxurl, data, function (response) {
        if(response == "success") {
            Materialize.toast("Nieuw antwoord aangemaakt!",1000);

            var id = $(that).closest('.question').attr("questionid");
            var div = $(that).parent().parent().parent().find(".answersdiv"+id);
            var thegodrow = $(that).parent().parent().parent().find(".answers");
            $(div).load(document.URL +  ' .answersdiv'+id+' .answers');
        } else if(response == "error") {
            Materialize.toast("Fout bij het aanmaken van antwoord!",1000);
        }

    });
};

var removeAnswer = function (e) {
    e.preventDefault();
    var parent = $(this).closest('.answers');
    var currentAnswer = $(this).closest('.answer');
    if (parent.children().length <= 1) {
        Materialize.toast('Je hebt geen antwoorden meer!', 4000)
    } else {
        currentAnswer.remove();
    }

    var answerId = $(this).closest(".answer").attr("answerid");
    //console.log("te verwijderen id: "+answerId);

    var ajaxurl = 'dbaction.php',
      data =  {
      'action': 'deleteAnswer',
      'answerId': answerId
    };
    $.post(ajaxurl, data, function (response) {
        if(response == "success") {
            Materialize.toast("Antwoord verwijderd!",1000);
        } else if(response == "error") {
            Materialize.toast("Fout bij het verwijderen van antwoord!",1000);
        }

    });
}

var markCorrect = function(){
  //console.log("correct!");

  $(this).removeClass("orange").addClass("green");
  $(this).closest(".answer").attr("correct", 1);
  var clickedAnswerId = $(this).closest(".answer").attr("answerid");

  var ul = $(this).closest(".collapsible-body").find(".answers");
   $(ul).find(".answer").each(function(){
     if($(this).attr("answerid") != clickedAnswerId){
       $(this).find(".markcorrect").removeClass("orange").removeClass("green").addClass("red");
       $(this).attr("correct", 0)
     }
   });
};
<commit_msg>Made small script that auto saves on focus loss<commit_after>$(document).ready(function () {
    bindEvents();
});

function bindEvents(){
    $('select').material_select();
    $('.question').on('click', '.updateQuestion', updateQuestion);

    addEventListenerToAnswers();
    addEventListenerToQuestions();

    $('.makeQuestion').on('click', makeQuestion);
    $('.questions').on('click', '.newanswer', addNewAnswer);
    $('.questions').on('click', '.removeanswer', removeAnswer);
    $('body').on('click', '.markcorrect', markCorrect);
    $('.question').on('click','.removeQuestion',removeQuestion);
    $(".dropdown-button").dropdown();
    $(".button-collapse").sideNav();
    $('form').on('change',updateQuestion);
    $('body').on('change','#difficulty',redirect);
    $('body').on('change','#category',redirect);

}

var redirect = function(){
    if($(this).prop('selectedIndex') == 1) window.location = this.value;
}

function addEventListenerToQuestions(){
    var questionList = document.getElementsByTagName("form");
    for(var i = 0; i < questionList.length;i++){
        questionList[i].childNodes[3].onblur = function(){
            updateQuestion();
        };

    }

}

function addEventListenerToAnswers(){
    var answerList = document.getElementsByClassName("answer");
    for(var i = 0; i < answerList.length;i++){
        answerList[i].childNodes[0].childNodes[1].onblur = function(){
            updateQuestion();
        };

    }

}

var updateQuestion = function(){
  ////console.log("updating question");
  //getting data
  //console.log("updating");

  var questionId = $(this).closest('.question').attr("questionid");
  var question = $(this).closest('.question').find("[name='question']").val();
  var difficulty = $(this).closest('.question').find("[name='difficulty']").val();
  var category = $(this).closest('.question').find("[name='category']").val();

  var img = $(this).closest('.question').find("[name='image']").attr("src");
  var imgLink="";
  if(img != "images/No-image-found.jpg"){
    imgLink = "imageQuestion_"+questionId+".png";
  }

  var ajaxurl = 'dbaction.php',
  data =  {
    'action': 'updateQuestion',
    'questionId': questionId,
    'question': question,
    'difficulty': difficulty,
    'category':category,
    'imgLink': imgLink
  };
  $.post(ajaxurl, data, function (response) {
      if(response == "success") {
          Materialize.toast("Vraag opgeslagen!",1000);
      } else if(response == "error") {
          Materialize.toast("Fout bij het opslaan van vraag!",1000);
      }
  });

 var answerlist = $(this).find('.answer li');
 //console.log("before");
  ////console.log($(this).parent().parent().parent().find(".answers"));
  var ul = $(this).closest(".collapsible-body").find(".answers");
  $(ul).find(".answer").each(function(){

   var answerId = $(this).attr("answerid");
   var answer = $(this).find("input").val();
   var correct = $(this).attr("correct");
   //console.log("answerid:"+answerId );
   //console.log("answer:"+answer);
   //console.log("correct:"+correct );

   var ajaxurl = 'dbaction.php',
   data =  {
     'action': 'updateAnswer',
     'answerId':answerId,
     'answer': answer,
     'correct': correct
   };
   $.post(ajaxurl, data, function (response) {
       if(response == "success") {
           Materialize.toast("Antwoord opgeslagen!",1000);
       } else if(response == "error") {
           Materialize.toast("Fout bij het opslaan van antwoord!",1000);
       }
   });

 });

}

var makeQuestion = function(){
  //console.log("making question");

    var url_string = window.location.href;
    var url = new URL(url_string);
    var quizId = url.searchParams.get("id");
    //console.log("quizId:"+ quizId);
    quizId = parseInt(quizId);

  var ajaxurl = 'dbaction.php',
  data =  {
    'action': 'createQuestion',
    'question': 'nieuwe vraag',
    'difficulty': null,
    'imgLink': '',
    'category': null,
    'quizId':quizId
  };
  ////console.log(quizId)

  $.post(ajaxurl, data, function (response) {
        if(response == "success") {
            Materialize.toast("Nieuwe vraag aangemaakt!",1000);
            location.reload();
        } else if(response == "error") {
            Materialize.toast("Fout bij het opslaan van vraag!",1000);
        }

  });

}

var removeQuestion = function(e){
    e.preventDefault();

    var currentQuestion = $(this).closest('.question');
    var questionId = currentQuestion.attr('questionid');

    var ajaxurl = 'dbaction.php',
      data =  {
      'action': 'deleteQuestion',
      'questionId': questionId
    };
    $.post(ajaxurl, data, function (response) {

        if(response == "success") {
            Materialize.toast("Vraag verwijderd",1000);
            location.reload();
        } else if(response == "error") {
            Materialize.toast("Fout bij het verwijderen van vraag!",1000);
        }

    });

}
var addNewAnswer = function (e) {
    e.preventDefault();
    var newInput = '

' +
        '<input placeholder="Antwoord " type="text" class="validate">' +
        'delete' +
        ' done' +
        '

';
     $(this).closest('.question').find('.answers').append(newInput);

    var questionId = $(this).closest('.question').attr("questionid");
    var answer = "Nieuw antwoord";
    var correct = 0;
    var that = this;

    var ajaxurl = 'dbaction.php',
      data =  {
      'action': 'makeAnswer',
      'questionId': questionId,
      'answer': answer,
      'correct': correct
    };

    $.post(ajaxurl, data, function (response) {
        if(response == "success") {
            Materialize.toast("Nieuw antwoord aangemaakt!",1000);

            var id = $(that).closest('.question').attr("questionid");
            var div = $(that).parent().parent().parent().find(".answersdiv"+id);
            var thegodrow = $(that).parent().parent().parent().find(".answers");
            $(div).load(document.URL +  ' .answersdiv'+id+' .answers');
        } else if(response == "error") {
            Materialize.toast("Fout bij het aanmaken van antwoord!",1000);
        }

    });
};

var removeAnswer = function (e) {
    e.preventDefault();
    var parent = $(this).closest('.answers');
    var currentAnswer = $(this).closest('.answer');
    if (parent.children().length <= 1) {
        Materialize.toast('Je hebt geen antwoorden meer!', 4000)
    } else {
        currentAnswer.remove();
    }

    var answerId = $(this).closest(".answer").attr("answerid");
    //console.log("te verwijderen id: "+answerId);

    var ajaxurl = 'dbaction.php',
      data =  {
      'action': 'deleteAnswer',
      'answerId': answerId
    };
    $.post(ajaxurl, data, function (response) {
        if(response == "success") {
            Materialize.toast("Antwoord verwijderd!",1000);
        } else if(response == "error") {
            Materialize.toast("Fout bij het verwijderen van antwoord!",1000);
        }

    });
}

var markCorrect = function(){
  //console.log("correct!");

  $(this).removeClass("orange").addClass("green");
  $(this).closest(".answer").attr("correct", 1);
  var clickedAnswerId = $(this).closest(".answer").attr("answerid");

  var ul = $(this).closest(".collapsible-body").find(".answers");
   $(ul).find(".answer").each(function(){
     if($(this).attr("answerid") != clickedAnswerId){
       $(this).find(".markcorrect").removeClass("orange").removeClass("green").addClass("red");
       $(this).attr("correct", 0)
     }
   });
};
<|endoftext|>


<commit_before>
// [START app]
'use strict';

// [START setup]

var express = require('express');

var app = express();
var google = require('googleapis');
//var bigquery = google.bigquery('v2');

app.enable('trust proxy');

var Datastore = require('@google-cloud/datastore');
//const BigQuery = require('@google-cloud/bigquery');
const projectId = "doolinhomeiot";
const datasetId = "OfficeData";
const tableId = "iotdata";

// Instantiate a datastore client
var datastore = Datastore();

var PubSub = require('@google-cloud/pubsub');

//Instantiate a pubsub client
var pubsub = PubSub();

var PUBSUB_VERIFICATION_TOKEN = process.env.PUBSUB_VERIFICATION_TOKEN;

var topic = pubsub.topic(process.env.PUBSUB_TOPIC);

var subscription = pubsub.subscription(process.env.PUBSUB_SUBSCRIPTION_NAME);

// [END setup]

function storeEvent(message) {
    var key = datastore.key('officedata');
    key.identifier = "id"
    // You can uncomment some of the other things if you want to store them in the database

    var obj = {
        messageid: message.id
        //deviceid: message.attributes.device_id,
        ////event: message.attributes.event,
        //published: message.attributes.published_at,
        //data: message.data
    }
    datastore.save(
        {
            key: key,
            data: obj
        }, function (err) {
            if (err) {
                console.log('There was an error storing the event', err);
            }
            console.log('stored in datastore', obj);
            console.log('Begin BIGQUERY:');
            var content = {"nameid": "789", "messagedata": "test1k"};
            console.log('content:' + content);
            //let rows = null;
            try {
                var rows = JSON.parse(content)
            } catch (err) {
           }
            console.log('beforeinsert');
        insertRowsAsStream(datasetId,tableId,rows,projectId)
        }
    );

}

function insertRowsAsStream (datasetId, tableId, rows, projectId) {
    // [START bigquery_insert_stream]
    // Imports the Google Cloud client library
    const BigQuery = require('@google-cloud/bigquery');
   console.log('INinsert');

    // Instantiates a client
    const bigquery = BigQuery({
        projectId: projectId
    });

    // Inserts data into a table
    bigquery
        .dataset(datasetId)
        .table(tableId)
        .insert(rows)
        .then((insertErrors) => {
        console.log('Inserted:');
    rows.forEach((row) => console.log(row));

    if (insertErrors && insertErrors.length > 0) {
        console.log('Insert errors:');
        insertErrors.forEach((err) => console.error(err));
    }
})
.catch((err) => {
        console.error('ERROR:', err);
});
    // [END bigquery_insert_stream]
}

subscription.on('message', function (message) {
    console.log('event received', message);
    // Called every time a message is received.
    // message.id = ID used to acknowledge its receival.
    // message.data = Contents of the message.
    // message.attributes = Attributes of the message.
    storeEvent(message);
    message.ack();
});

// [START listen]
var server = app.listen(process.env.PORT || 8080, function () {
    console.log('App listening on port %s', server.address().port);
    console.log('Press Ctrl+C to quit.');
});
// [END listen]
// [END app]

module.exports = app;
<commit_msg>Update app.js<commit_after>
// [START app]
'use strict';

// [START setup]

var express = require('express');

var app = express();
var google = require('googleapis');
//var bigquery = google.bigquery('v2');

app.enable('trust proxy');

var Datastore = require('@google-cloud/datastore');
//const BigQuery = require('@google-cloud/bigquery');
const projectId = "doolinhomeiot";
const datasetId = "OfficeData";
const tableId = "iotdata";

// Instantiate a datastore client
var datastore = Datastore();

var PubSub = require('@google-cloud/pubsub');

//Instantiate a pubsub client
var pubsub = PubSub();

var PUBSUB_VERIFICATION_TOKEN = process.env.PUBSUB_VERIFICATION_TOKEN;

var topic = pubsub.topic(process.env.PUBSUB_TOPIC);

var subscription = pubsub.subscription(process.env.PUBSUB_SUBSCRIPTION_NAME);

// [END setup]

function storeEvent(message) {
    var key = datastore.key('officedata');
    key.identifier = "id"
    // You can uncomment some of the other things if you want to store them in the database

    var obj = {
        messageid: message.id
        //deviceid: message.attributes.device_id,
        ////event: message.attributes.event,
        //published: message.attributes.published_at,
        //data: message.data
    }
    datastore.save(
        {
            key: key,
            data: obj
        }, function (err) {
            if (err) {
                console.log('There was an error storing the event', err);
            }
            console.log('stored in datastore', obj);
            console.log('Begin BIGQUERY:');
            var content = {"nameid": "789", "messagedata": "test1k"};
            console.log('content:' + content);
            //let rows = null;
            try {
                var rows = JSON.parse(content)
            } catch (err) {
           }
        insertRowsAsStream(datasetId,tableId,rows,projectId)
        }
    );

}

function insertRowsAsStream (datasetId, tableId, rows, projectId) {
    // [START bigquery_insert_stream]
    // Imports the Google Cloud client library
    const BigQuery = require('@google-cloud/bigquery');

    // Instantiates a client
    const bigquery = BigQuery({
        projectId: projectId
    });

    // Inserts data into a table
    bigquery
        .dataset(datasetId)
        .table(tableId)
        .insert(rows)
        .then((insertErrors) => {
        console.log('Inserted:');
    rows.forEach((row) => console.log(row));

    if (insertErrors && insertErrors.length > 0) {
        console.log('Insert errors:');
        insertErrors.forEach((err) => console.error(err));
    }
})
.catch((err) => {
        console.error('ERROR:', err);
});
    // [END bigquery_insert_stream]
}

subscription.on('message', function (message) {
    console.log('event received', message);
    // Called every time a message is received.
    // message.id = ID used to acknowledge its receival.
    // message.data = Contents of the message.
    // message.attributes = Attributes of the message.
    storeEvent(message);
    message.ack();
});

// [START listen]
var server = app.listen(process.env.PORT || 8080, function () {
    console.log('App listening on port %s', server.address().port);
    console.log('Press Ctrl+C to quit.');
});
// [END listen]
// [END app]

module.exports = app;
<|endoftext|>


<commit_before>/**
 * Parses text to return to the log items
 * Created by cos-caner on 12/4/15.
 * Remember to embed nodes, user, linked_node and template_node in api call i.e. var url = $osf.apiV2Url('nodes/' + nodeId + '/logs/', { query : { 'embed' : ['nodes', 'user']}});
 */
var m = require('mithril'); // exposes mithril methods, useful for redraw etc.
var logActions = require('json!js/_allLogTexts.json');
var $ = require('jquery');  // jQuery
var $osf = require('js/osfHelpers');

var ravenMessagesCache = []; // Cache messages to avoid sending multiple times in one page view
/**
 * Utility function to not repeat logging errors to Sentry
 * @param message {String} Custom message for error
 * @param logObject {Object} the entire log object returned from the api
 */
function ravenMessage (message, logObject) {
    if(ravenMessagesCache.indexOf(message) === -1){
        Raven.captureMessage(message, {logObject: logObject});
        ravenMessagesCache.push(message);
    }
}

/**
 * Checks if the required parameter to complete the log is returned
 * This may intentionally not be returned to make log anonymous
 * @param param {string|number} The parameter to be used
 * @param logObject {Object} the entire log object returned from the api
 * @returns {boolean}
 */
var paramIsReturned = function _paramIsReturned (param, logObject){
    if(!param){
        var message = 'Expected parameter for Log action ' + logObject.attributes.action + ' was not returned from log api.';
        ravenMessage(message, logObject);
        return false;
    }
    if (param.errors){
        return false;
    }
    return true;
};

/**
 * Returns the text parameters since their formatting is mainly the same
 * @param param {string} The parameter to be used, has to be available under logObject.attributes.param
 * @param text {string} The text to be used if param is not available
 * @param logObject {Object} the entire log object returned from the api
 * @returns {*}
 */
var returnTextParams = function (param, text, logObject, view_url) {
    var source = logObject.attributes.params[param];

    if(paramIsReturned(source, logObject)){
        if($.isArray(source)){
            return m('span', [
                source.map(function(item, index, arr){
                    if(arr.length === 1 && index === 0){
                        return m('span', item);
                    }
                    if(index === arr.length-1) {
                        return m('span', ', and ' + item);
                    }
                    return m('span', item + ', ');
                })
            ]);
        }
        if (param === 'path' && source.charAt(0) === '/'){
            source = source.substr(1, source.length);
        }
        return view_url ? m('a', {href: view_url}, source) : m('span', source);
    }
    return m('span', text);
};

var LogText = {
    controller: function(logObject){
        var self = this;

        self.userInfoReturned = function(userObject){
            if (userObject){
                if (userObject.data){
                    return true;
                }
                else if (userObject.errors[0].meta){
                    return true;
                }
            }
            return false;
        };

        self.logText = function() {
            var text = logActions[logObject.attributes.action];
            if (text) {
                if (text.indexOf('${user}') !== -1) {
                    var userObject = logObject.embeds.user;
                    if (self.userInfoReturned(userObject)) {
                        return text;
                    }
                    else {
                        var newAction = logObject.attributes.action + '_no_user';
                        return logActions[newAction] ? logActions[newAction]: text;
                    }
                }
                return text;
            }
        return null;
        };
    },
    view : function(ctrl, logObject) {
        var message = '';
        var text = ctrl.logText();
        if(text){
            var list = text.split(/(\${.*?})/);
            return m('span.osf-log-item',[
                list.map(function(piece){
                    if (piece === '') {
                        return m('span');
                    }
                    var startsWith = piece.substring(0,2);
                    if(startsWith === '${'){
                        var last = piece.length-1;
                        var logComponentName = piece.substring(2,last);
                        if(LogPieces[logComponentName]){
                            return m.component(LogPieces[logComponentName], logObject);
                        } else {
                            message = 'There is no template in logTextParser.js for  ' + logComponentName + '.';
                            ravenMessage(message, logObject);
                            return m('');
                        }
                    }
                    return piece;
                })
            ]);
        } else {
            message = 'There is no text entry in dictionary for the action :' + logObject.attributes.action;
            ravenMessage(message, logObject);
            return m('');
        }
    }
};

var LogPieces = {
    // User that took the action
    user: {
        view: function (ctrl, logObject) {
            var userObject = logObject.embeds.user;
            if(paramIsReturned(userObject, logObject) && userObject.data) {
                return m('a', {href: userObject.data.links.html, onclick: function() {
                    $osf.trackClick(logObject.trackingCategory, logObject.trackingAction, 'navigate-to-user-from-logs');
                }}, userObject.data.attributes.full_name);
            }
            else if (userObject && userObject.errors[0].meta) {
                return m('span', userObject.errors[0].meta.full_name);
            }
            else {
                return m('span', 'A user');
            }
        }
    },
    // Node involved
    node: {
        view: function (ctrl, logObject) {
            var nodeObject = logObject.embeds.nodes;

            if (logObject.attributes.action === 'node_removed') {
                if (logObject.attributes.params.params_node) {
                return m('span', logObject.attributes.params.params_node.title);
            }}
            else if(paramIsReturned(nodeObject, logObject) && nodeObject.data[0]){
                if (nodeObject.data[0].links && nodeObject.data[0].attributes) {
                    return m('a', {href: nodeObject.data[0].links.html, onclick: function() {
                        $osf.trackClick(logObject.trackingCategory, logObject.trackingAction, 'navigate-to-project-from-logs');
                    }}, nodeObject.data[0].attributes.title);
                }
                else if (nodeObject.data[0].attributes) {
                    return m('span', nodeObject.data[0].attributes.title);
                }
            } else {
                return m('span', 'a project');
            }
        }
    },
    // Contrubutor list of added, updated etc.
    contributors: {
        view: function (ctrl, logObject) {
            var contributors = logObject.embeds.contributors;
            if(paramIsReturned(contributors, logObject)) {
                return m('span', contributors.data.map(function(item, index, arr){
                    var comma = ' ';
                    if(index !== arr.length - 1){
                        comma = ', ';
                    }
                    if(index === arr.length-2){
                        comma = ' and ';
                    }
                    if (item.attributes.active) {
                        return [ m('a', {href: item.links.html}, item.attributes.full_name), comma];
                    }
                    else {
                        return [item.attributes.full_name, comma];

                    }
                }));
            }
            return m('span', 'some users');
        }
    },
    // The tag added to item involved
    tag: {
        view: function (ctrl, logObject) {
            var tag = logObject.attributes.params.tag;
            if(paramIsReturned(tag, logObject)) {
               return m('a', {href: '/search/?q=%22' + tag + '%22'}, tag);
            }
            return m('span', 'a tag');
       }
    },
    // Node that is linked to the node involved
    pointer: {
        view: function (ctrl, logObject) {
            var linked_node = logObject.embeds.linked_node;
            if(paramIsReturned(linked_node, logObject)){
                return m('a', {href: linked_node.data.links.html}, linked_node.data.attributes.title);
            }
            return m('span','a project' );
        }
    },
    // Node that acted as template to create a new node involved
    template: {
        view: function (ctrl, logObject) {
            var template_node = logObject.embeds.template_node;
            if(paramIsReturned(template_node, logObject)){
                return m('a', {href: template_node.data.links.html}, template_node.data.attributes.title);
            }
            return m('span','a project' );
        }
    },
    // The original title of node involved
    title_original: {
        view: function (ctrl, logObject) {
            return returnTextParams('title_original', 'a title', logObject);
        }
    },
    // The new title of node involved
    title_new: {
        view: function (ctrl, logObject) {
            return returnTextParams('title_new', 'a title', logObject);
        }
    },
    // Update fields for the node
    updated_fields: {
        view: function (ctrl, logObject) {
            return returnTextParams('updated_fields', 'field(s)', logObject);
        }
    },
    // external identifiers on node
    identifiers: {
        view: function (ctrl, logObject) {
            return returnTextParams('identifiers', 'identifier(s)', logObject);
        }
    },
    // Wiki page name
    page: {
        controller: function(logObject){
            var self = this;
            self.returnLinkForPath = function() {
                if (logObject) {
                    var action = logObject.attributes.action;
                    var acceptableLinkedItems = ['wiki_updated', 'wiki_renamed'];
                    if (acceptableLinkedItems.indexOf(action) !== -1) {
                        return logObject.attributes.params.page_id + '/';
                    }
                }
                return null;
            };
        },
        view: function (ctrl, logObject) {
            var url = ctrl.returnLinkForPath();
            return returnTextParams('page', 'a title', logObject, url);
        }
    },
    // Old wiki title that's renamed
    old_page: {
        view: function (ctrl, logObject) {
            var url = logObject.attributes.params.page_id + '/';
            return returnTextParams('old_page', 'a title', logObject, url);
        }
    },
    // Wiki page version
    version: {
        view: function (ctrl, logObject) {
            var version = logObject.attributes.params.version;
            if(paramIsReturned(version, logObject)){
                return m('span', version);
            }
            return m('span', '#');
        }
    },
    //
    source: {
        view: function (ctrl, logObject) {
            var source = logObject.attributes.params.source;
            if(paramIsReturned(source, logObject)){
                return m('span', [source.materialized, ' in ', source.addon]);
            }
            return m('span','a name/location' );
        }
    },
    //
    destination: {
        view: function (ctrl, logObject) {
            var destination = logObject.attributes.params.destination;
            if(paramIsReturned(destination, logObject)){
                if (destination.materialized.endsWith('/')){
                    return m('span', [destination.materialized, ' in ', destination.addon]);
                }
                return m('span', [m('a', {href: destination.url}, destination.materialized), ' in ', destination.addon]);
            }
            return m('span','a new name/location' );
        }
    },
        //
    path: {
        controller: function(logObject){
            var self = this;
            self.returnLinkForPath = function() {
                if (logObject) {
                    var action = logObject.attributes.action;
                    var acceptableLinkedItems = ['file_added', 'file_restored', 'osf_storage_file_added', 'osf_storage_file_updated'];
                    if (acceptableLinkedItems.indexOf(action) !== -1) {
                        return logObject.attributes.params.view_url;
                    }
                }
                return null;
            };
        },
        view: function (ctrl, logObject) {
            var url = ctrl.returnLinkForPath();
            return returnTextParams('path', 'a file', logObject, url);
        }
    },
        //
    filename: {
        view: function (ctrl, logObject) {
            return returnTextParams('filename', 'a title', logObject);
        }
    },

    folder: {
        view: function(ctrl, logObject) {
            return returnTextParams('folder', 'a folder', logObject);
        }
    },

    repo: {
        view: function(ctrl, logObject) {
            var github_user = logObject.attributes.params.github_user;
            var github_repo = logObject.attributes.params.github_repo;
            if (paramIsReturned(github_repo, logObject) && paramIsReturned(github_user, logObject)){
                return m('span', github_user + '/' + github_repo);
            }
            return m('span', '');
        }
    },

    folder_name: {
        view: function(ctrl, logObject) {
            return returnTextParams('folder_name', 'a folder', logObject);
        }
    },

    bucket: {
        view: function(ctrl, logObject) {
            return returnTextParams('bucket', 'a bucket', logObject);
        }
    },

    forward_url: {
        view: function(ctrl, logObject) {
            var url = logObject.attributes.params.forward_url;
            return returnTextParams('forward_url', 'a new URL', logObject, url);
        }
    },

    box_folder: {
        view: function(ctrl, logObject) {
            var folder = logObject.attributes.params.folder;
            if(paramIsReturned(folder, logObject)){
                return m('span', folder === 'All Files' ? '/ (Full Box)' : (folder || '').replace('All Files',''));
            }
            return m('span', '');
        }
    },

    citation: {
        view: function(ctrl, logObject) {
            return returnTextParams('citation_name', '', logObject);
        }
    },

    dataset: {
        view: function(ctrl, logObject){
            return returnTextParams('data_set', '', logObject);
        }
    },

    study: {
        view: function(ctrl, logObject){
            return returnTextParams('study', '', logObject);
        }
    },

    googledrive_path: {
        view: function(ctrl, logObject){
            var path = logObject.attributes.params.path;
            if(paramIsReturned(path, logObject)){
                return m('span', decodeURIComponent(path));
            }
            return m('span', '');
        }
    },

    googledrive_folder: {
        view: function(ctrl, logObject){
            var folder = logObject.attributes.params.folder;
            if(paramIsReturned(folder, logObject)){
                return m('span', folder === '/' ? '(Full Google Drive)' : decodeURIComponent(folder));
            }
            return m('span', '');
        }
    },

    addon: {
        view: function(ctrl, logObject){
            return returnTextParams('addon', '', logObject);
        }
    },

    previous_institution: {
        view: function(ctrl, logObject){
            var previous_institution = logObject.attributes.params.previous_institution;
            if (paramIsReturned(previous_institution, logObject)){
                return m('span', previous_institution.name);
            }
            return m('span', 'an institution');
        }
    },

    institution: {
        view: function(ctrl, logObject){
            var institution = logObject.attributes.params.institution;
            if (paramIsReturned(institution, logObject)){
                return m('span', institution.name);
            }
            return m('span', 'an institution');
        }
    },

    comment_file: {
        view: function(ctrl,logObject){
            var file = logObject.attributes.params.file;
            if (file){  // skipe paramIsReturned, as not having a file is expected at times
                return m('span', ['in ', m('a', {href: file.url}, file.name)]);
            }
            return m('span', '');
        }
    }
};

module.exports = LogText;
<commit_msg>Remove wiki links and links for file_added and file_restored.<commit_after>/**
 * Parses text to return to the log items
 * Created by cos-caner on 12/4/15.
 * Remember to embed nodes, user, linked_node and template_node in api call i.e. var url = $osf.apiV2Url('nodes/' + nodeId + '/logs/', { query : { 'embed' : ['nodes', 'user']}});
 */
var m = require('mithril'); // exposes mithril methods, useful for redraw etc.
var logActions = require('json!js/_allLogTexts.json');
var $ = require('jquery');  // jQuery
var $osf = require('js/osfHelpers');

var ravenMessagesCache = []; // Cache messages to avoid sending multiple times in one page view
/**
 * Utility function to not repeat logging errors to Sentry
 * @param message {String} Custom message for error
 * @param logObject {Object} the entire log object returned from the api
 */
function ravenMessage (message, logObject) {
    if(ravenMessagesCache.indexOf(message) === -1){
        Raven.captureMessage(message, {logObject: logObject});
        ravenMessagesCache.push(message);
    }
}

/**
 * Checks if the required parameter to complete the log is returned
 * This may intentionally not be returned to make log anonymous
 * @param param {string|number} The parameter to be used
 * @param logObject {Object} the entire log object returned from the api
 * @returns {boolean}
 */
var paramIsReturned = function _paramIsReturned (param, logObject){
    if(!param){
        var message = 'Expected parameter for Log action ' + logObject.attributes.action + ' was not returned from log api.';
        ravenMessage(message, logObject);
        return false;
    }
    if (param.errors){
        return false;
    }
    return true;
};

/**
 * Returns the text parameters since their formatting is mainly the same
 * @param param {string} The parameter to be used, has to be available under logObject.attributes.param
 * @param text {string} The text to be used if param is not available
 * @param logObject {Object} the entire log object returned from the api
 * @returns {*}
 */
var returnTextParams = function (param, text, logObject, view_url) {
    var source = logObject.attributes.params[param];

    if(paramIsReturned(source, logObject)){
        if($.isArray(source)){
            return m('span', [
                source.map(function(item, index, arr){
                    if(arr.length === 1 && index === 0){
                        return m('span', item);
                    }
                    if(index === arr.length-1) {
                        return m('span', ', and ' + item);
                    }
                    return m('span', item + ', ');
                })
            ]);
        }
        if (param === 'path' && source.charAt(0) === '/'){
            source = source.substr(1, source.length);
        }
        return view_url ? m('a', {href: view_url}, source) : m('span', source);
    }
    return m('span', text);
};

var LogText = {
    controller: function(logObject){
        var self = this;

        self.userInfoReturned = function(userObject){
            if (userObject){
                if (userObject.data){
                    return true;
                }
                else if (userObject.errors[0].meta){
                    return true;
                }
            }
            return false;
        };

        self.logText = function() {
            var text = logActions[logObject.attributes.action];
            if (text) {
                if (text.indexOf('${user}') !== -1) {
                    var userObject = logObject.embeds.user;
                    if (self.userInfoReturned(userObject)) {
                        return text;
                    }
                    else {
                        var newAction = logObject.attributes.action + '_no_user';
                        return logActions[newAction] ? logActions[newAction]: text;
                    }
                }
                return text;
            }
        return null;
        };
    },
    view : function(ctrl, logObject) {
        var message = '';
        var text = ctrl.logText();
        if(text){
            var list = text.split(/(\${.*?})/);
            return m('span.osf-log-item',[
                list.map(function(piece){
                    if (piece === '') {
                        return m('span');
                    }
                    var startsWith = piece.substring(0,2);
                    if(startsWith === '${'){
                        var last = piece.length-1;
                        var logComponentName = piece.substring(2,last);
                        if(LogPieces[logComponentName]){
                            return m.component(LogPieces[logComponentName], logObject);
                        } else {
                            message = 'There is no template in logTextParser.js for  ' + logComponentName + '.';
                            ravenMessage(message, logObject);
                            return m('');
                        }
                    }
                    return piece;
                })
            ]);
        } else {
            message = 'There is no text entry in dictionary for the action :' + logObject.attributes.action;
            ravenMessage(message, logObject);
            return m('');
        }
    }
};

var LogPieces = {
    // User that took the action
    user: {
        view: function (ctrl, logObject) {
            var userObject = logObject.embeds.user;
            if(paramIsReturned(userObject, logObject) && userObject.data) {
                return m('a', {href: userObject.data.links.html, onclick: function() {
                    $osf.trackClick(logObject.trackingCategory, logObject.trackingAction, 'navigate-to-user-from-logs');
                }}, userObject.data.attributes.full_name);
            }
            else if (userObject && userObject.errors[0].meta) {
                return m('span', userObject.errors[0].meta.full_name);
            }
            else {
                return m('span', 'A user');
            }
        }
    },
    // Node involved
    node: {
        view: function (ctrl, logObject) {
            var nodeObject = logObject.embeds.nodes;

            if (logObject.attributes.action === 'node_removed') {
                if (logObject.attributes.params.params_node) {
                return m('span', logObject.attributes.params.params_node.title);
            }}
            else if(paramIsReturned(nodeObject, logObject) && nodeObject.data[0]){
                if (nodeObject.data[0].links && nodeObject.data[0].attributes) {
                    return m('a', {href: nodeObject.data[0].links.html, onclick: function() {
                        $osf.trackClick(logObject.trackingCategory, logObject.trackingAction, 'navigate-to-project-from-logs');
                    }}, nodeObject.data[0].attributes.title);
                }
                else if (nodeObject.data[0].attributes) {
                    return m('span', nodeObject.data[0].attributes.title);
                }
            } else {
                return m('span', 'a project');
            }
        }
    },
    // Contrubutor list of added, updated etc.
    contributors: {
        view: function (ctrl, logObject) {
            var contributors = logObject.embeds.contributors;
            if(paramIsReturned(contributors, logObject)) {
                return m('span', contributors.data.map(function(item, index, arr){
                    var comma = ' ';
                    if(index !== arr.length - 1){
                        comma = ', ';
                    }
                    if(index === arr.length-2){
                        comma = ' and ';
                    }
                    if (item.attributes.active) {
                        return [ m('a', {href: item.links.html}, item.attributes.full_name), comma];
                    }
                    else {
                        return [item.attributes.full_name, comma];

                    }
                }));
            }
            return m('span', 'some users');
        }
    },
    // The tag added to item involved
    tag: {
        view: function (ctrl, logObject) {
            var tag = logObject.attributes.params.tag;
            if(paramIsReturned(tag, logObject)) {
               return m('a', {href: '/search/?q=%22' + tag + '%22'}, tag);
            }
            return m('span', 'a tag');
       }
    },
    // Node that is linked to the node involved
    pointer: {
        view: function (ctrl, logObject) {
            var linked_node = logObject.embeds.linked_node;
            if(paramIsReturned(linked_node, logObject)){
                return m('a', {href: linked_node.data.links.html}, linked_node.data.attributes.title);
            }
            return m('span','a project' );
        }
    },
    // Node that acted as template to create a new node involved
    template: {
        view: function (ctrl, logObject) {
            var template_node = logObject.embeds.template_node;
            if(paramIsReturned(template_node, logObject)){
                return m('a', {href: template_node.data.links.html}, template_node.data.attributes.title);
            }
            return m('span','a project' );
        }
    },
    // The original title of node involved
    title_original: {
        view: function (ctrl, logObject) {
            return returnTextParams('title_original', 'a title', logObject);
        }
    },
    // The new title of node involved
    title_new: {
        view: function (ctrl, logObject) {
            return returnTextParams('title_new', 'a title', logObject);
        }
    },
    // Update fields for the node
    updated_fields: {
        view: function (ctrl, logObject) {
            return returnTextParams('updated_fields', 'field(s)', logObject);
        }
    },
    // external identifiers on node
    identifiers: {
        view: function (ctrl, logObject) {
            return returnTextParams('identifiers', 'identifier(s)', logObject);
        }
    },
    // Wiki page name
    page: {
        view: function (ctrl, logObject) {
            return returnTextParams('page', 'a title', logObject);
        }
    },
    // Old wiki title that's renamed
    old_page: {
        view: function (ctrl, logObject) {
            return returnTextParams('old_page', 'a title', logObject);
        }
    },
    // Wiki page version
    version: {
        view: function (ctrl, logObject) {
            var version = logObject.attributes.params.version;
            if(paramIsReturned(version, logObject)){
                return m('span', version);
            }
            return m('span', '#');
        }
    },
    //
    source: {
        view: function (ctrl, logObject) {
            var source = logObject.attributes.params.source;
            if(paramIsReturned(source, logObject)){
                return m('span', [source.materialized, ' in ', source.addon]);
            }
            return m('span','a name/location' );
        }
    },
    //
    destination: {
        view: function (ctrl, logObject) {
            var destination = logObject.attributes.params.destination;
            if(paramIsReturned(destination, logObject)){
                if (destination.materialized.endsWith('/')){
                    return m('span', [destination.materialized, ' in ', destination.addon]);
                }
                return m('span', [m('a', {href: destination.url}, destination.materialized), ' in ', destination.addon]);
            }
            return m('span','a new name/location' );
        }
    },
        //
    path: {
        controller: function(logObject){
            var self = this;
            self.returnLinkForPath = function() {
                if (logObject) {
                    var action = logObject.attributes.action;
                    var acceptableLinkedItems = ['osf_storage_file_added', 'osf_storage_file_updated'];
                    if (acceptableLinkedItems.indexOf(action) !== -1) {
                        return logObject.attributes.params.view_url;
                    }
                }
                return null;
            };
        },
        view: function (ctrl, logObject) {
            var url = ctrl.returnLinkForPath();
            return returnTextParams('path', 'a file', logObject, url);
        }
    },
        //
    filename: {
        view: function (ctrl, logObject) {
            return returnTextParams('filename', 'a title', logObject);
        }
    },

    folder: {
        view: function(ctrl, logObject) {
            return returnTextParams('folder', 'a folder', logObject);
        }
    },

    repo: {
        view: function(ctrl, logObject) {
            var github_user = logObject.attributes.params.github_user;
            var github_repo = logObject.attributes.params.github_repo;
            if (paramIsReturned(github_repo, logObject) && paramIsReturned(github_user, logObject)){
                return m('span', github_user + '/' + github_repo);
            }
            return m('span', '');
        }
    },

    folder_name: {
        view: function(ctrl, logObject) {
            return returnTextParams('folder_name', 'a folder', logObject);
        }
    },

    bucket: {
        view: function(ctrl, logObject) {
            return returnTextParams('bucket', 'a bucket', logObject);
        }
    },

    forward_url: {
        view: function(ctrl, logObject) {
            var url = logObject.attributes.params.forward_url;
            return returnTextParams('forward_url', 'a new URL', logObject, url);
        }
    },

    box_folder: {
        view: function(ctrl, logObject) {
            var folder = logObject.attributes.params.folder;
            if(paramIsReturned(folder, logObject)){
                return m('span', folder === 'All Files' ? '/ (Full Box)' : (folder || '').replace('All Files',''));
            }
            return m('span', '');
        }
    },

    citation: {
        view: function(ctrl, logObject) {
            return returnTextParams('citation_name', '', logObject);
        }
    },

    dataset: {
        view: function(ctrl, logObject){
            return returnTextParams('data_set', '', logObject);
        }
    },

    study: {
        view: function(ctrl, logObject){
            return returnTextParams('study', '', logObject);
        }
    },

    googledrive_path: {
        view: function(ctrl, logObject){
            var path = logObject.attributes.params.path;
            if(paramIsReturned(path, logObject)){
                return m('span', decodeURIComponent(path));
            }
            return m('span', '');
        }
    },

    googledrive_folder: {
        view: function(ctrl, logObject){
            var folder = logObject.attributes.params.folder;
            if(paramIsReturned(folder, logObject)){
                return m('span', folder === '/' ? '(Full Google Drive)' : decodeURIComponent(folder));
            }
            return m('span', '');
        }
    },

    addon: {
        view: function(ctrl, logObject){
            return returnTextParams('addon', '', logObject);
        }
    },

    previous_institution: {
        view: function(ctrl, logObject){
            var previous_institution = logObject.attributes.params.previous_institution;
            if (paramIsReturned(previous_institution, logObject)){
                return m('span', previous_institution.name);
            }
            return m('span', 'an institution');
        }
    },

    institution: {
        view: function(ctrl, logObject){
            var institution = logObject.attributes.params.institution;
            if (paramIsReturned(institution, logObject)){
                return m('span', institution.name);
            }
            return m('span', 'an institution');
        }
    },

    comment_file: {
        view: function(ctrl,logObject){
            var file = logObject.attributes.params.file;
            if (file){  // skipe paramIsReturned, as not having a file is expected at times
                return m('span', ['in ', m('a', {href: file.url}, file.name)]);
            }
            return m('span', '');
        }
    }
};

module.exports = LogText;
<|endoftext|>


<commit_before>
function newPromise() {
  let savedResolve, savedReject;
  let promise = new Promise((resolve, reject) => {
    savedResolve = resolve;
    savedReject = reject;
  });
  return [promise, savedResolve, savedReject];
}

class NormalRequester {
  constructor(serverUrl) {
    assert(serverUrl);
    this.serverUrl = serverUrl;
    this.headers = {};
    this.openRequests = [];
    this.nextRequestId = 1;
  }
  setHeaders(headers) {
    this.headers = headers;
  }
  sendRequest_(verb, path, urlParams, body) {
    const requestId = this.nextRequestId++;
    let [promise, resolve, reject] = newPromise();
    var request = new XMLHttpRequest();
    request.onreadystatechange = function() {
      if (request.readyState == XMLHttpRequest.DONE ) {
        if (request.status == 200) {
          var result = JSON.parse(request.responseText);
          resolve(result);
        } else {
          reject('Error ' + request.status + ' ' + request.statusText);
        }
      }
    };

    var urlParamsStr = "";
    for (var key in urlParams) {
      urlParamsStr +=
          (urlParamsStr && "&") +
          key + "=" + encodeURIComponent(urlParams[key]);
    }
    let url = this.serverUrl + path + (urlParamsStr && "?" + urlParamsStr);
    request.open(verb, url, true);
    for (var key in this.headers) {
      request.setRequestHeader(key, this.headers[key]);
    }
    this.openRequests.push({
      request: request,
      resolve: resolve,
      reject: reject,
      promise: promise,
    });
    if (body) {
      request.send(JSON.stringify(body));
    } else {
      request.send();
    }
    return promise;
  }
  sendGetRequest(path, urlParams) {
    return this.sendRequest_('GET', path, urlParams, null);
  }
  sendPutRequest(path, urlParams, body) {
    return this.sendRequest_('PUT', path, urlParams, body);
  }
  sendPostRequest(path, urlParams, body) {
    return this.sendRequest_('POST', path, urlParams, body);
  }
}
<commit_msg>added token to all requests<commit_after>
function newPromise() {
  let savedResolve, savedReject;
  let promise = new Promise((resolve, reject) => {
    savedResolve = resolve;
    savedReject = reject;
  });
  return [promise, savedResolve, savedReject];
}

class NormalRequester {
  constructor(serverUrl) {
    assert(serverUrl);
    this.serverUrl = serverUrl;
    this.headers = {};
    this.openRequests = [];
    this.nextRequestId = 1;
  }
  setHeaders(headers) {
    this.headers = headers;
  }
  sendRequest_(verb, path, urlParams, body) {
    const requestId = this.nextRequestId++;
    let [promise, resolve, reject] = newPromise();
    var request = new XMLHttpRequest();
    request.onreadystatechange = function() {
      if (request.readyState == XMLHttpRequest.DONE ) {
        if (request.status == 200) {
          var result = JSON.parse(request.responseText);
          resolve(result);
        } else {
          reject('Error ' + request.status + ' ' + request.statusText);
        }
      }
    };

    this.openRequests.push({
      request: request,
      resolve: resolve,
      reject: reject,
      promise: promise,
    });

    firebase.auth().currentUser.getToken(false).then((userToken) => {
      urlParams = urlParams || {};
      urlParams.userToken = userToken;
      var urlParamsStr = "";
      for (var key in urlParams) {
        urlParamsStr +=
            (urlParamsStr && "&") +
            key + "=" + encodeURIComponent(urlParams[key]);
      }
      let url = this.serverUrl + path + (urlParamsStr && "?" + urlParamsStr);
      request.open(verb, url, true);
      for (var key in this.headers) {
        request.setRequestHeader(key, this.headers[key]);
      }
      if (body) {
        request.send(JSON.stringify(body));
      } else {
        request.send();
      }
    });

    return promise;
  }
  sendGetRequest(path, urlParams) {
    return this.sendRequest_('GET', path, urlParams, null);
  }
  sendPutRequest(path, urlParams, body) {
    return this.sendRequest_('PUT', path, urlParams, body);
  }
  sendPostRequest(path, urlParams, body) {
    return this.sendRequest_('POST', path, urlParams, body);
  }
}
<|endoftext|>


<commit_before>'use strict';

const returnSamePicture = require('./return-same-picture');

const pad = require('./pad');

const remove = require('./remove');

const path = require('./path');

const buffer = require('./buffer');

const hash = require('./hash');

const read = require('./read');
const write = require('./write');
const resize = require('./resize');

const globalHooks = require('../../../hooks');
const hooks = require('feathers-hooks');
const auth = require('feathers-authentication').hooks;
const errors = require('feathers-errors');

const model = require('../picture-model');

exports.before = {
    all: [
        auth.verifyToken(),
        auth.populateUser(),
        auth.restrictToAuthenticated()
    ],
    find: [],
    get: [],
    create: [
        hooks.disable('external'),
        globalHooks.required({ model: model }),
        globalHooks.validate({ model: model }),
        buffer(),
        hash(),
        returnSamePicture(),
        pad(hook => !hook.result && hook.data.type === 'icon'),
        resize(160, hook => !hook.result && hook.data.type === 'icon'),
        // resize(800, hook => !hook.data.type || hook.data.type === 'full'),
        path(),
        write(),
        hooks.pluck('_id', 'path', 'type', 'mimetype'),
        auth.associateCurrentUser(),
        globalHooks.createdAt()
    ],
    update: [hooks.disable()],
    patch: [hooks.disable()],
    remove: [
        // Disallow globally deleting pictures externally
        hooks.disable('external', hook => !hook.id),
        auth.restrictToRoles({
            roles: [ 'admin', 'host' ],
            fieldName: 'roles',
            ownerField: 'userId',
            owner: true
        })
    ]
};

exports.after = {
    all: [],
    find: [
        read(),
        hooks.remove('path')
    ],
    get: [
        read(),
        hooks.remove('path')
    ],
    create: [
        read(),
        hooks.remove('path')
    ],
    update: [],
    patch: [],
    remove: [
        read(),
        remove(),
        hooks.remove('path')
    ]
};
<commit_msg>Cleaned up excess newlines.<commit_after>'use strict';

const returnSamePicture = require('./return-same-picture');
const pad = require('./pad');
const remove = require('./remove');
const path = require('./path');
const buffer = require('./buffer');
const hash = require('./hash');
const read = require('./read');
const write = require('./write');
const resize = require('./resize');

const globalHooks = require('../../../hooks');
const hooks = require('feathers-hooks');
const auth = require('feathers-authentication').hooks;
const errors = require('feathers-errors');

const model = require('../picture-model');

exports.before = {
    all: [
        auth.verifyToken(),
        auth.populateUser(),
        auth.restrictToAuthenticated()
    ],
    find: [],
    get: [],
    create: [
        hooks.disable('external'),
        globalHooks.required({ model: model }),
        globalHooks.validate({ model: model }),
        buffer(),
        hash(),
        returnSamePicture(),
        pad(hook => !hook.result && hook.data.type === 'icon'),
        resize(160, hook => !hook.result && hook.data.type === 'icon'),
        // resize(800, hook => !hook.data.type || hook.data.type === 'full'),
        path(),
        write(),
        hooks.pluck('_id', 'path', 'type', 'mimetype'),
        auth.associateCurrentUser(),
        globalHooks.createdAt()
    ],
    update: [hooks.disable()],
    patch: [hooks.disable()],
    remove: [
        // Disallow globally deleting pictures externally
        hooks.disable('external', hook => !hook.id),
        auth.restrictToRoles({
            roles: [ 'admin', 'host' ],
            fieldName: 'roles',
            ownerField: 'userId',
            owner: true
        })
    ]
};

exports.after = {
    all: [],
    find: [
        read(),
        hooks.remove('path')
    ],
    get: [
        read(),
        hooks.remove('path')
    ],
    create: [
        read(),
        hooks.remove('path')
    ],
    update: [],
    patch: [],
    remove: [
        read(),
        remove(),
        hooks.remove('path')
    ]
};
<|endoftext|>


<commit_before>import React, {Component, PropTypes} from "react";
import { Link } from "react-router";
import classNames from "classnames";
import debounce from "lodash.debounce";
import { DragDropContext } from "react-dnd";
import HTML5Backend from "react-dnd-html5-backend";

import Icon from "../components/Icon";
import {
  HouseSVGIcon,
  ArrowDownSVGIcon,
  ArrowRightSVGIcon ,
  ListSVGIcon,
  PlusSVGIcon
} from "../components/SVGIcon";

import Badge from "../components/Badge";
import Button from "../components/Button";
import Category from "../components/Category";
import Feed from "../components/Feed";
import imageProfile from "../../assets/images/profile.jpg";

import { bindHotKey, unbindHotKey } from "../utils/HotKeys";

class Sidebar extends Component {

  static propTypes = {
    feeds: PropTypes.array.isRequired,
    categories: PropTypes.array.isRequired,
    currentPathname: PropTypes.string.isRequired,
    currentUser: PropTypes.object.isRequired,
    onAddClick: PropTypes.func.isRequired,
    onSignOutClick: PropTypes.func.isRequired,
    onNextClick: PropTypes.func.isRequired,
    onPreviousClick: PropTypes.func.isRequired,
    onCategoryExpandClick: PropTypes.func.isRequired,
    onAddCategoryClick: PropTypes.func.isRequired,
    onFeedDrop: PropTypes.func.isRequired
  };

  constructor(props) {
    super(props);

    this.onNextClick = debounce(this.onNextClick.bind(this), 100);
    this.onPreviousClick = debounce(this.onPreviousClick.bind(this), 100);
    this.onAddClick = this.onAddClick.bind(this);
  }

  renderFeed(feed) {
    const { currentPathname, onFeedDrop } = this.props;
    const path = `/feeds/${feed.id}`;
    const active = path === currentPathname;

    const cls = classNames({ "sidebar-nav-list__name": true, active: active });
    const listItemCls = classNames({ active: active, "sidebar-nav-list__item": true });

    return (
      <Feed className={listItemCls} {...feed} active={active} onDrop={onFeedDrop}>

          <Link to={path} className={cls} title={feed.title}>{feed.title}</Link>
          {feed.unread_count > 0 &&
            <Badge count={feed.unread_count} className="sidebar-nav-list__badge"/>
          }

      </Feed>
    );
  }

  renderLink(label, path, iconName) {
    const { currentPathname } = this.props;
    const key = path;
    const active = path === currentPathname;

    const cls = classNames({ "sidebar-nav-list__name": true, active: active });
    const listItemCls = classNames({ active: active, "sidebar-nav-list__item": true });
    const currentColor = active ? "white" : "gray";

    return (

          {React.createElement(iconName, { color: currentColor })}
          <Icon name={iconName} size="small"/>
          <Link to={path} className={cls}>{label}</Link>

    );
  }

  renderCategory(category, feeds) {
    const { currentPathname, onCategoryExpandClick } = this.props;
    const path = `/categories/${category.id}`;
    const active = path === currentPathname;
    const matchingFeeds = feeds.filter((feed) => feed.category_id === category.id);
    const totalUnreadCount = matchingFeeds.reduce((result, feed) => {
      return result + feed.unread_count;
    }, 0);

    const cls = classNames({ "sidebar-nav-list__name": true, active: active });
    const listItemCls = classNames({ active: active, "sidebar-nav-list__item": true });
    const currentColor = active ? "white" : "gray";

    return (
      <Category className={listItemCls} {...category} active={active}>

            {category.expanded && <ArrowDownSVGIcon color={currentColor}/>}
            {!category.expanded && <ArrowRightSVGIcon color={currentColor}/>}

         <Link to={path} className={cls} title={category.title}>{category.title}</Link>
         {totalUnreadCount > 0 &&
           <Badge count={totalUnreadCount} className="sidebar-nav-list__badge"/>
         }

        {matchingFeeds.length > 0 && category.expanded &&

            {matchingFeeds.map((feed) => {
              return this.renderFeed(feed);
            })}

        }
      </Category>
    );
  }

  renderAddCategoryLink() {
    return (

          <PlusSVGIcon color="gray"/>
          Category

    );
  }

  componentDidUpdate() {
    const { currentPathname, feeds } = this.props;

    this.paths = ["/today", "/all"];
    this.paths = [...this.paths, ...feeds.map((feed) => `/feeds/${feed.id}`)];
    this.currentPathIndex = this.paths.indexOf(currentPathname);
  }

  componentDidMount() {
    bindHotKey("nextFeed", () => this.onNextClick());
    bindHotKey("previousFeed", () => this.onPreviousClick());
  }

  componentWillUnmount() {
    unbindHotKey("nextFeed");
    unbindHotKey("previousFeed");
  }

  onNextClick() {
    if (this.currentPathIndex+1 < this.paths.length) {
      const path = this.paths[this.currentPathIndex+1];
      this.props.onNextClick(path);
    }
  }

  onPreviousClick() {
    if (this.currentPathIndex-1 >= 0) {
      const path = this.paths[this.currentPathIndex-1];
      this.props.onPreviousClick(path);
    }
  }

  onAddClick(e) {
    e.preventDefault();
    this.props.onAddClick();
  }

  render() {
    const { feeds, categories, currentUser, onSignOutClick } = this.props;
    const feedsWithoutCategory = feeds.filter((feed) => !feed.category_id);

    return (

whistle'r

            <Button
              onClick={this.onAddClick}
              type="primary"
              expand={true}>+ Subscriptions</Button>

          {/*
Home
*/}

            {this.renderLink("Today", "/today", HouseSVGIcon)}
            {this.renderLink("All", "/all", ListSVGIcon)}

          {/*

            Subscriptions

*/}

            {categories.map((category) => {
              return this.renderCategory(category, feeds);
            })}
            {feedsWithoutCategory.map((feed) => {
              return this.renderFeed(feed);
            })}
            {this.renderAddCategoryLink()}

{currentUser.first_name} {currentUser.last_name}

            Logout

    );
  }
}

export default DragDropContext(HTML5Backend)(Sidebar);
<commit_msg>fix icon error for home/all<commit_after>import React, {Component, PropTypes} from "react";
import { Link } from "react-router";
import classNames from "classnames";
import debounce from "lodash.debounce";
import { DragDropContext } from "react-dnd";
import HTML5Backend from "react-dnd-html5-backend";

import Icon from "../components/Icon";
import {
  HouseSVGIcon,
  ArrowDownSVGIcon,
  ArrowRightSVGIcon ,
  ListSVGIcon,
  PlusSVGIcon
} from "../components/SVGIcon";

import Badge from "../components/Badge";
import Button from "../components/Button";
import Category from "../components/Category";
import Feed from "../components/Feed";
import imageProfile from "../../assets/images/profile.jpg";

import { bindHotKey, unbindHotKey } from "../utils/HotKeys";

class Sidebar extends Component {

  static propTypes = {
    feeds: PropTypes.array.isRequired,
    categories: PropTypes.array.isRequired,
    currentPathname: PropTypes.string.isRequired,
    currentUser: PropTypes.object.isRequired,
    onAddClick: PropTypes.func.isRequired,
    onSignOutClick: PropTypes.func.isRequired,
    onNextClick: PropTypes.func.isRequired,
    onPreviousClick: PropTypes.func.isRequired,
    onCategoryExpandClick: PropTypes.func.isRequired,
    onAddCategoryClick: PropTypes.func.isRequired,
    onFeedDrop: PropTypes.func.isRequired
  };

  constructor(props) {
    super(props);

    this.onNextClick = debounce(this.onNextClick.bind(this), 100);
    this.onPreviousClick = debounce(this.onPreviousClick.bind(this), 100);
    this.onAddClick = this.onAddClick.bind(this);
  }

  renderFeed(feed) {
    const { currentPathname, onFeedDrop } = this.props;
    const path = `/feeds/${feed.id}`;
    const active = path === currentPathname;

    const cls = classNames({ "sidebar-nav-list__name": true, active: active });
    const listItemCls = classNames({ active: active, "sidebar-nav-list__item": true });

    return (
      <Feed className={listItemCls} {...feed} active={active} onDrop={onFeedDrop}>

          <Link to={path} className={cls} title={feed.title}>{feed.title}</Link>
          {feed.unread_count > 0 &&
            <Badge count={feed.unread_count} className="sidebar-nav-list__badge"/>
          }

      </Feed>
    );
  }

  renderLink(label, path, iconName) {
    const { currentPathname } = this.props;
    const key = path;
    const active = path === currentPathname;

    const cls = classNames({ "sidebar-nav-list__name": true, active: active });
    const listItemCls = classNames({ active: active, "sidebar-nav-list__item": true });
    const currentColor = active ? "white" : "gray";

    return (

          {React.createElement(iconName, { color: currentColor })}
          <Link to={path} className={cls}>{label}</Link>

    );
  }

  renderCategory(category, feeds) {
    const { currentPathname, onCategoryExpandClick } = this.props;
    const path = `/categories/${category.id}`;
    const active = path === currentPathname;
    const matchingFeeds = feeds.filter((feed) => feed.category_id === category.id);
    const totalUnreadCount = matchingFeeds.reduce((result, feed) => {
      return result + feed.unread_count;
    }, 0);

    const cls = classNames({ "sidebar-nav-list__name": true, active: active });
    const listItemCls = classNames({ active: active, "sidebar-nav-list__item": true });
    const currentColor = active ? "white" : "gray";

    return (
      <Category className={listItemCls} {...category} active={active}>

            {category.expanded && <ArrowDownSVGIcon color={currentColor}/>}
            {!category.expanded && <ArrowRightSVGIcon color={currentColor}/>}

         <Link to={path} className={cls} title={category.title}>{category.title}</Link>
         {totalUnreadCount > 0 &&
           <Badge count={totalUnreadCount} className="sidebar-nav-list__badge"/>
         }

        {matchingFeeds.length > 0 && category.expanded &&

            {matchingFeeds.map((feed) => {
              return this.renderFeed(feed);
            })}

        }
      </Category>
    );
  }

  renderAddCategoryLink() {
    return (

          <PlusSVGIcon color="gray"/>
          Category

    );
  }

  componentDidUpdate() {
    const { currentPathname, feeds } = this.props;

    this.paths = ["/today", "/all"];
    this.paths = [...this.paths, ...feeds.map((feed) => `/feeds/${feed.id}`)];
    this.currentPathIndex = this.paths.indexOf(currentPathname);
  }

  componentDidMount() {
    bindHotKey("nextFeed", () => this.onNextClick());
    bindHotKey("previousFeed", () => this.onPreviousClick());
  }

  componentWillUnmount() {
    unbindHotKey("nextFeed");
    unbindHotKey("previousFeed");
  }

  onNextClick() {
    if (this.currentPathIndex+1 < this.paths.length) {
      const path = this.paths[this.currentPathIndex+1];
      this.props.onNextClick(path);
    }
  }

  onPreviousClick() {
    if (this.currentPathIndex-1 >= 0) {
      const path = this.paths[this.currentPathIndex-1];
      this.props.onPreviousClick(path);
    }
  }

  onAddClick(e) {
    e.preventDefault();
    this.props.onAddClick();
  }

  render() {
    const { feeds, categories, currentUser, onSignOutClick } = this.props;
    const feedsWithoutCategory = feeds.filter((feed) => !feed.category_id);

    return (

whistle'r

            <Button
              onClick={this.onAddClick}
              type="primary"
              expand={true}>+ Subscriptions</Button>

          {/*
Home
*/}

            {this.renderLink("Today", "/today", HouseSVGIcon)}
            {this.renderLink("All", "/all", ListSVGIcon)}

          {/*

            Subscriptions

*/}

            {categories.map((category) => {
              return this.renderCategory(category, feeds);
            })}
            {feedsWithoutCategory.map((feed) => {
              return this.renderFeed(feed);
            })}
            {this.renderAddCategoryLink()}

{currentUser.first_name} {currentUser.last_name}

            Logout

    );
  }
}

export default DragDropContext(HTML5Backend)(Sidebar);
<|endoftext|>


<commit_before>/**
 * Created by Alex Bol on 3/7/2017.
 */
"use strict";

import Flatten from '../flatten';

/**
 * Class Box represent bounding box of the shape
 * @type {Box}
 */
export class Box {
    /**
     *
     * @param {number} xmin - minimal x coordinate
     * @param {number} ymin - minimal y coordinate
     * @param {number} xmax - maximal x coordinate
     * @param {number} ymax - maximal y coordinate
     */
    constructor(xmin = undefined, ymin = undefined, xmax = undefined, ymax = undefined) {
        /**
         * Minimal x coordinate
         * @type {number}
         */
        this.xmin = xmin;
        /**
         * Minimal y coordinate
         * @type {number}
         */
        this.ymin = ymin;
        /**
         * Maximal x coordinate
         * @type {number}
         */
        this.xmax = xmax;
        /**
         * Maximal y coordinate
         * @type {number}
         */
        this.ymax = ymax;
    }

    /**
     * Return new cloned instance of box
     * @returns {Box}
     */
    clone() {
        return new Box(this.xmin, this.ymin, this.xmax, this.ymax);
    }

    /**
     * Property low need for interval tree interface
     * @returns {Point}
     */
    get low() {
        return new Flatten.Point(this.xmin, this.ymin);
    }

    /**
     * Property high need for interval tree interface
     * @returns {Point}
     */
    get high() {
        return new Flatten.Point(this.xmax, this.ymax);
    }

    /**
     * Property max returns the box itself !
     * @returns {Box}
     */
    get max() {
        return this.clone();
    }

    /**
     * Return center of the box
     * @returns {Point}
     */
    get center() {
        return new Flatten.Point((this.xmin + this.xmax) / 2, (this.ymin + this.ymax) / 2);
    }

    /**
     * Return property box like all other shapes
     * @returns {Box}
     */
    get box() {
        return this.clone();
    }

    /**
     * Returns true if not intersected with other box
     * @param {Box} other_box - other box to test
     * @returns {boolean}
     */
    not_intersect(other_box) {
        return (
            this.xmax < other_box.xmin ||
            this.xmin > other_box.xmax ||
            this.ymax < other_box.ymin ||
            this.ymin > other_box.ymax
        );
    }

    /**
     * Returns true if intersected with other box
     * @param {Box} other_box - Query box
     * @returns {boolean}
     */
    intersect(other_box) {
        return !this.not_intersect(other_box);
    }

    /**
     * Returns new box merged with other box
     * @param {Box} other_box - Other box to merge with
     * @returns {Box}
     */
    merge(other_box) {
        return new Box(
            this.xmin === undefined ? other_box.xmin : Math.min(this.xmin, other_box.xmin),
            this.ymin === undefined ? other_box.ymin : Math.min(this.ymin, other_box.ymin),
            this.xmax === undefined ? other_box.xmax : Math.max(this.xmax, other_box.xmax),
            this.ymax === undefined ? other_box.ymax : Math.max(this.ymax, other_box.ymax)
        );
    }

    /**
     * Defines predicate "less than" between two boxes. Need for interval index
     * @param {Box} other_box - other box
     * @returns {boolean} - true if this box less than other box, false otherwise
     */
    less_than(other_box) {
        if (this.low.lessThan(other_box.low))
            return true;
        if (this.low.equalTo(other_box.low) && this.high.lessThan(other_box.high))
            return true;
        return false;
    }

    /**
     * Returns true if this box is equal to other box, false otherwise
     * @param {Box} other_box - query box
     * @returns {boolean}
     */
    equal_to(other_box) {
        return (this.low.equalTo(other_box.low) && this.high.equalTo(other_box.high));
    }

    output() {
        return this.clone();
    }

    static comparable_max(box1, box2) {
        // return pt1.lessThan(pt2) ? pt2.clone() : pt1.clone();
        return box1.merge(box2);
    }

    static comparable_less_than(pt1, pt2) {
        return pt1.lessThan(pt2);
    }

    /**
     * Set new values to the box object
     * @param {number} xmin - miminal x coordinate
     * @param {number} ymin - minimal y coordinate
     * @param {number} xmax - maximal x coordinate
     * @param {number} ymax - maximal y coordinate
     */
    set(xmin, ymin, xmax, ymax) {
        this.xmin = xmin;
        this.ymin = ymin;
        this.xmax = xmax;
        this.ymax = ymax;
    }

    /**
     * Transform box into array of points from low left corner in counter clockwise
     * @returns {Point[]}
     */
    toPoints() {
        return [
            new Flatten.Point(this.xmin, this.ymin),
            new Flatten.Point(this.xmax, this.ymin),
            new Flatten.Point(this.xmax, this.ymax),
            new Flatten.Point(this.xmin, this.ymax)
        ];
    }

    /**
     * Transform box into array of segments from low left corner in counter clockwise
     * @returns {Segment[]}
     */
    toSegments() {
        let pts = this.toPoints();
        return [
            new Flatten.Segment(pts[0], pts[1]),
            new Flatten.Segment(pts[1], pts[2]),
            new Flatten.Segment(pts[2], pts[3]),
            new Flatten.Segment(pts[3], pts[0])
        ];
    }

    /**
     * Return string to draw circle in svg
     * @param {Object} attrs - an object with attributes of svg rectangle element,
     * like "stroke", "strokeWidth", "fill"

     * Defaults are stroke:"black", strokeWidth:"1", fill:"none"
     * @returns {string}
     */
    svg(attrs = {}) {
        let {stroke, strokeWidth, fill, id, className} = attrs;
        // let rest_str = Object.keys(rest).reduce( (acc, key) => acc += ` ${key}="${rest[key]}"`, "");
        let id_str = (id && id.length > 0) ? `id="${id}"` : "";
        let class_str = (className && className.length > 0) ? `class="${className}"` : "";
        let width = this.xmax - this.xmin;
        let height = this.ymax - this.ymin;

        return `\n<rect x="${this.xmin}" y="${this.ymin}" width=${width} height=${height} stroke="${stroke || "black"}" stroke-width="${strokeWidth || 1}" fill="${fill || "none"}" ${id_str} ${class_str} />`;
    };
};

Flatten.Box = Box;
/**
 * Shortcut to create new circle
 * @param args
 * @returns {Box}
 */
export const box = (...args) => new Flatten.Box(...args);
Flatten.box = box;
<commit_msg>Fix box documentation<commit_after>/**
 * Created by Alex Bol on 3/7/2017.
 */
"use strict";

import Flatten from '../flatten';

/**
 * Class Box represent bounding box of the shape
 * @type {Box}
 */
export class Box {
    /**
     *
     * @param {number} xmin - minimal x coordinate
     * @param {number} ymin - minimal y coordinate
     * @param {number} xmax - maximal x coordinate
     * @param {number} ymax - maximal y coordinate
     */
    constructor(xmin = undefined, ymin = undefined, xmax = undefined, ymax = undefined) {
        /**
         * Minimal x coordinate
         * @type {number}
         */
        this.xmin = xmin;
        /**
         * Minimal y coordinate
         * @type {number}
         */
        this.ymin = ymin;
        /**
         * Maximal x coordinate
         * @type {number}
         */
        this.xmax = xmax;
        /**
         * Maximal y coordinate
         * @type {number}
         */
        this.ymax = ymax;
    }

    /**
     * Return new cloned instance of box
     * @returns {Box}
     */
    clone() {
        return new Box(this.xmin, this.ymin, this.xmax, this.ymax);
    }

    /**
     * Property low need for interval tree interface
     * @returns {Point}
     */
    get low() {
        return new Flatten.Point(this.xmin, this.ymin);
    }

    /**
     * Property high need for interval tree interface
     * @returns {Point}
     */
    get high() {
        return new Flatten.Point(this.xmax, this.ymax);
    }

    /**
     * Property max returns the box itself !
     * @returns {Box}
     */
    get max() {
        return this.clone();
    }

    /**
     * Return center of the box
     * @returns {Point}
     */
    get center() {
        return new Flatten.Point((this.xmin + this.xmax) / 2, (this.ymin + this.ymax) / 2);
    }

    /**
     * Return property box like all other shapes
     * @returns {Box}
     */
    get box() {
        return this.clone();
    }

    /**
     * Returns true if not intersected with other box
     * @param {Box} other_box - other box to test
     * @returns {boolean}
     */
    not_intersect(other_box) {
        return (
            this.xmax < other_box.xmin ||
            this.xmin > other_box.xmax ||
            this.ymax < other_box.ymin ||
            this.ymin > other_box.ymax
        );
    }

    /**
     * Returns true if intersected with other box
     * @param {Box} other_box - Query box
     * @returns {boolean}
     */
    intersect(other_box) {
        return !this.not_intersect(other_box);
    }

    /**
     * Returns new box merged with other box
     * @param {Box} other_box - Other box to merge with
     * @returns {Box}
     */
    merge(other_box) {
        return new Box(
            this.xmin === undefined ? other_box.xmin : Math.min(this.xmin, other_box.xmin),
            this.ymin === undefined ? other_box.ymin : Math.min(this.ymin, other_box.ymin),
            this.xmax === undefined ? other_box.xmax : Math.max(this.xmax, other_box.xmax),
            this.ymax === undefined ? other_box.ymax : Math.max(this.ymax, other_box.ymax)
        );
    }

    /**
     * Defines predicate "less than" between two boxes. Need for interval index
     * @param {Box} other_box - other box
     * @returns {boolean} - true if this box less than other box, false otherwise
     */
    less_than(other_box) {
        if (this.low.lessThan(other_box.low))
            return true;
        if (this.low.equalTo(other_box.low) && this.high.lessThan(other_box.high))
            return true;
        return false;
    }

    /**
     * Returns true if this box is equal to other box, false otherwise
     * @param {Box} other_box - query box
     * @returns {boolean}
     */
    equal_to(other_box) {
        return (this.low.equalTo(other_box.low) && this.high.equalTo(other_box.high));
    }

    output() {
        return this.clone();
    }

    static comparable_max(box1, box2) {
        // return pt1.lessThan(pt2) ? pt2.clone() : pt1.clone();
        return box1.merge(box2);
    }

    static comparable_less_than(pt1, pt2) {
        return pt1.lessThan(pt2);
    }

    /**
     * Set new values to the box object
     * @param {number} xmin - miminal x coordinate
     * @param {number} ymin - minimal y coordinate
     * @param {number} xmax - maximal x coordinate
     * @param {number} ymax - maximal y coordinate
     */
    set(xmin, ymin, xmax, ymax) {
        this.xmin = xmin;
        this.ymin = ymin;
        this.xmax = xmax;
        this.ymax = ymax;
    }

    /**
     * Transform box into array of points from low left corner in counter clockwise
     * @returns {Point[]}
     */
    toPoints() {
        return [
            new Flatten.Point(this.xmin, this.ymin),
            new Flatten.Point(this.xmax, this.ymin),
            new Flatten.Point(this.xmax, this.ymax),
            new Flatten.Point(this.xmin, this.ymax)
        ];
    }

    /**
     * Transform box into array of segments from low left corner in counter clockwise
     * @returns {Segment[]}
     */
    toSegments() {
        let pts = this.toPoints();
        return [
            new Flatten.Segment(pts[0], pts[1]),
            new Flatten.Segment(pts[1], pts[2]),
            new Flatten.Segment(pts[2], pts[3]),
            new Flatten.Segment(pts[3], pts[0])
        ];
    }

    /**
     * Return string to draw circle in svg
     * @param {Object} attrs - an object with attributes of svg rectangle element,
     * like "stroke", "strokeWidth", "fill"

     * Defaults are stroke:"black", strokeWidth:"1", fill:"none"
     * @returns {string}
     */
    svg(attrs = {}) {
        let {stroke, strokeWidth, fill, id, className} = attrs;
        // let rest_str = Object.keys(rest).reduce( (acc, key) => acc += ` ${key}="${rest[key]}"`, "");
        let id_str = (id && id.length > 0) ? `id="${id}"` : "";
        let class_str = (className && className.length > 0) ? `class="${className}"` : "";
        let width = this.xmax - this.xmin;
        let height = this.ymax - this.ymin;

        return `\n<rect x="${this.xmin}" y="${this.ymin}" width=${width} height=${height} stroke="${stroke || "black"}" stroke-width="${strokeWidth || 1}" fill="${fill || "none"}" ${id_str} ${class_str} />`;
    };
};

Flatten.Box = Box;
/**
 * Shortcut to create new box
 * @param args
 * @returns {Box}
 */
export const box = (...args) => new Flatten.Box(...args);
Flatten.box = box;
<|endoftext|>