<commit_before>/*jslint nomen: true */
/*globals define: true */

define(function(require, exports, module) {
  'use strict';

  // Libs
  var $ = require('jquery');
  var _ = require('lib/lodash');
  var Backbone = require('backbone');

  // App
  var settings = require('settings');
  var api = require('api');

  // Models
  var Responses = require('models/responses');
  var Stats = require('models/stats');

  // Views
  var ResponseListView = require('views/responses/list');

  // Templates
  var template = require('text!templates/filters/filters.html');
  var questionFiltersTemplate = require('text!templates/filters/question-filters.html');
  var selectedFiltersTemplate = require('text!templates/filters/selected-filters.html');

  var ANSWER = 'response';
  var NOANSWER = 'no response';

  /**
   * Intended for shorter lists of responses (arbitrarily <25)
   * Doesn't include pagination, which isn't relevant in this case.
   * See responses/responses/ListView for a heavyweight implementation.
   */
  var FilterView = Backbone.View.extend({
    filters: {},

    template: _.template(template),
    questionFiltersTemplate: _.template(questionFiltersTemplate),
    selectedFiltersTemplate: _.template(selectedFiltersTemplate),

    events: {
      "click .question": "selectQuestion",
      "click .answer": "selectAnswer",
      "click .clear": "reset",
      "click .close": "close",

      "change #datefilter": "selectDate"
    },

    initialize: function(options) {
      _.bindAll(this, 'render', 'reset', 'updateSidebar');

      this.survey = options.survey;
      this.forms = options.forms;
      this.map = options.map;

      this.stats = new Stats.Model({
        id: this.survey.get('id')
      });
      this.stats.on('change', this.render);
      this.$el.html(this.template());

      $('.action-show-filters').click(function(event) {
      });
    },

    close: function() {
      console.log("Closing filters");
      this.$el.find('.filters').hide();
    },

    selectDate: function(event) {
      var HOUR_IN_MS = 1000*60*60;
      var val = $(event.target).val();
      var after = new Date();

      if (val === 'all') {
        this.map.setDate({});
        this.stats.initialize({
          id: this.survey.get('id')
        });

        return;
      }

      if (val === 'hour') {
        after = new Date(after.getTime() - HOUR_IN_MS);
      }

      if (val === 'today') {
        // The beginning of the day, not 24 hours ago.
        after = new Date(after.setHours(0,0,0,0));
      }

      if (val === 'week') {
        after = new Date(after.getTime() - (HOUR_IN_MS * 24 * 7));
      }

      // Set the date on the map, so the correct tiles are fetched.
      this.map.setDate({
        after: after.getTime()
      });

      // Reset the stats with the new parameters.
      this.stats.initialize({
        id: this.survey.get('id'),
        params: {
          after: after.getTime()
        }
      });

      // Update the sidebar
      this.filters.after = after;
      this.updateSidebar();
    },

    render: function() {
      console.log('Rendering the filters');

      this.$el.find('.question-filters').html('');

      // Match the question names and answer values from the form with stats and colors.
      var questions = this.forms.getFlattenedForm();
      var stats = this.stats;

      if (stats.has('reviewed')) {
        questions.reviewed = {
          text: 'Review status',
          answers: [{
            text: 'flagged',
            value: 'flagged'
          }, {
            text: 'accepted',
            value: 'accepted'
          }, {
            text: 'no response',
            value: 'no response'
          }]
        };
      }

      _.each(_.keys(questions), function (question) {
        var answerObjects = {};
        var questionStats = stats.get(question);
        var type = questions[question].type;
        if (type === 'text') {
          var total = _.reduce(questionStats, function (sum, count) {
            return sum + count;
          }, 0);

          var noResponseCount;
          if (questionStats) {
            noResponseCount = questionStats[NOANSWER];
          }
          if (noResponseCount === undefined) {
            noResponseCount = 0;
          }

          questions[question].answers = [{
            text: ANSWER,
            value: ANSWER,
            count: total - noResponseCount,
            color: settings.colorRange[1]
          }, {
            text: NOANSWER,
            value: NOANSWER,
            count: noResponseCount,
            color: settings.colorRange[0]
          }];
        } else if (type === 'file') {
          // TODO: We need to see photo upload numbers in the stats (or
          // somewhere) to report them in the UI.

          questions[question].answers = [{
            text: ANSWER,
            value: ANSWER,
            count: '',
            color: settings.colorRange[1]
          }, {
            text: NOANSWER,
            value: NOANSWER,
            count: '',
            color: settings.colorRange[0]
          }];
        } else {
          var answers = questions[question].answers;
          _.each(answers, function (answer, index) {
            if (!questionStats) {
              answer.count = 0;
            } else {
              // Get the count from the stats object.
              answer.count = questionStats[answer.value];
              if (answer.count === undefined) {
                answer.count = 0;
              }
            }

            // Get the color.
            // The last "answer" is the no-response placeholder, which gets the
            // zero-index color.
            answer.color = settings.colorRange[(index + 1) % answers.length];
          });
        }
      });

      var context = {
        questions: questions,
        mapping: this.forms.map()
      };

      this.$el.find('.question-filters').html(this.questionFiltersTemplate(context));

      // Re-mark any selected questions
      if(this.filters.question) {
        var $question = $('div[data-question=' + this.filters.question + ']');
        this.markQuestionSelected($question);
      }
      if(this.filters.answer) {
        var $answer = $('div[data-question=' + this.filters.question + '][data-answer='
            + this.filters.answer + ']');
        this.markAnswerSelected($answer);
      }

      return this;
    },

    /**
     * Associate a unqie color with each answer in a list
     */
    colors: function(keys) {
      var answers = {};
      _.each(keys, function(key, index) {
        answers[key] = {
          color: settings.colorRange[index + 1]
        };
      });
      return answers;
    },

    /**
     * Reset any filters
     */
    reset: function(event) {
      if(event) {
        event.preventDefault();
      }

      this.filters = {};
      this.map.clearFilter();

      $('.question').removeClass('selected');
      $('.answers .circle').removeClass('inactive');

      // Clear out the sidebar
      this.updateSidebar();
    },

    // TODO: indicate filter selection/clearing through an event; move the
    // rendering piece to the appropriate view.
    updateSidebar: function() {
      // Display the selected filter on the sidbar.
      console.log("Flattened form", this.forms.getFlattenedForm());
      var questions = this.forms.getFlattenedForm();

      if (!this.filters.question) {
        $('.selected-filters').html('');
        return;
      }

      var question =  questions[this.filters.question].text;
      var answer = '';
      if (this.filters.answer) {
        answer = _.findWhere(questions[this.filters.question].answers, { value: this.filters.answer }).text || '';
      }

      var selectedFilters = this.selectedFiltersTemplate({
        filters: {
          question: question,
          answer: answer
        }
      });
      $('.selected-filters').html(selectedFilters);
    },

    markQuestionSelected: function($question) {
      // Mark this filter as selected and show answers
      // First, clear out any selected questions
      console.log("Marking question selected", $question);
      $('.filters .question').removeClass('selected');

      // Then, add the selected class to this question
      $question.addClass('selected');

      this.updateSidebar();
    },

    markAnswerSelected: function($answer) {
      // Make sure we have the right question selected
      this.filters.question = $answer.attr('data-question');
      var $question = $('div.question[data-question=' + this.filters.question + ']');
      this.markQuestionSelected($question);

      if(!this.filters.answer) {
        // $answer = $answer.parent();
        this.filters.answer = $answer.attr('data-answer');
      }

      // Remove the "selected" class from any of the circles.
      $('.answers .circle').removeClass('selected');
      $('.answers .circle').addClass('inactive');

      // Mark the circle as selected
      $answer.find('.circle').addClass('selected');
      $answer.find('.circle').removeClass('inactive');

      // Color the responses on the map
      this.map.setFilter(this.filters.question, this.filters.answer);

      this.updateSidebar();

      console.log("Selected answer", $answer, this.filters.answer);
    },

    selectQuestion: function(event) {
      var $question = $(event.target);
      var question = $question.attr('data-question');
      if(!question) {
        $question = $question.parent();
        question = $question.attr('data-question');
      }

      // Don't double select the question.
      if (this.filters.question === question) {
        return;
      }

      // Clear out any existing filters
      if(this.filters.answer) {
        this.reset();
      }

      // Record the filter
      this.filters.question = question;
      var answers = this.stats.get(question);

      this.markQuestionSelected($question);

      // Color the responses on the map
      this.map.setFilter(question);
    },

    /**
     * Show only responses with a specific answer
     */
    selectAnswer: function(event) {
      var $answer = $(event.target);
      this.filters.answer = $answer.attr('data-answer');

      this.markAnswerSelected($answer);
    }
  });

  return FilterView;

});
<commit_msg>Avoid recomputing the flattened form For reviewed entries, we tweak the list of questions and need to avoid obliterating those tweaks by recomputing.<commit_after>/*jslint nomen: true */
/*globals define: true */

define(function(require, exports, module) {
  'use strict';

  // Libs
  var $ = require('jquery');
  var _ = require('lib/lodash');
  var Backbone = require('backbone');

  // App
  var settings = require('settings');

  // Models
  var Stats = require('models/stats');

  // Templates
  var template = require('text!templates/filters/filters.html');
  var questionFiltersTemplate = require('text!templates/filters/question-filters.html');
  var selectedFiltersTemplate = require('text!templates/filters/selected-filters.html');

  var ANSWER = 'response';
  var NOANSWER = 'no response';

  /**
   * Intended for shorter lists of responses (arbitrarily <25)
   * Doesn't include pagination, which isn't relevant in this case.
   * See responses/responses/ListView for a heavyweight implementation.
   */
  var FilterView = Backbone.View.extend({
    filters: {},

    template: _.template(template),
    questionFiltersTemplate: _.template(questionFiltersTemplate),
    selectedFiltersTemplate: _.template(selectedFiltersTemplate),

    events: {
      "click .question": "selectQuestion",
      "click .answer": "selectAnswer",
      "click .clear": "reset",
      "click .close": "close",

      "change #datefilter": "selectDate"
    },

    initialize: function(options) {
      _.bindAll(this, 'render', 'reset', 'updateSidebar');

      this.survey = options.survey;
      this.forms = options.forms;
      this.map = options.map;

      this.stats = new Stats.Model({
        id: this.survey.get('id')
      });
      this.stats.on('change', this.render);
      this.$el.html(this.template());

      $('.action-show-filters').click(function(event) {
      });
    },

    close: function() {
      console.log("Closing filters");
      this.$el.find('.filters').hide();
    },

    selectDate: function(event) {
      var HOUR_IN_MS = 1000*60*60;
      var val = $(event.target).val();
      var after = new Date();

      if (val === 'all') {
        this.map.setDate({});
        this.stats.initialize({
          id: this.survey.get('id')
        });

        return;
      }

      if (val === 'hour') {
        after = new Date(after.getTime() - HOUR_IN_MS);
      }

      if (val === 'today') {
        // The beginning of the day, not 24 hours ago.
        after = new Date(after.setHours(0,0,0,0));
      }

      if (val === 'week') {
        after = new Date(after.getTime() - (HOUR_IN_MS * 24 * 7));
      }

      // Set the date on the map, so the correct tiles are fetched.
      this.map.setDate({
        after: after.getTime()
      });

      // Reset the stats with the new parameters.
      this.stats.initialize({
        id: this.survey.get('id'),
        params: {
          after: after.getTime()
        }
      });

      // Update the sidebar
      this.filters.after = after;
      this.updateSidebar();
    },

    render: function() {
      console.log('Rendering the filters');

      this.$el.find('.question-filters').html('');

      // Match the question names and answer values from the form with stats and colors.
      this.questions = this.forms.getFlattenedForm();
      var questions = this.questions;
      var stats = this.stats;

      if (stats.has('reviewed')) {
        questions.reviewed = {
          text: 'Review status',
          answers: [{
            text: 'flagged',
            value: 'flagged'
          }, {
            text: 'accepted',
            value: 'accepted'
          }, {
            text: 'no response',
            value: 'no response'
          }]
        };
      }

      _.each(_.keys(questions), function (question) {
        var questionStats = stats.get(question);
        var type = questions[question].type;
        if (type === 'text') {
          var total = _.reduce(questionStats, function (sum, count) {
            return sum + count;
          }, 0);

          var noResponseCount;
          if (questionStats) {
            noResponseCount = questionStats[NOANSWER];
          }
          if (noResponseCount === undefined) {
            noResponseCount = 0;
          }

          questions[question].answers = [{
            text: ANSWER,
            value: ANSWER,
            count: total - noResponseCount,
            color: settings.colorRange[1]
          }, {
            text: NOANSWER,
            value: NOANSWER,
            count: noResponseCount,
            color: settings.colorRange[0]
          }];
        } else if (type === 'file') {
          // TODO: We need to see photo upload numbers in the stats (or
          // somewhere) to report them in the UI.

          questions[question].answers = [{
            text: ANSWER,
            value: ANSWER,
            count: '',
            color: settings.colorRange[1]
          }, {
            text: NOANSWER,
            value: NOANSWER,
            count: '',
            color: settings.colorRange[0]
          }];
        } else {
          var answers = questions[question].answers;
          _.each(answers, function (answer, index) {
            if (!questionStats) {
              answer.count = 0;
            } else {
              // Get the count from the stats object.
              answer.count = questionStats[answer.value];
              if (answer.count === undefined) {
                answer.count = 0;
              }
            }

            // Get the color.
            // The last "answer" is the no-response placeholder, which gets the
            // zero-index color.
            answer.color = settings.colorRange[(index + 1) % answers.length];
          });
        }
      });

      var context = {
        questions: questions,
        mapping: this.forms.map()
      };

      this.$el.find('.question-filters').html(this.questionFiltersTemplate(context));

      // Re-mark any selected questions
      if(this.filters.question) {
        // TODO: scope this search to less than the whole document
        var $question = $('div[data-question=' + this.filters.question + ']');
        this.markQuestionSelected($question);
      }
      if(this.filters.answer) {
        // TODO: scope this search to less than the whole document
        var $answer = $('div[data-question=' +
                        this.filters.question +
                        '][data-answer=' +
                        this.filters.answer + ']');
        this.markAnswerSelected($answer);
      }

      return this;
    },

    /**
     * Associate a unqie color with each answer in a list
     */
    colors: function(keys) {
      var answers = {};
      _.each(keys, function(key, index) {
        answers[key] = {
          color: settings.colorRange[index + 1]
        };
      });
      return answers;
    },

    /**
     * Reset any filters
     */
    reset: function(event) {
      if(event) {
        event.preventDefault();
      }

      this.filters = {};
      this.map.clearFilter();

      $('.question').removeClass('selected');
      $('.answers .circle').removeClass('inactive');

      // Clear out the sidebar
      this.updateSidebar();
    },

    // TODO: indicate filter selection/clearing through an event; move the
    // rendering piece to the appropriate view.
    updateSidebar: function() {
      // Display the selected filter on the sidbar.
      if (!this.filters.question) {
        $('.selected-filters').html('');
        return;
      }

      var question =  this.questions[this.filters.question].text;
      var answer = '';
      if (this.filters.answer) {
        answer = _.findWhere(this.questions[this.filters.question].answers, { value: this.filters.answer }).text || '';
      }

      var selectedFilters = this.selectedFiltersTemplate({
        filters: {
          question: question,
          answer: answer
        }
      });
      $('.selected-filters').html(selectedFilters);
    },

    markQuestionSelected: function($question) {
      // Mark this filter as selected and show answers
      // First, clear out any selected questions
      console.log("Marking question selected", $question);
      $('.filters .question').removeClass('selected');

      // Then, add the selected class to this question
      $question.addClass('selected');

      this.updateSidebar();
    },

    markAnswerSelected: function($answer) {
      // Make sure we have the right question selected
      this.filters.question = $answer.attr('data-question');
      var $question = $('div.question[data-question=' + this.filters.question + ']');
      this.markQuestionSelected($question);

      if(!this.filters.answer) {
        // $answer = $answer.parent();
        this.filters.answer = $answer.attr('data-answer');
      }

      // Remove the "selected" class from any of the circles.
      $('.answers .circle').removeClass('selected');
      $('.answers .circle').addClass('inactive');

      // Mark the circle as selected
      $answer.find('.circle').addClass('selected');
      $answer.find('.circle').removeClass('inactive');

      // Color the responses on the map
      this.map.setFilter(this.filters.question, this.filters.answer);

      this.updateSidebar();

      console.log("Selected answer", $answer, this.filters.answer);
    },

    selectQuestion: function(event) {
      var $question = $(event.target);
      var question = $question.attr('data-question');
      if(!question) {
        $question = $question.parent();
        question = $question.attr('data-question');
      }

      // Don't double select the question.
      if (this.filters.question === question) {
        return;
      }

      // Clear out any existing filters
      if(this.filters.answer) {
        this.reset();
      }

      // Record the filter
      this.filters.question = question;

      this.markQuestionSelected($question);

      // Color the responses on the map
      this.map.setFilter(question);
    },

    /**
     * Show only responses with a specific answer
     */
    selectAnswer: function(event) {
      var $answer = $(event.target);
      this.filters.answer = $answer.attr('data-answer');

      this.markAnswerSelected($answer);
    }
  });

  return FilterView;

});
<|endoftext|>


<commit_before>exports.level = {
  "compareOnlyMasterHashAgnostic": true,
  "disabledMap": {
    "git revert": true,
    "git cherry-pick": true
  },
  "goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C7%27%22%2C%22id%22%3A%22master%22%7D%2C%22bugFix%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22bugFix%22%7D%2C%22side%22%3A%7B%22target%22%3A%22C6%27%22%2C%22id%22%3A%22side%22%7D%2C%22another%22%3A%7B%22target%22%3A%22C7%27%22%2C%22id%22%3A%22another%22%7D%7D%2C%22commits%22%3A%7B%22C0%22%3A%7B%22parents%22%3A%5B%5D%2C%22id%22%3A%22C0%22%2C%22rootCommit%22%3Atrue%7D%2C%22C1%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%22%7D%2C%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C4%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C4%22%7D%2C%22C5%22%3A%7B%22parents%22%3A%5B%22C4%22%5D%2C%22id%22%3A%22C5%22%7D%2C%22C6%22%3A%7B%22parents%22%3A%5B%22C5%22%5D%2C%22id%22%3A%22C6%22%7D%2C%22C7%22%3A%7B%22parents%22%3A%5B%22C5%22%5D%2C%22id%22%3A%22C7%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%27%22%7D%2C%22C4%27%22%3A%7B%22parents%22%3A%5B%22C3%27%22%5D%2C%22id%22%3A%22C4%27%22%7D%2C%22C5%27%22%3A%7B%22parents%22%3A%5B%22C4%27%22%5D%2C%22id%22%3A%22C5%27%22%7D%2C%22C6%27%22%3A%7B%22parents%22%3A%5B%22C5%27%22%5D%2C%22id%22%3A%22C6%27%22%7D%2C%22C7%27%22%3A%7B%22parents%22%3A%5B%22C6%27%22%5D%2C%22id%22%3A%22C7%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D",
  "solutionCommand": "git checkout bugFix;git rebase master;git checkout side;git rebase bugFix;git checkout another;git rebase side;git rebase another master",
  "startTree": "{\"branches\":{\"master\":{\"target\":\"C2\",\"id\":\"master\"},\"bugFix\":{\"target\":\"C3\",\"id\":\"bugFix\"},\"side\":{\"target\":\"C6\",\"id\":\"side\"},\"another\":{\"target\":\"C7\",\"id\":\"another\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C0\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C4\"],\"id\":\"C5\"},\"C6\":{\"parents\":[\"C5\"],\"id\":\"C6\"},\"C7\":{\"parents\":[\"C5\"],\"id\":\"C7\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
  "name": {
    "en_US": "Rebasing over 9000 times",
    "ko": "9천번이 넘는 리베이스",
    "ja": "Rebasing over 9000 times",
    "zh_CN": "N次Rebase"
  },
  "hint": {
    "en_US": "Remember, the most efficient way might be to only update master at the end...",
    "ja": "最も効率的なやり方はmasterを最後に更新するだけかもしれない・・・",
    "ko": "아마도 master를 마지막에 업데이트하는 것이 가장 효율적인 방법일 것입니다...",
    "zh_CN": "记住，最后更新master分支可能是最高效的方法。"
  },
  "startDialog": {
    "en_US": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "### Rebasing Multiple Branches",
              "",
              "Man, we have a lot of branches going on here! Let's rebase all the work from these branches onto master.",
              "",
              "Upper management is making this a bit trickier though -- they want the commits to all be in sequential order. So this means that our final tree should have `C7'` at the bottom, `C6'` above that, etc etc, etc all in order.",
              "",
              "If you mess up along the way, feel free to use `reset` to start over again. Be sure to check out our solution and see if you can do it in fewer commands!"
            ]
          }
        }
      ]
    },
    "ja": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "### 複数のブランチをリベースする",
              "",
              "さあ、いくつものブランチが出てきます。このブランチたち全てをmasterブランチにリベースしましょう。",
              "",
              "おエライさん方が今回の仕事を少しトリッキーにしてくれました ― コミットはすべて一列のシーケンシャルな状態にしてほしいそうです。つまり私たちが作るリポジトリの最終的なツリーの状態は、`C7'`が最後に来て、`C6'`がその一つ上に来て、、と順に積み重なるイメージです。",
              "",
              "試行錯誤してツリーが汚くなってきたら、`reset`コマンドを使ってツリーの状態を初期化してください。模範解答をチェックして、それよりも簡単なコマンドで済ませられるかどうか、を考えるのも忘れずに！"
            ]
          }
        }
      ]
    },
    "zh_CN": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "### 多分支衍合",
              "",
              "呐，现在我们有很多分支啦！让我们rebase这些分支的工作到 master 分支上吧。",
              "",
              "但是你的头头找了点麻烦 —— 他们希望得到有序的提交历史，也就是我们最终的结果是 `C7'` 在最底部，`C6'` 在它上面，以此类推。",
              "",
              "假如你搞砸了，没所谓的（虽然我不会告诉你用 `reset` 可以重新开始）。记得看看我们提供的答案，看你能否使用更少的命令完成任务！"
            ]
          }
        }
      ]
    },
    "ko": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "### 여러 브랜치를 리베이스(rebase)하기 ",
              "",
              "음, 여기 꽤 여러개의 브랜치가 있습니다! 이 브랜치들의 모든 작업내역을 master에 리베이스 해볼까요?",
              "",
              "윗선에서 일을 복잡하게 만드네요 -- 그 분들이 이 모든 커밋들을 순서에 맞게 정렬하라고 합니다. 그럼 결국 우리의 최종 목표 트리는 제일 아래에 `C7'` 커밋, 그 위에 `C6'` 커밋, 또 그 위에 순서대로 보여합니다.",
              "",
              "만일 작업중에 내용이 꼬인다면, `reset`이라고 쳐서 처음부터 다시 시작할 수 있습니다. 모범 답안을 확인해 보시고, 혹시 더 적은 수의 커맨드로 해결할 수 있는지 알아보세요!"
            ]
          }
        }
      ]
    }
  }
};
<commit_msg>Update manyRebases.js<commit_after>exports.level = {
  "compareOnlyMasterHashAgnostic": true,
  "disabledMap": {
    "git revert": true,
    "git cherry-pick": true
  },
  "goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C7%27%22%2C%22id%22%3A%22master%22%7D%2C%22bugFix%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22bugFix%22%7D%2C%22side%22%3A%7B%22target%22%3A%22C6%27%22%2C%22id%22%3A%22side%22%7D%2C%22another%22%3A%7B%22target%22%3A%22C7%27%22%2C%22id%22%3A%22another%22%7D%7D%2C%22commits%22%3A%7B%22C0%22%3A%7B%22parents%22%3A%5B%5D%2C%22id%22%3A%22C0%22%2C%22rootCommit%22%3Atrue%7D%2C%22C1%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%22%7D%2C%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C4%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C4%22%7D%2C%22C5%22%3A%7B%22parents%22%3A%5B%22C4%22%5D%2C%22id%22%3A%22C5%22%7D%2C%22C6%22%3A%7B%22parents%22%3A%5B%22C5%22%5D%2C%22id%22%3A%22C6%22%7D%2C%22C7%22%3A%7B%22parents%22%3A%5B%22C5%22%5D%2C%22id%22%3A%22C7%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%27%22%7D%2C%22C4%27%22%3A%7B%22parents%22%3A%5B%22C3%27%22%5D%2C%22id%22%3A%22C4%27%22%7D%2C%22C5%27%22%3A%7B%22parents%22%3A%5B%22C4%27%22%5D%2C%22id%22%3A%22C5%27%22%7D%2C%22C6%27%22%3A%7B%22parents%22%3A%5B%22C5%27%22%5D%2C%22id%22%3A%22C6%27%22%7D%2C%22C7%27%22%3A%7B%22parents%22%3A%5B%22C6%27%22%5D%2C%22id%22%3A%22C7%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D",
  "solutionCommand": "git rebase master bugFix;git rebase bugFix side;git side another;git rebase another master",
  "startTree": "{\"branches\":{\"master\":{\"target\":\"C2\",\"id\":\"master\"},\"bugFix\":{\"target\":\"C3\",\"id\":\"bugFix\"},\"side\":{\"target\":\"C6\",\"id\":\"side\"},\"another\":{\"target\":\"C7\",\"id\":\"another\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C0\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C4\"],\"id\":\"C5\"},\"C6\":{\"parents\":[\"C5\"],\"id\":\"C6\"},\"C7\":{\"parents\":[\"C5\"],\"id\":\"C7\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
  "name": {
    "en_US": "Rebasing over 9000 times",
    "ko": "9천번이 넘는 리베이스",
    "ja": "Rebasing over 9000 times",
    "zh_CN": "N次Rebase"
  },
  "hint": {
    "en_US": "Remember, the most efficient way might be to only update master at the end...",
    "ja": "最も効率的なやり方はmasterを最後に更新するだけかもしれない・・・",
    "ko": "아마도 master를 마지막에 업데이트하는 것이 가장 효율적인 방법일 것입니다...",
    "zh_CN": "记住，最后更新master分支可能是最高效的方法。"
  },
  "startDialog": {
    "en_US": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "### Rebasing Multiple Branches",
              "",
              "Man, we have a lot of branches going on here! Let's rebase all the work from these branches onto master.",
              "",
              "Upper management is making this a bit trickier though -- they want the commits to all be in sequential order. So this means that our final tree should have `C7'` at the bottom, `C6'` above that, etc etc, etc all in order.",
              "",
              "If you mess up along the way, feel free to use `reset` to start over again. Be sure to check out our solution and see if you can do it in fewer commands!"
            ]
          }
        }
      ]
    },
    "ja": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "### 複数のブランチをリベースする",
              "",
              "さあ、いくつものブランチが出てきます。このブランチたち全てをmasterブランチにリベースしましょう。",
              "",
              "おエライさん方が今回の仕事を少しトリッキーにしてくれました ― コミットはすべて一列のシーケンシャルな状態にしてほしいそうです。つまり私たちが作るリポジトリの最終的なツリーの状態は、`C7'`が最後に来て、`C6'`がその一つ上に来て、、と順に積み重なるイメージです。",
              "",
              "試行錯誤してツリーが汚くなってきたら、`reset`コマンドを使ってツリーの状態を初期化してください。模範解答をチェックして、それよりも簡単なコマンドで済ませられるかどうか、を考えるのも忘れずに！"
            ]
          }
        }
      ]
    },
    "zh_CN": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "### 多分支衍合",
              "",
              "呐，现在我们有很多分支啦！让我们rebase这些分支的工作到 master 分支上吧。",
              "",
              "但是你的头头找了点麻烦 —— 他们希望得到有序的提交历史，也就是我们最终的结果是 `C7'` 在最底部，`C6'` 在它上面，以此类推。",
              "",
              "假如你搞砸了，没所谓的（虽然我不会告诉你用 `reset` 可以重新开始）。记得看看我们提供的答案，看你能否使用更少的命令完成任务！"
            ]
          }
        }
      ]
    },
    "ko": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "### 여러 브랜치를 리베이스(rebase)하기 ",
              "",
              "음, 여기 꽤 여러개의 브랜치가 있습니다! 이 브랜치들의 모든 작업내역을 master에 리베이스 해볼까요?",
              "",
              "윗선에서 일을 복잡하게 만드네요 -- 그 분들이 이 모든 커밋들을 순서에 맞게 정렬하라고 합니다. 그럼 결국 우리의 최종 목표 트리는 제일 아래에 `C7'` 커밋, 그 위에 `C6'` 커밋, 또 그 위에 순서대로 보여합니다.",
              "",
              "만일 작업중에 내용이 꼬인다면, `reset`이라고 쳐서 처음부터 다시 시작할 수 있습니다. 모범 답안을 확인해 보시고, 혹시 더 적은 수의 커맨드로 해결할 수 있는지 알아보세요!"
            ]
          }
        }
      ]
    }
  }
};
<|endoftext|>


<commit_before>const validNoteLetters = 'ABCDEFG';
const validSharpNotes = 'ACDFG';
const validFlatNotes = 'ABDEG';
const validModifiers = '#b';

export default function (note) {
  let letter = note.charAt(0).toUpperCase();
  let modifier = note.charAt(1) || '';

  if (modifier === 'b' && validFlatNotes.indexOf(letter) === -1) {
    letter = validNoteLetters.charAt(validNoteLetters.indexOf(letter) - 1);
    modifier = '';
  }

  if (modifier === '#' && validSharpNotes.indexOf(letter) === -1) {
    letter = validNoteLetters.charAt(validNoteLetters.indexOf(letter) + 1);
    modifier = '';
  }

  validateLetter(letter);
  validateModifier(modifier);

  return { letter: letter, modifier: modifier || null };
}

function validateLetter(letter) {
  if (validNoteLetters.indexOf(letter) === -1) {
    throw new Error('Invalid note letter');
  }
}

function validateModifier(modifier) {
  if (modifier && validModifiers.indexOf(modifier) === -1) {
    throw new Error('Invalid modifier');
  }
}<commit_msg>Minor refactorings<commit_after>const validNoteLetters = 'ABCDEFG';
const validSharpNotes = 'ACDFG';
const validFlatNotes = 'ABDEG';
const validModifiers = '#b';

export default function (note) {
  let letter = note.charAt(0).toUpperCase();
  let modifier = note.charAt(1) || null;

  if (modifier === 'b' && !validFlatNotes.includes(letter)) {
    letter = validNoteLetters.charAt(validNoteLetters.indexOf(letter) - 1);
    modifier = null;
  }

  if (modifier === '#' && !validSharpNotes.includes(letter)) {
    letter = validNoteLetters.charAt(validNoteLetters.indexOf(letter) + 1);
    modifier = null;
  }

  validateLetter(letter);
  validateModifier(modifier);

  return { letter: letter, modifier: modifier};
}

function validateLetter(letter) {
  if (validNoteLetters.indexOf(letter) === -1) {
    throw new Error('Invalid note letter');
  }
}

function validateModifier(modifier) {
  if (modifier && validModifiers.indexOf(modifier) === -1) {
    throw new Error('Invalid modifier');
  }
}<|endoftext|>


<commit_before>const got = require('got');

const cache = require('../utils/cache.js');
const time = require('../utils/time.js');

// Get trips for stop.
async function getTrips(id) {

	return cache.use('elron-stops', id, async () => {

		const data = JSON.parse((await got(`http://elron.ee/api/v1/stop?stop=${encodeURIComponent(id)}`)).body).data;

		if (!data) throw new Error("Provider 'Elron' is not returning data");
		if (data.text) throw new Error(data.text);

		const now = time.getSeconds();

		return {
			timestamp: (new Date()).getTime(),
			trips: data.filter((trip) => time.toSeconds(trip.plaaniline_aeg) > now).map((trip) => ({
				trip_id: Number(trip.reis),
				time: time.toSeconds(trip.plaaniline_aeg),
				name: trip.reis,
				terminus: trip.liin,
				type: 'train',
				live: false,
				provider: 'elron'
			})).slice(0, 15)
		};

	});

};

// Get trip by id.
async function getTrip(id) {

	return cache.use('elron-trips', id, async () => {

		const data = JSON.parse((await got(`http://elron.ee/api/v1/trip?id=${encodeURIComponent(id)}`)).body).data;

		if (!data) throw new Error("Provider 'Elron' is not returning data");
		if (data.text) throw new Error(data.text);

		return {
			name: id,
			terminus: `${data[0].peatus} - ${data[data.length - 1].peatus}`,
			type: 'train',
			stops: data.map((trip) => ({
				id: trip.peatus,
				name: trip.peatus,
				type: 'train',
				time: trip.plaaniline_aeg
			}))
		};

	});

}

module.exports = {
	getTrips,
	getTrip
};
<commit_msg>Fix Elron provider data format (api)<commit_after>const got = require('got');

const cache = require('../utils/cache.js');
const time = require('../utils/time.js');

// Get trips for stop.
async function getTrips(id) {

	return cache.use('elron-stops', id, async () => {

		const data = JSON.parse((await got(`http://elron.ee/api/v1/stop?stop=${encodeURIComponent(id)}`)).body).data;

		if (!data) throw new Error("Provider 'Elron' is not returning data");
		if (data.text) throw new Error(data.text);

		const now = time.getSeconds();

		return data.filter((trip) => time.toSeconds(trip.plaaniline_aeg) > now).map((trip) => ({
			trip_id: Number(trip.reis),
			time: time.toSeconds(trip.plaaniline_aeg),
			name: trip.reis,
			terminus: trip.liin,
			type: 'train',
			live: false,
			provider: 'elron'
		})).slice(0, 15);

	});

};

// Get trip by id.
async function getTrip(id) {

	return cache.use('elron-trips', id, async () => {

		const data = JSON.parse((await got(`http://elron.ee/api/v1/trip?id=${encodeURIComponent(id)}`)).body).data;

		if (!data) throw new Error("Provider 'Elron' is not returning data");
		if (data.text) throw new Error(data.text);

		return {
			name: id,
			terminus: `${data[0].peatus} - ${data[data.length - 1].peatus}`,
			type: 'train',
			stops: data.map((trip) => ({
				id: trip.peatus,
				name: trip.peatus,
				type: 'train',
				time: trip.plaaniline_aeg
			}))
		};

	});

}

module.exports = {
	getTrips,
	getTrip
};
<|endoftext|>


<commit_before>/**
 * @file xsdwebform.parser.log.js
 * XSD Schema to HTML5 Web Form
 * @author George Bouris <gb@eworx.gr>
 * @copyright Copyright (C) 2017 EEA, Eworx, George Bouris. All rights reserved.
 */

'use strict';

/**
 * Class XSDWebFormParserLog
 * Parser for XSD Schema Tags
 * Static
 */
class XSDWebFormParserLog {
	/**
	 * Class constructor
	 */
	constructor() {
		this.htmlOutput = `<!DOCTYPE html>

`;
	}
	/**
	 * showLog
	 */
	showLogs(sender) {
		if (!sender.verbose)
			console.log("");

		// process.stdout.write(sender.htmlOutput.HTMLObjects[0]);
		if (sender.verbose) {
			console.log("\n\n\x1b[0m\x1b[32mHTML OBJECTS: \x1b[0m\x1b[36m");
			this.htmlOutput  += `<h2>HTML OBJECTS: </h2>\n`;

			console.log("\x1b[0m\x1b[2m");
			this.htmlOutput  += `<ul>\n`;
			sender.htmlOutput.HTMLObjects.forEach( (item) => {
				item.itemObject.groups.forEach( (gitem) => {
					gitem.itemObject.items.forEach( (eitem) => {
						console.log(eitem.toString().substring(0, 40) + "...");
						this.htmlOutput  += `<li>${eitem.toString().substring(0, 80) .replace(/</g, '<').replace(/>/g, '>')}..</li>\n`;
					});
				});
			});
			this.htmlOutput  += `</ul>\n`;
		} else {
			console.log("");
		}
		console.log("\x1b[0m");
		console.log(new Date());

		this.htmlOutput  += `<div style="font-size:14px;color:#555">${new Date()}</div>\n`;

		console.log("\n\x1b[2m\x1b[33m==================================================================================================================================================\n\x1b[0m");
	}

	/**
	 * logXSD
	 * @param xObject
	 */
	logXSD(xObject) {
		console.log("\n\n\x1b[2m\x1b[36m__________________________________________________________________________________________________________________________________________________\n\x1b[0m");
		console.log(`                                                             \x1b[1m\x1b[36mFILE : ${xObject.xfile} \x1b[0m\n`);
		console.log("\x1b[2m\x1b[36m__________________________________________________________________________________________________________________________________________________\n\x1b[0m\n\n");

		this.htmlOutput  += `<h2><span style="font-size:14px;color:#777">XSD File:</span> ${xObject.xfile}</h2>\n`;
	}

	/**
	 * logHTML
	 * @param xObject
	 */
	logHTML(xObject) {
		console.log("\n\n\x1b[2m\x1b[33m__________________________________________________________________________________________________________________________________________________\n\x1b[0m");
		console.log(`                                                             \x1b[1m\x1b[33mFILE : ${xObject.hfile} \x1b[0m\n`);
		console.log("\x1b[2m\x1b[33m__________________________________________________________________________________________________________________________________________________\n\x1b[0m\n\n");

		this.htmlOutput  += `<h2><span style="font-size:14px;color:#777">XML File:</span> ${xObject.hfile}</h2>\n`;
	}

	/**
	 * showItemLog - ShowLog
	 * @param xsdItem
	 */
	showItemLog(xsdItem, verbose) {

		let xspace = "  ";
		for (let i = 0; i < xsdItem.level; i++) {
			xspace += "\t";
		}

		console.log(`${xspace}\x1b[0m\x1b[31m▓▓▓▓▓▓▓▓▓▓▓▓▓\x1b[0m`);
		process.stdout.write(`${xspace}\x1b[2m▓▓▓▓ \x1b[0m\x1b[2mL:${xsdItem.level} \x1b[2m▓▓▓▓\x1b[0m\x1b[31m⇢\x1b[0m `);
		this.htmlOutput  += `

Level ${xsdItem.level}
`;

		if (xsdItem.children) {
			process.stdout.write(`\x1b[1m${xsdItem.name}`);
			this.htmlOutput  += `<li class="xsdc" style="width:200px;color:rgb(0, 51, 153);background-color:#fff;border:1px solid #e5e5e5;border-bottom:none;">${xsdItem.name}</li>\n`;

			if (xsdItem.attr.name) {
				process.stdout.write(` - ${xsdItem.attr.name}`);
				this.htmlOutput  += `<li class="xsdc" style="width:300px;font-size:14px;color:rgb(204, 0, 0);background-color:#fafafa;"><b>${xsdItem.attr.name}</b></li>\n`;

				if (verbose) {
					if (xsdItem.name === "xs:element") {
						let txmlItem = xsdItem.toString();
						txmlItem = txmlItem.split("\n").join("");
						txmlItem = txmlItem.split("<").join(xspace + `\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓  \x1b[2m<`);

						let pos1 = txmlItem.indexOf("<xs:documentation>");
						if (pos1 > 0) {
							let pos2 = txmlItem.indexOf("</xs:documentation>");
							txmlItem = txmlItem.substring(0, pos1) + "<xs:documentation> ..." + txmlItem.substring(pos2);
						}
						process.stdout.write(`\x1b[2m${txmlItem}`);
					}
				}
			} else if (xsdItem.attr.value) {
				process.stdout.write(`\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓  \x1b[2m${xsdItem.attr.value}\x1b[0m`);
				this.htmlOutput  += `<li class="xsdc"style="width:300px;font-size:12px;color:#333;background-color:#eee;"><b>${xsdItem.attr.value}</b></li>\n`;
			} else if (xsdItem.attr.ref) {
				process.stdout.write(`\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓  \x1b[2m\x1b[36mRef: \x1b[1m\x1b[36m${xsdItem.attr.ref}\x1b[0m`);
				this.htmlOutput  += `<li class="xsdc"style="width:300px;font-size:12px;color:#333;background-color:#eee;">Ref: ${xsdItem.attr.ref}</li>\n`;
			}

			process.stdout.write(`\n\x1b[2m${xspace}▓▓▓▓▓▓▓▓▓▓▓▓▓`);

			if (xsdItem.name === "xs:documentation" && xsdItem.xparent.name === "xs:annotation") {
				let txmlItem = xsdItem.val.toString().trim();
				if (txmlItem.length > 60)
					txmlItem = txmlItem.substring(0, 60) + "...";
				process.stdout.write(` \x1b[2m\x1b[37m ${txmlItem}\x1b[0m\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓`);
			}

			if (xsdItem.xparent) {
				console.log(`\x1b[2m\x1b[32m  parent ::\x1b[1m ${xsdItem.xparent.name}\x1b[0m`);
				if (xsdItem.xparent.attr.name) {
					console.log(`${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓ \x1b[2m\x1b[32m par.name ::\x1b[1m ${xsdItem.xparent.attr.name}\x1b[0m`);
				}
			}
		}

		if (xsdItem.level === 0)
			console.log(" ");

		this.htmlOutput  += `</ul>\n`;

		process.stdout.write(`\x1b[2m${xspace}         ▒▒`);
	}

	/**
	 * logXsdTag - Log XSD Element Tag
	 * @param item
	 */
	logXsdTag(item) {
		console.log(`\x1b[0m\x1b[31m⇣\x1b[2m Found Tag \x1b[33m${item}\x1b[0m`);
		this.htmlOutput  += `<div style="width:98%;z-index:-1;padding:4px 8px;font-size:12px;position:absolute;color:#333;background-color:#fafafa;">Found Tag >> ${item}</div>\n`;
	}

	/**
	 * logTODO - Log XSD Element Tag
	 * @param msg
	 */
	logTODO(msg) {
		console.log(`\x1b[1m\x1b[31mTODO: \x1b[0m${msg}\x1b[0m`);
	}

	/**
	 * logHtmlTag - Log HTML Element Tag
	 * @param item
	 */
	logHtmlTag(item, sender) {
		if (sender.verbose) {
			console.log(`\x1b[0m\x1b[31m⇣\n\x1b[2mParsing HTML Tag ⇢ \x1b[33m${item.name}\x1b[0m\n`);
			this.htmlOutput  += `
Parsing HTML Tag >> ${item.name} :: ${item.attr.element  || item.attr.name || ' '}
\n`;
		}
	}

	/**
	 * getHtmlLog
	 */
	getHtmlLog() {
		return this.htmlOutput  + `

		 `;
	}

}

module.exports = XSDWebFormParserLog;<commit_msg>Updated XSD<commit_after>/**
 * @file xsdwebform.parser.log.js
 * XSD Schema to HTML5 Web Form
 * @author George Bouris <gb@eworx.gr>
 * @copyright Copyright (C) 2017 EEA, Eworx, George Bouris. All rights reserved.
 */

'use strict';

/**
 * Class XSDWebFormParserLog
 * Parser for XSD Schema Tags
 * Static
 */
class XSDWebFormParserLog {
	/**
	 * Class constructor
	 */
	constructor() {
		this.htmlOutput = `<!DOCTYPE html>

`;
	}
	/**
	 * showLog
	 */
	showLogs(sender) {
		if (!sender.verbose)
			console.log("");

		// process.stdout.write(sender.htmlOutput.HTMLObjects[0]);
		if (sender.verbose) {
			console.log("\n\n\x1b[0m\x1b[32mHTML OBJECTS: \x1b[0m\x1b[36m");
			this.htmlOutput  += `<div style="background-color:#eaeaea;">\n<h2>HTML OBJECTS: </h2>\n`;

			console.log("\x1b[0m\x1b[2m");
			this.htmlOutput  += `<ul>\n`;
			sender.htmlOutput.HTMLObjects.forEach( (item) => {
				item.itemObject.groups.forEach( (gitem) => {
					gitem.itemObject.items.forEach( (eitem) => {
						console.log(eitem.toString().substring(0, 40) + "...");
						this.htmlOutput  += `<li>${eitem.toString().substring(0, 80) .replace(/</g, '<').replace(/>/g, '>')}..</li>\n`;
					});
				});
			});
			this.htmlOutput  += `</ul>/n</div>\n`;
		} else {
			console.log("");
		}
		console.log("\x1b[0m");
		console.log(new Date());

		this.htmlOutput  += `<div style="font-size:14px;color:#555">${new Date()}</div>\n`;

		console.log("\n\x1b[2m\x1b[33m==================================================================================================================================================\n\x1b[0m");
	}

	/**
	 * logXSD
	 * @param xObject
	 */
	logXSD(xObject) {
		console.log("\n\n\x1b[2m\x1b[36m__________________________________________________________________________________________________________________________________________________\n\x1b[0m");
		console.log(`                                                             \x1b[1m\x1b[36mFILE : ${xObject.xfile} \x1b[0m\n`);
		console.log("\x1b[2m\x1b[36m__________________________________________________________________________________________________________________________________________________\n\x1b[0m\n\n");

		this.htmlOutput  += `<h2><span style="font-size:14px;color:#777">XSD File:</span> ${xObject.xfile}</h2>\n`;
	}

	/**
	 * logHTML
	 * @param xObject
	 */
	logHTML(xObject) {
		console.log("\n\n\x1b[2m\x1b[33m__________________________________________________________________________________________________________________________________________________\n\x1b[0m");
		console.log(`                                                             \x1b[1m\x1b[33mFILE : ${xObject.hfile} \x1b[0m\n`);
		console.log("\x1b[2m\x1b[33m__________________________________________________________________________________________________________________________________________________\n\x1b[0m\n\n");

		this.htmlOutput  += `<h2><span style="font-size:14px;color:#777">XML File:</span> ${xObject.hfile}</h2>\n`;
	}

	/**
	 * showItemLog - ShowLog
	 * @param xsdItem
	 */
	showItemLog(xsdItem, verbose) {

		let xspace = "  ";
		for (let i = 0; i < xsdItem.level; i++) {
			xspace += "\t";
		}

		console.log(`${xspace}\x1b[0m\x1b[31m▓▓▓▓▓▓▓▓▓▓▓▓▓\x1b[0m`);
		process.stdout.write(`${xspace}\x1b[2m▓▓▓▓ \x1b[0m\x1b[2mL:${xsdItem.level} \x1b[2m▓▓▓▓\x1b[0m\x1b[31m⇢\x1b[0m `);
		this.htmlOutput  += `

Level ${xsdItem.level}
`;

		if (xsdItem.children) {
			process.stdout.write(`\x1b[1m${xsdItem.name}`);
			this.htmlOutput  += `<li class="xsdc" style="width:200px;color:rgb(0, 51, 153);background-color:#fff;">${xsdItem.name}</li>\n`;

			if (xsdItem.attr.name) {
				process.stdout.write(` - ${xsdItem.attr.name}`);
				this.htmlOutput  += `<li class="xsdc" style="width:300px;font-size:14px;color:rgb(204, 0, 0);background-color:#fafafa;"><b>${xsdItem.attr.name}</b></li>\n`;

				if (verbose) {
					if (xsdItem.name === "xs:element") {
						let txmlItem = xsdItem.toString();
						txmlItem = txmlItem.split("\n").join("");
						txmlItem = txmlItem.split("<").join(xspace + `\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓  \x1b[2m<`);

						let pos1 = txmlItem.indexOf("<xs:documentation>");
						if (pos1 > 0) {
							let pos2 = txmlItem.indexOf("</xs:documentation>");
							txmlItem = txmlItem.substring(0, pos1) + "<xs:documentation> ..." + txmlItem.substring(pos2);
						}
						process.stdout.write(`\x1b[2m${txmlItem}`);
					}
				}
			} else if (xsdItem.attr.value) {
				process.stdout.write(`\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓  \x1b[2m${xsdItem.attr.value}\x1b[0m`);
				this.htmlOutput  += `<li class="xsdc"style="width:300px;font-size:12px;color:#333;background-color:#eee;"><b>${xsdItem.attr.value}</b></li>\n`;
			} else if (xsdItem.attr.ref) {
				process.stdout.write(`\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓  \x1b[2m\x1b[36mRef: \x1b[1m\x1b[36m${xsdItem.attr.ref}\x1b[0m`);
				this.htmlOutput  += `<li class="xsdc"style="width:300px;font-size:12px;color:#333;background-color:#eee;">Ref: ${xsdItem.attr.ref}</li>\n`;
			}

			process.stdout.write(`\n\x1b[2m${xspace}▓▓▓▓▓▓▓▓▓▓▓▓▓`);

			if (xsdItem.name === "xs:documentation" && xsdItem.xparent.name === "xs:annotation") {
				let txmlItem = xsdItem.val.toString().trim();
				if (txmlItem.length > 60)
					txmlItem = txmlItem.substring(0, 60) + "...";
				process.stdout.write(` \x1b[2m\x1b[37m ${txmlItem}\x1b[0m\n${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓`);
			}

			if (xsdItem.xparent) {
				console.log(`\x1b[2m\x1b[32m  parent ::\x1b[1m ${xsdItem.xparent.name}\x1b[0m`);
				if (xsdItem.xparent.attr.name) {
					console.log(`${xspace}\x1b[2m▓▓▓▓▓▓▓▓▓▓▓▓▓ \x1b[2m\x1b[32m par.name ::\x1b[1m ${xsdItem.xparent.attr.name}\x1b[0m`);
				}
			}
		}

		if (xsdItem.level === 0)
			console.log(" ");

		this.htmlOutput  += `</ul>\n`;

		process.stdout.write(`\x1b[2m${xspace}         ▒▒`);
	}

	/**
	 * logXsdTag - Log XSD Element Tag
	 * @param item
	 */
	logXsdTag(item) {
		console.log(`\x1b[0m\x1b[31m⇣\x1b[2m Found Tag \x1b[33m${item}\x1b[0m`);
		this.htmlOutput  += `<div style="width:98%;z-index:-1;padding:4px 8px;font-size:12px;position:absolute;color:#eee;background-color:#242424;">Found Tag >> ${item}</div>\n`;
	}

	/**
	 * logTODO - Log XSD Element Tag
	 * @param msg
	 */
	logTODO(msg) {
		console.log(`\x1b[1m\x1b[31mTODO: \x1b[0m${msg}\x1b[0m`);
	}

	/**
	 * logHtmlTag - Log HTML Element Tag
	 * @param item
	 */
	logHtmlTag(item, sender) {
		if (sender.verbose) {
			console.log(`\x1b[0m\x1b[31m⇣\n\x1b[2mParsing HTML Tag ⇢ \x1b[33m${item.name}\x1b[0m\n`);
			this.htmlOutput  += `
Parsing HTML Tag >> ${item.name} :: ${item.attr.element  || item.attr.name || ' '}
\n`;
		}
	}

	/**
	 * getHtmlLog
	 */
	getHtmlLog() {
		return this.htmlOutput  + `

		 `;
	}

}

module.exports = XSDWebFormParserLog;<|endoftext|>


<commit_before>'use strict';

$(document).ready(function() {
    /* The state of the parameters in the sidebar.  Dictionary mapping
       strings to values determining the "enabled" configurations. */
    var state = null;

    function setup_display(state_selection) {
        var new_state = setup_state(state_selection);
        var same_state = (state !== null);

        /* Avoid needless UI updates, e.g., on table sort */

        if (same_state) {
            $.each(state, function (key, value) {
                if (value != new_state[key]) {
                    same_state = false;
                }
            });
        }

        if (!same_state) {
            state = new_state;
            replace_params_ui();

            var filename = $.asv.graph_to_path('summary', state);
            $.asv.load_graph_data(
                filename
            ).done(function (data) {
                replace_benchmark_table(data);
            });
        }
    }

    function update_state_url(key, value) {
        var info = $.asv.parse_hash_string(window.location.hash);
        var new_state = get_valid_state(state, key, value);

        $.each($.asv.master_json.params, function(param, values) {
            if (values.length > 1) {
                info.params[param] = [new_state[param]];
            }
            else if (info.params[param]) {
                delete info.params[param];
            }
        });

        window.location.hash = $.asv.format_hash_string(info);
    }

    function obj_copy(obj) {
        var newobj = {};
        $.each(obj, function(key, val) {
            newobj[key] = val;
        });
        return newobj;
    }

    function obj_diff(obj1, obj2) {
        var count = 0;
        $.each(obj1, function(key, val) {
            if (obj2[key] != val) {
                ++count
            }
        });
        return count;
    }

    function get_valid_state(tmp_state, wanted_key, wanted_value) {
        /*
          Get an available state with wanted_key having wanted_value,
          preferably as a minor modification of tmp_state.
         */
        var best_params = null;
        var best_diff = 1e99;
        var best_hit = false;

        tmp_state = obj_copy(tmp_state);
        tmp_state[wanted_key] = wanted_value;

        $.each($.asv.master_json.graph_param_list, function(idx, params) {
            var diff = obj_diff(tmp_state, params);
            var hit = (params[wanted_key] == wanted_value);

            if ((!best_hit && hit) || (hit == best_hit && diff < best_diff)) {
                best_params = params;
                best_diff = diff;
                best_hit = hit;
            }
        });

        if (best_params === null) {
            best_params = $.asv.master_json.graph_param_list[0];
        }

        return obj_copy(best_params);
    }

    function setup_state(state_selection) {
        var index = $.asv.master_json;
        var state = {};

        state.machine = index.params.machine;

        $.each(index.params, function(param, values) {
            state[param] = values[0];
        });

        if (state_selection !== null) {
            /* Select a specific generic parameter state */
            $.each(index.params, function(param, values) {
                if (state_selection[param]) {
                    state[param] = state_selection[param][0];
                }
            });
        }

        return state;
    }

    function replace_params_ui() {
        var index = $.asv.master_json;

        var nav = $('#summarylist-navigation');
        nav.empty();

        /* Machine selection */
        $.asv.ui.make_value_selector_panel(nav, 'machine', index.params.machine,  function(i, machine, button) {
            button.text(machine);

            button.on('click', function(evt) {
                update_state_url('machine', machine);
            });

            if (state.machine != machine) {
                button.removeClass('active');
            }
            button.removeAttr('data-toggle');

            /* Create tooltips for each machine */
            var details = [];
            $.each(index.machines[machine], function(key, val) {
                details.push(key + ': ' + val);
            });
            details = details.join('
');

            button.tooltip({
                title: details,
                html: true,
                placement: 'right',
                container: 'body',
                animation: false
            });
        });

        /* Generic parameter selectors */
        $.each(index.params, function(param, values) {
            if (values.length > 1 && param != 'machine') {
                $.asv.ui.make_value_selector_panel(nav, param, values, function(i, value, button) {
                    var value_display;
                    if (value === null)
                        value_display = '[none]';
                    else if (!value)
                        value_display = '[default]';
                    else
                        value_display = value;

                    button.text(value_display);

                    if (state[param] != value) {
                        button.removeClass('active');
                    }

                    button.on('click', function(evt) {
                        update_state_url(param, value);
                    });
                });
            }
        });

        $(nav).find(".btn-group").removeAttr("data-toggle");

        $.asv.ui.reflow_value_selector_panels();
    }

    function pad_left(s, c, num) {
        s = '' + s;
        while (s.length < num) {
            s = c + s;
        }
        return s;
    }

    function format_date_yyyymmdd(date) {
        return (pad_left(date.getFullYear(), '0', 4)
                + '-' + pad_left(date.getMonth() + 1, '0', 2)
                + '-' + pad_left(date.getDay() + 1, '0', 2));
    }

    function replace_benchmark_table(data) {
        var index = $.asv.master_json;
        var body = $("#summarylist-body");

        body.empty();

        /* Form a new table */

        var table = $('
');

        var table_head = $('

' +
                           'Benchmark	' +
                           'Value	' +
                           'Recent change	' +
                           'Changed at	' +
                           '

');
        table.append(table_head);

        var table_body = $('
');

        $.each(data, function(row_idx, row) {
            var tr = $('
');
            var name_td = $('');
            var name = $('');
            var url = '#/' + row.name;
            var benchmark_full_url;

            var bm_link;
            if (row.idx === null) {
                bm_link = $('').attr('href', url).text(row.pretty_name);
                name_td.append(bm_link);
                benchmark_full_url = url + '?';
            }
            else {
                var basename = row.pretty_name;
                var args = null;
                var m = row.pretty_name.match(/(.*)\(.*$/);
                if (m) {
                    basename = m[1];
                    args = row.pretty_name.slice(basename.length);
                }
                bm_link = $('').attr('href', url).text(basename);
                name_td.append(bm_link);
                if (args) {
                    var bm_idx_link;
                    var graph_url;
                    bm_idx_link = $('').attr('href', url + '?idx=' + row.idx).text(' ' + args);
                    name_td.append(bm_idx_link);
                    graph_url = $.asv.graph_to_path(row.name, state);
                    $.asv.ui.hover_graph(bm_idx_link, graph_url, row.name, row.idx, null);
                }
                benchmark_full_url = url + '?idx=' + row.idx;
            }
            $.asv.ui.hover_summary_graph(bm_link, row.name);

            var value_td = $('');
            if (row.last_value !== null) {
                var value, err, err_str, sort_value;
                if ($.asv.master_json.benchmarks[row.name].unit == "seconds") {
                    value = $.asv.pretty_second(row.last_value);
                    sort_value = row.last_value * 1e100;
                }
                else {
                    value = row.last_value.toPrecision(3);
                    sort_value = row.last_value;
                }
                var value_span = $('').text(value);

                err = 100*row.last_err/row.last_value;
                if (err == err) {
                    err_str = " \u00b1 " + err.toFixed(0.1) + '%';
                }
                else {
                    err_str = "";
                }
                value_span.attr('data-toggle', 'tooltip');
                value_span.attr('title', value + err_str);
                value_td.append(value_span);
                value_td.attr('data-sort-value', sort_value);
            }
            else {
                value_td.attr('data-sort-value', -1e99);
            }

            var change_td = $('');
            if (row.prev_value !== null) {
                var text, change_str, change = 0, sort_value = 0;
                if ($.asv.master_json.benchmarks[row.name].unit == "seconds") {
                    change_str = $.asv.pretty_second(row.last_value - row.prev_value);
                }
                else {
                    change_str = '' + (row.last_value - row.prev_value).toPrecision(3);
                }
                if (!change_str.match(/^-/)) {
                    change_str = '+' + change_str;
                }
                if (row.prev_value != 0) {
                    change = 100 * (row.last_value / row.prev_value - 1);
                    text = change.toFixed(1) + '%  (' + change_str + ')';
                    if (change > 0) {
                        text = '+' + text;
                    }
                    sort_value = change;
                }
                else {
                    text = ' (' + change_str + ')';
                }
                text = text.replace('-', '\u2212');

                var change_commit = $.asv.master_json.revision_to_hash[row.change_rev];
                var change_link = $('').attr('href', benchmark_full_url
                                                 + '&commits='
                                                 + change_commit
                                                ).text(text);

                graph_url = $.asv.graph_to_path(row.name, state);
                $.asv.ui.hover_graph(change_link, graph_url, row.name, row.idx, [[null, row.change_rev]]);

                change_td.append(change_link);

                if (change > 5) {
                    change_td.addClass('positive-change');
                }
                else if (change < -5) {
                    change_td.addClass('negative-change');
                }
                change_td.attr('data-sort-value', sort_value);
            }
            else {
                change_td.attr('data-sort-value', 0);
            }

            var changed_at_td = $('');
            if (row.change_rev !== null) {
                var date = new Date($.asv.master_json.revision_to_date[row.change_rev]);
                var commit = $.asv.get_commit_hash(row.change_rev);
                var commit_a = $('');
                var last_commit = $.asv.get_commit_hash(row.last_rev);
                var last_commit_a = $('');
                var span = $('');
                commit_a.attr('href', $.asv.master_json.show_commit_url + commit);
                commit_a.text(commit);
                last_commit_a.attr('href', $.asv.master_json.show_commit_url + commit);
                last_commit_a.text(commit);
                span.text(format_date_yyyymmdd(date) + ' ');
                span.append(commit_a);
                changed_at_td.append(span);
            }

            tr.append(name_td);
            tr.append(value_td);
            tr.append(change_td);
            tr.append(changed_at_td);

            table_body.append(tr);
        });

        table_body.find('[data-toggle="tooltip"]').tooltip();

        /* Finalize */
        table.append(table_body);
        setup_sort(table);
        body.append(table);
    }

    function setup_sort(table) {
        var info = $.asv.parse_hash_string(window.location.hash);

        table.stupidtable();

        table.bind('aftertablesort', function (event, data) {
            var info = $.asv.parse_hash_string(window.location.hash);
            info.params['sort'] = [data.column];
            info.params['dir'] = [data.direction];
            window.location.hash = $.asv.format_hash_string(info);

            /* Update appearance */
            table.find('thead th').removeClass('asc');
            table.find('thead th').removeClass('desc');
            var th_to_sort = table.find("thead th").eq(parseInt(data.column));
            if (th_to_sort) {
                th_to_sort.addClass(data.direction);
            }
        });

        if (info.params.sort && info.params.dir) {
            var th_to_sort = table.find("thead th").eq(parseInt(info.params.sort[0]));
            th_to_sort.stupidsort(info.params.dir[0]);
        }
        else {
            var th_to_sort = table.find("thead th").eq(0);
            th_to_sort.stupidsort("asc");
        }
    }

    /*
     * Entry point
     */
    $.asv.register_page('summarylist', function(params) {
        var state_selection = null;

        if (Object.keys(params).length > 0) {
            state_selection = params;
        }

        setup_display(state_selection);

        $('#summarylist-display').show();
        $("#title").text("List of benchmarks");
    });
});
<commit_msg>Cache constructed table DOM in summarylist<commit_after>'use strict';

$(document).ready(function() {
    /* The state of the parameters in the sidebar.  Dictionary mapping
       strings to values determining the "enabled" configurations. */
    var state = null;
    /* Cache of constructed tables, {data_path: table_dom_id} */
    var table_cache = {};
    var table_cache_counter = 0;

    function setup_display(state_selection) {
        var new_state = setup_state(state_selection);
        var same_state = (state !== null);

        /* Avoid needless UI updates, e.g., on table sort */

        if (same_state) {
            $.each(state, function (key, value) {
                if (value != new_state[key]) {
                    same_state = false;
                }
            });
        }

        if (!same_state) {
            state = new_state;
            replace_params_ui();

            var filename = $.asv.graph_to_path('summary', state);

            $("#summarylist-body table").hide();
            $("#summarylist-body .message").remove();

            if (table_cache[filename] !== undefined) {
                $(table_cache[filename]).show();
            }
            else {
                $("#summarylist-body").append($("
Loading...
"));
                $.asv.load_graph_data(
                    filename
                ).done(function (data) {
                    var table = construct_benchmark_table(data);
                    var table_name = 'summarylist-table-' + table_cache_counter;
                    ++table_cache_counter;

                    table.attr('id', table_name);
                    table_cache[filename] = '#' + table_name;
                    $("#summarylist-body .message").remove();
                    $("#summarylist-body").append(table);
                    table.show()
                });
            }
        }
    }

    function update_state_url(key, value) {
        var info = $.asv.parse_hash_string(window.location.hash);
        var new_state = get_valid_state(state, key, value);

        $.each($.asv.master_json.params, function(param, values) {
            if (values.length > 1) {
                info.params[param] = [new_state[param]];
            }
            else if (info.params[param]) {
                delete info.params[param];
            }
        });

        window.location.hash = $.asv.format_hash_string(info);
    }

    function obj_copy(obj) {
        var newobj = {};
        $.each(obj, function(key, val) {
            newobj[key] = val;
        });
        return newobj;
    }

    function obj_diff(obj1, obj2) {
        var count = 0;
        $.each(obj1, function(key, val) {
            if (obj2[key] != val) {
                ++count
            }
        });
        return count;
    }

    function get_valid_state(tmp_state, wanted_key, wanted_value) {
        /*
          Get an available state with wanted_key having wanted_value,
          preferably as a minor modification of tmp_state.
         */
        var best_params = null;
        var best_diff = 1e99;
        var best_hit = false;

        tmp_state = obj_copy(tmp_state);
        tmp_state[wanted_key] = wanted_value;

        $.each($.asv.master_json.graph_param_list, function(idx, params) {
            var diff = obj_diff(tmp_state, params);
            var hit = (params[wanted_key] == wanted_value);

            if ((!best_hit && hit) || (hit == best_hit && diff < best_diff)) {
                best_params = params;
                best_diff = diff;
                best_hit = hit;
            }
        });

        if (best_params === null) {
            best_params = $.asv.master_json.graph_param_list[0];
        }

        return obj_copy(best_params);
    }

    function setup_state(state_selection) {
        var index = $.asv.master_json;
        var state = {};

        state.machine = index.params.machine;

        $.each(index.params, function(param, values) {
            state[param] = values[0];
        });

        if (state_selection !== null) {
            /* Select a specific generic parameter state */
            $.each(index.params, function(param, values) {
                if (state_selection[param]) {
                    state[param] = state_selection[param][0];
                }
            });
        }

        return state;
    }

    function replace_params_ui() {
        var index = $.asv.master_json;

        var nav = $('#summarylist-navigation');
        nav.empty();

        /* Machine selection */
        $.asv.ui.make_value_selector_panel(nav, 'machine', index.params.machine,  function(i, machine, button) {
            button.text(machine);

            button.on('click', function(evt) {
                update_state_url('machine', machine);
            });

            if (state.machine != machine) {
                button.removeClass('active');
            }
            button.removeAttr('data-toggle');

            /* Create tooltips for each machine */
            var details = [];
            $.each(index.machines[machine], function(key, val) {
                details.push(key + ': ' + val);
            });
            details = details.join('
');

            button.tooltip({
                title: details,
                html: true,
                placement: 'right',
                container: 'body',
                animation: false
            });
        });

        /* Generic parameter selectors */
        $.each(index.params, function(param, values) {
            if (values.length > 1 && param != 'machine') {
                $.asv.ui.make_value_selector_panel(nav, param, values, function(i, value, button) {
                    var value_display;
                    if (value === null)
                        value_display = '[none]';
                    else if (!value)
                        value_display = '[default]';
                    else
                        value_display = value;

                    button.text(value_display);

                    if (state[param] != value) {
                        button.removeClass('active');
                    }

                    button.on('click', function(evt) {
                        update_state_url(param, value);
                    });
                });
            }
        });

        $(nav).find(".btn-group").removeAttr("data-toggle");

        $.asv.ui.reflow_value_selector_panels();
    }

    function pad_left(s, c, num) {
        s = '' + s;
        while (s.length < num) {
            s = c + s;
        }
        return s;
    }

    function format_date_yyyymmdd(date) {
        return (pad_left(date.getFullYear(), '0', 4)
                + '-' + pad_left(date.getMonth() + 1, '0', 2)
                + '-' + pad_left(date.getDay() + 1, '0', 2));
    }

    function construct_benchmark_table(data) {
        var index = $.asv.master_json;

        /* Form a new table */

        var table = $('
');

        var table_head = $('

' +
                           'Benchmark	' +
                           'Value	' +
                           'Recent change	' +
                           'Changed at	' +
                           '

');
        table.append(table_head);

        var table_body = $('
');

        $.each(data, function(row_idx, row) {
            var tr = $('
');
            var name_td = $('');
            var name = $('');
            var url = '#/' + row.name;
            var benchmark_full_url;

            var bm_link;
            if (row.idx === null) {
                bm_link = $('').attr('href', url).text(row.pretty_name);
                name_td.append(bm_link);
                benchmark_full_url = url + '?';
            }
            else {
                var basename = row.pretty_name;
                var args = null;
                var m = row.pretty_name.match(/(.*)\(.*$/);
                if (m) {
                    basename = m[1];
                    args = row.pretty_name.slice(basename.length);
                }
                bm_link = $('').attr('href', url).text(basename);
                name_td.append(bm_link);
                if (args) {
                    var bm_idx_link;
                    var graph_url;
                    bm_idx_link = $('').attr('href', url + '?idx=' + row.idx).text(' ' + args);
                    name_td.append(bm_idx_link);
                    graph_url = $.asv.graph_to_path(row.name, state);
                    $.asv.ui.hover_graph(bm_idx_link, graph_url, row.name, row.idx, null);
                }
                benchmark_full_url = url + '?idx=' + row.idx;
            }
            $.asv.ui.hover_summary_graph(bm_link, row.name);

            var value_td = $('');
            if (row.last_value !== null) {
                var value, err, err_str, sort_value;
                if ($.asv.master_json.benchmarks[row.name].unit == "seconds") {
                    value = $.asv.pretty_second(row.last_value);
                    sort_value = row.last_value * 1e100;
                }
                else {
                    value = row.last_value.toPrecision(3);
                    sort_value = row.last_value;
                }
                var value_span = $('').text(value);

                err = 100*row.last_err/row.last_value;
                if (err == err) {
                    err_str = " \u00b1 " + err.toFixed(0.1) + '%';
                }
                else {
                    err_str = "";
                }
                value_span.attr('data-toggle', 'tooltip');
                value_span.attr('title', value + err_str);
                value_td.append(value_span);
                value_td.attr('data-sort-value', sort_value);
            }
            else {
                value_td.attr('data-sort-value', -1e99);
            }

            var change_td = $('');
            if (row.prev_value !== null) {
                var text, change_str, change = 0, sort_value = 0;
                if ($.asv.master_json.benchmarks[row.name].unit == "seconds") {
                    change_str = $.asv.pretty_second(row.last_value - row.prev_value);
                }
                else {
                    change_str = '' + (row.last_value - row.prev_value).toPrecision(3);
                }
                if (!change_str.match(/^-/)) {
                    change_str = '+' + change_str;
                }
                if (row.prev_value != 0) {
                    change = 100 * (row.last_value / row.prev_value - 1);
                    text = change.toFixed(1) + '%  (' + change_str + ')';
                    if (change > 0) {
                        text = '+' + text;
                    }
                    sort_value = change;
                }
                else {
                    text = ' (' + change_str + ')';
                }
                text = text.replace('-', '\u2212');

                var change_commit = $.asv.master_json.revision_to_hash[row.change_rev];
                var change_link = $('').attr('href', benchmark_full_url
                                                 + '&commits='
                                                 + change_commit
                                                ).text(text);

                graph_url = $.asv.graph_to_path(row.name, state);
                $.asv.ui.hover_graph(change_link, graph_url, row.name, row.idx, [[null, row.change_rev]]);

                change_td.append(change_link);

                if (change > 5) {
                    change_td.addClass('positive-change');
                }
                else if (change < -5) {
                    change_td.addClass('negative-change');
                }
                change_td.attr('data-sort-value', sort_value);
            }
            else {
                change_td.attr('data-sort-value', 0);
            }

            var changed_at_td = $('');
            if (row.change_rev !== null) {
                var date = new Date($.asv.master_json.revision_to_date[row.change_rev]);
                var commit = $.asv.get_commit_hash(row.change_rev);
                var commit_a = $('');
                var last_commit = $.asv.get_commit_hash(row.last_rev);
                var last_commit_a = $('');
                var span = $('');
                commit_a.attr('href', $.asv.master_json.show_commit_url + commit);
                commit_a.text(commit);
                last_commit_a.attr('href', $.asv.master_json.show_commit_url + commit);
                last_commit_a.text(commit);
                span.text(format_date_yyyymmdd(date) + ' ');
                span.append(commit_a);
                changed_at_td.append(span);
            }

            tr.append(name_td);
            tr.append(value_td);
            tr.append(change_td);
            tr.append(changed_at_td);

            table_body.append(tr);
        });

        table_body.find('[data-toggle="tooltip"]').tooltip();

        /* Finalize */
        table.append(table_body);
        setup_sort(table);

        return table;
    }

    function setup_sort(table) {
        var info = $.asv.parse_hash_string(window.location.hash);

        table.stupidtable();

        table.bind('aftertablesort', function (event, data) {
            var info = $.asv.parse_hash_string(window.location.hash);
            info.params['sort'] = [data.column];
            info.params['dir'] = [data.direction];
            window.location.hash = $.asv.format_hash_string(info);

            /* Update appearance */
            table.find('thead th').removeClass('asc');
            table.find('thead th').removeClass('desc');
            var th_to_sort = table.find("thead th").eq(parseInt(data.column));
            if (th_to_sort) {
                th_to_sort.addClass(data.direction);
            }
        });

        if (info.params.sort && info.params.dir) {
            var th_to_sort = table.find("thead th").eq(parseInt(info.params.sort[0]));
            th_to_sort.stupidsort(info.params.dir[0]);
        }
        else {
            var th_to_sort = table.find("thead th").eq(0);
            th_to_sort.stupidsort("asc");
        }
    }

    /*
     * Entry point
     */
    $.asv.register_page('summarylist', function(params) {
        var state_selection = null;

        if (Object.keys(params).length > 0) {
            state_selection = params;
        }

        setup_display(state_selection);

        $('#summarylist-display').show();
        $("#title").text("List of benchmarks");
    });
});
<|endoftext|>


<commit_before>/*
	This is an example app to use as starting point for building a mydigitalstucture.cloud based nodejs app ...
	Once nodejs has been installed; run 'node learn.js' using the OS terminal/console command prompt

	If you plan to host the app using AWS lambda then check out index.js

	Help @ https://learn-next.mydigitalstructure.cloud/learn-function-automation
*/

var mydigitalstructure = require('mydigitalstructure')
var _ = require('lodash')
var moment = require('moment');

/*
	mydigitalstructure. functions impact local data.
	mydigitalstructure.cloud. functions impact data managed by the mydigitalstructure.cloud service (remote).

	All functions invoked on mydigitalstructure.cloud (remote) are asynchronous,
	in that the local code will keep running after the invoke and you need to
	use a callcack: controller to handle the response from mydigitalstructure.cloud, as in examples 5 & 5 below.

	To get the current logged on user using mydigitalstructure.cloud.invoke({method: 'core_get_user_details'}),
*/

mydigitalstructure.init(main);

function main(err, data)
{
	if (mydigitalstructure.data.settings.testing.status != 'true')
	{
		mydigitalstructure._util.message(
		[
			'-',
			'LEARN-TIP #1:',
			' To see the mydigitalstructure module requests to and received responses from mydigitalstructure.cloud;',
			' set mydigitalstructure.data.settings.testing.status: \"true\"',
			' and/or mydigitalstructure.data.settings.testing.showData: \"true\" in settings.json',
		]);

		/*
			You can use mydigitalstructure._util.message to write a message to the terminal command line.
			You can pass a string or an array of strings.  If it is an array each string will be displayed on a new line.
		*/
	}

	/*
		[LEARN EXAMPLE #1]
		Use mydigitalstructure.add to add your controller functions to your app and mydigitalstructure.invoke to run them,
		as per example app-show-session.
	*/

	mydigitalstructure.add(
	{
		name: 'learn-example-1-show-session',
		code: function ()
		{
			mydigitalstructure._util.message(
			[
				'-',
				'Using mydigitalstructure module version ' + mydigitalstructure.VERSION,
				'-',
				'',
				'LEARN-EXAMPLE #1; mydigitalstructure.cloud session object:',
				mydigitalstructure.data.session
			]);
		}
	});

	mydigitalstructure.invoke('learn-example-1-show-session');

	/*
		[LEARN EXAMPLE #2]
		Now with some parameters and data.

		In example using mydigitalstructure._util.message instead of console.log,
		so as to format message before showing in terminal/console.
	*/

	mydigitalstructure.add(
	{
		name: 'learn-example-2-show-session',
		code: function (param, data)
		{
			if (!_.isUndefined(param))
			{
				mydigitalstructure._util.message(
				[
					'-',
					'',
					param.hello,
					data
				])
			}
		}
	});

	mydigitalstructure.invoke(
	'learn-example-2-show-session',
	{
		hello: 'LEARN-EXAMPLE #2; mydigitalstructure.cloud session object:'
	},
	mydigitalstructure.data.session);

	/*
		[LEARN EXAMPLE #3]
		Get and set data locally.

		This example uses mydigitalstructure.set/.get - you can store at any level
		ie just scope, scope/context or scope/context/name.
		The value can be any Javascript data type ie string, number, object, array.
	*/

	mydigitalstructure.add(
	{
		name: 'learn-example-3-local-data',
		code: function (param, data)
		{
			mydigitalstructure.set(
			{
				scope: 'learn-example-3-local-data',
				context: 'example-context',
				name: 'example-name',
				value: 'example-value'
			});

			var data = mydigitalstructure.get(
			{
				scope: 'learn-example-3-local-data',
				context: 'example-context',
				name: 'example-name'
			});

			mydigitalstructure._util.message(
			[
				'-',
				'',
				'LEARN-EXAMPLE #3; Local Data:',
				data,
			]);
		}
	});

	mydigitalstructure.invoke('learn-example-3-local-data');

	/*
		[LEARN EXAMPLE #4]
		Retrieve some data from mydigitalstructure.cloud

		!! Call to mydigitalstructure.cloud is asynchronous so a callback controller needs to be used.
			It then invokes the next example, else it will be invoked before this example is complete.
	*/

	mydigitalstructure.add(
	[
		{
			name: 'learn-example-4-mydigitalstructure.cloud-retrieve-contacts',
			code: function (param)
			{
				mydigitalstructure.cloud.retrieve(
				{
					object: 'contact_person',
					fields:
					[
						{name: 'firstname'},
						{name: 'surname'}
					],
					callback: 'learn-example-4-mydigitalstructure.cloud-show-contacts'
				});
			}
		},
		{
			name: 'learn-example-4-mydigitalstructure.cloud-show-contacts',
			note: 'Handles the response from mydigitalstructure.cloud',
			code: function (param, response)
			{
				mydigitalstructure._util.message(
				[
					'-',
					'',
					'LEARN-EXAMPLE #4; Returned JSON Data:',
					response
				]);

				/*
					Invoked here so is called after data is returned from mydigitalstucture.cloud
				*/

				mydigitalstructure.invoke('learn-example-5-mydigitalstructure.cloud-save-contact');
			}
		}
	]);

	mydigitalstructure.invoke('learn-example-4-mydigitalstructure.cloud-retrieve-contacts');

	/*
		[LEARN EXAMPLE #5]
		Save some data to mydigitalstructure.cloud.

		!! Call to mydigitalstructure.cloud is asynchronous so a callback controller needs to be used.
			It then invokes the next example, else it will be invoked before this example is complete.

		!!! mydigitalstructure.cloud will return with error message ""No rights (No Access to method)",
			 to make it work update the settings.json logon & password to be your own,
			 ie. as you use to log on to https://console.mydigitalstructure.cloud.
	*/

	mydigitalstructure.add(
	[
		{
			name: 'learn-example-5-mydigitalstructure.cloud-save-contact',
			code: function (param)
			{
				mydigitalstructure.cloud.save(
				{
					object: 'contact_person',
					fields:
					{
						firstname: 'A',
						surname: 'B'
					},
					callback: 'learn-example-5-mydigitalstructure.cloud-save-contact-confirm'
				});
			}
		},
		{
			name: 'learn-example-5-mydigitalstructure.cloud-save-contact-confirm',
			note: 'Handles the response from mydigitalstructure.cloud',
			code: function (param, response)
			{
				mydigitalstructure._util.message(
				[
					'-',
					'',
					'LEARN-EXAMPLE #5; Returned JSON Data:',
					response
				]);

				mydigitalstructure.invoke('learn-example-6-mydigitalstructure.cloud-retrieve-contacts');
			}
		}
	]);

	/*
		[LEARN EXAMPLE #6]
		Retrieve some data from mydigitalstructure.cloud
		And loop through the return rows and write them to the console.

		It also checks that the response as OK and if not shows the error.

		List of fields and filters @
		https://learn-next.mydigitalstructure.cloud/schema

		To add a filter to search by say firstname add following to code below:
		{
			field: 'firstname',
			comparison: 'EQUAL_TO',
			value: 'John'
		}

		The following example uses the lodash.com _.each() method.

		!! Call to mydigitalstructure.cloud is asynchronous so a callback controller needs to be used.
	*/

	mydigitalstructure.add(
	[
		{
			name: 'learn-example-6-mydigitalstructure.cloud-retrieve-contacts',
			code: function (param)
			{
				mydigitalstructure.cloud.retrieve(
				{
					object: 'contact_person',
					fields:
					[
						{name: 'firstname'},
						{name: 'surname'},
						{name: 'guid'}
					],
					filters:
					[],
					callback: 'learn-example-6-mydigitalstructure.cloud-retrieve-contacts-show'
				});
			}
		},
		{
			name: 'learn-example-6-mydigitalstructure.cloud-retrieve-contacts-show',
			note: 'Handles the response from mydigitalstructure.cloud and shows the contacts or error.',
			code: function (param, response)
			{
				if (response.status == 'ER')
				{
					mydigitalstructure._util.message(
					[
						'-',
						'',
						'LEARN-EXAMPLE #6:',
						'Error Code; ' + response.error.errorcode,
						'Error Notes; ' + response.error.errornotes,
						'Help @ ' + response.error.methodhelp
					]);
				}
				else
				{
					mydigitalstructure._util.message(
					[
						'-',
						'',
						'LEARN-EXAMPLE #6 Data:',
						'-'
					]);

					_.each(response.data.rows, function (row)
					{
						mydigitalstructure._util.message(
						[
							'First name; ' + row.firstname,
							'Surname; ' + row.surname,
							'Unique ID; ' + row.guid,
							'-'
						]);
					});
				}

				mydigitalstructure.invoke('learn-example-7-show-controllers');
			}
		}
	]);

	/*
		[LEARN EXAMPLE #7]
		Show controller code & notes to the terminal (console);
		Process comment line arguments.  You can also use module like yargs.
		In this case will show the controller code of a named controller or if the list of controllers
	*/

	mydigitalstructure.add(
	[
		{
			name: 'learn-example-7-show-controllers',
			code: function (param)
			{
				mydigitalstructure._util.message(
				[
					'',
					'LEARN-EXAMPLE #7, Show Controllers:'
				]);

				if (_.find(process.argv, function (a) {return (a == '/?')}))
				{
					var name = _.find(process.argv, function (a) {return _.includes(a, '/n:')});

					if (name != undefined)
					{
						name = _.replace(name, '/n:', '');
						mydigitalstructure._util.controller.show({name: name});
					}
					else
					{
						mydigitalstructure._util.controller.show()
					}
				}

				mydigitalstructure._util.message(
				[
					'',
					'To show the code for a controller add argument: /n:[name of controller]',
					''
				]);
			}
		}
	])
}<commit_msg>Update learn.js<commit_after>/*
	This is an example app to use as starting point for building a mydigitalstucture.cloud based nodejs app ...
	Once nodejs has been installed; run 'node learn.js' using the OS terminal/console command prompt

	If you plan to host the app using AWS lambda then check out index.js

	Help @ https://learn-next.mydigitalstructure.cloud/learn-function-automation
*/

var mydigitalstructure = require('mydigitalstructure')
var _ = require('lodash')
var moment = require('moment');

/*
	mydigitalstructure. functions impact local data.
	mydigitalstructure.cloud. functions impact data managed by the mydigitalstructure.cloud service (remote).

	All functions invoked on mydigitalstructure.cloud (remote) are asynchronous,
	in that the local code will keep running after the invoke and you need to
	use a callcack: controller to handle the response from mydigitalstructure.cloud, as in examples 5 & 5 below.

	To get the current logged on user using mydigitalstructure.cloud.invoke({method: 'core_get_user_details'}),
*/

mydigitalstructure.init(main);

function main(err, data)
{
	if (mydigitalstructure.data.settings.testing.status != 'true')
	{
		mydigitalstructure._util.message(
		[
			'-',
			'LEARN-TIP #1:',
			' To see the mydigitalstructure module requests to and received responses from mydigitalstructure.cloud;',
			' set mydigitalstructure.data.settings.testing.status: \"true\"',
			' and/or mydigitalstructure.data.settings.testing.showData: \"true\" in settings.json',
		]);

		/*
			You can use mydigitalstructure._util.message to write a message to the terminal command line.
			You can pass a string or an array of strings.  If it is an array each string will be displayed on a new line.
		*/
	}

	/*
		[LEARN EXAMPLE #1]
		Use mydigitalstructure.add to add your controller functions to your app and mydigitalstructure.invoke to run them,
		as per example app-show-session.
	*/

	mydigitalstructure.add(
	{
		name: 'learn-example-1-show-session',
		code: function ()
		{
			mydigitalstructure._util.message(
			[
				'-',
				'Using mydigitalstructure module version ' + mydigitalstructure.VERSION,
				'-',
				'',
				'LEARN-EXAMPLE #1; mydigitalstructure.cloud session object:',
				mydigitalstructure.data.session
			]);
		}
	});

	mydigitalstructure.invoke('learn-example-1-show-session');

	/*
		[LEARN EXAMPLE #2]
		Now with some parameters and data.

		In example using mydigitalstructure._util.message instead of console.log,
		so as to format message before showing in terminal/console.
	*/

	mydigitalstructure.add(
	{
		name: 'learn-example-2-show-session',
		code: function (param, data)
		{
			if (!_.isUndefined(param))
			{
				mydigitalstructure._util.message(
				[
					'-',
					'',
					param.hello,
					data
				])
			}
		}
	});

	mydigitalstructure.invoke(
	'learn-example-2-show-session',
	{
		hello: 'LEARN-EXAMPLE #2; mydigitalstructure.cloud session object:'
	},
	mydigitalstructure.data.session);

	/*
		[LEARN EXAMPLE #3]
		Get and set data locally.

		This example uses mydigitalstructure.set/.get - you can store at any level
		ie just scope, scope/context or scope/context/name.
		The value can be any Javascript data type ie string, number, object, array.
	*/

	mydigitalstructure.add(
	{
		name: 'learn-example-3-local-data',
		code: function (param, data)
		{
			mydigitalstructure.set(
			{
				scope: 'learn-example-3-local-data',
				context: 'example-context',
				name: 'example-name',
				value: 'example-value'
			});

			var data = mydigitalstructure.get(
			{
				scope: 'learn-example-3-local-data',
				context: 'example-context',
				name: 'example-name'
			});

			mydigitalstructure._util.message(
			[
				'-',
				'',
				'LEARN-EXAMPLE #3; Local Data:',
				data,
			]);
		}
	});

	mydigitalstructure.invoke('learn-example-3-local-data');

	/*
		[LEARN EXAMPLE #4]
		Retrieve some data from mydigitalstructure.cloud

		!! Call to mydigitalstructure.cloud is asynchronous so a callback controller needs to be used.
			It then invokes the next example, else it will be invoked before this example is complete.
	*/

	mydigitalstructure.add(
	[
		{
			name: 'learn-example-4-mydigitalstructure.cloud-retrieve-contacts',
			code: function (param)
			{
				mydigitalstructure.cloud.retrieve(
				{
					object: 'contact_person',
					fields:
					[
						{name: 'firstname'},
						{name: 'surname'}
					],
					callback: 'learn-example-4-mydigitalstructure.cloud-show-contacts'
				});
			}
		},
		{
			name: 'learn-example-4-mydigitalstructure.cloud-show-contacts',
			note: 'Handles the response from mydigitalstructure.cloud',
			code: function (param, response)
			{
				mydigitalstructure._util.message(
				[
					'-',
					'',
					'LEARN-EXAMPLE #4; Returned JSON Data:',
					response
				]);

				/*
					Invoked here so is called after data is returned from mydigitalstucture.cloud
				*/

				mydigitalstructure.invoke('learn-example-5-mydigitalstructure.cloud-save-contact');
			}
		}
	]);

	mydigitalstructure.invoke('learn-example-4-mydigitalstructure.cloud-retrieve-contacts');

	/*
		[LEARN EXAMPLE #5]
		Save some data to mydigitalstructure.cloud.

		!! Call to mydigitalstructure.cloud is asynchronous so a callback controller needs to be used.
			It then invokes the next example, else it will be invoked before this example is complete.

		!!! mydigitalstructure.cloud will return with error message ""No rights (No Access to method)",
			 to make it work update the settings.json logon & password to be your own,
			 ie. as you use to log on to https://console.mydigitalstructure.cloud.
	*/

	mydigitalstructure.add(
	[
		{
			name: 'learn-example-5-mydigitalstructure.cloud-save-contact',
			code: function (param)
			{
				mydigitalstructure.cloud.save(
				{
					object: 'contact_person',
					fields:
					{
						firstname: 'A',
						surname: 'B'
					},
					callback: 'learn-example-5-mydigitalstructure.cloud-save-contact-confirm'
				});
			}
		},
		{
			name: 'learn-example-5-mydigitalstructure.cloud-save-contact-confirm',
			note: 'Handles the response from mydigitalstructure.cloud',
			code: function (param, response)
			{
				mydigitalstructure._util.message(
				[
					'-',
					'',
					'LEARN-EXAMPLE #5; Returned JSON Data:',
					response
				]);

				mydigitalstructure.invoke('learn-example-6-mydigitalstructure.cloud-retrieve-contacts');
			}
		}
	]);

	/*
		[LEARN EXAMPLE #6]
		Retrieve some data from mydigitalstructure.cloud
		And loop through the return rows and write them to the console.

		It also checks that the response as OK and if not shows the error.

		List of fields and filters @
		https://learn-next.mydigitalstructure.cloud/schema

		To add a filter to search by say firstname add following to code below:
		{
			field: 'firstname',
			comparison: 'EQUAL_TO',
			value: 'John'
		}

		The following example uses the lodash.com _.each() method.

		!! Call to mydigitalstructure.cloud is asynchronous so a callback controller needs to be used.
	*/

	mydigitalstructure.add(
	[
		{
			name: 'learn-example-6-mydigitalstructure.cloud-retrieve-contacts',
			code: function (param)
			{
				mydigitalstructure.cloud.retrieve(
				{
					object: 'contact_person',
					fields:
					[
						{name: 'firstname'},
						{name: 'surname'},
						{name: 'guid'}
					],
					filters:
					[],
					callback: 'learn-example-6-mydigitalstructure.cloud-retrieve-contacts-show'
				});
			}
		},
		{
			name: 'learn-example-6-mydigitalstructure.cloud-retrieve-contacts-show',
			note: 'Handles the response from mydigitalstructure.cloud and shows the contacts or error.',
			code: function (param, response)
			{
				if (response.status == 'ER')
				{
					mydigitalstructure._util.message(
					[
						'-',
						'',
						'LEARN-EXAMPLE #6:',
						'Error Code; ' + response.error.errorcode,
						'Error Notes; ' + response.error.errornotes,
						'Help @ ' + response.error.methodhelp
					]);
				}
				else
				{
					mydigitalstructure._util.message(
					[
						'-',
						'',
						'LEARN-EXAMPLE #6 Data:',
						'-'
					]);

					_.each(response.data.rows, function (row)
					{
						mydigitalstructure._util.message(
						[
							'First name; ' + row.firstname,
							'Surname; ' + row.surname,
							'Unique ID; ' + row.guid,
							'-'
						]);
					});
				}

				mydigitalstructure.invoke('learn-example-7-show-controllers');
			}
		}
	]);

	/*
		[LEARN EXAMPLE #7]
		Show controller code & notes to the terminal (console);
		Process comment line arguments.  You can also use module like yargs.
		In this case will show the controller code of a named controller or if the list of controllers
	*/

	mydigitalstructure.add(
	[
		{
			name: 'learn-example-7-show-controllers',
			code: function (param)
			{
				mydigitalstructure._util.message(
				[
					'',
					'LEARN-EXAMPLE #7, Show Controllers:'
				]);

				if (_.find(process.argv, function (a) {return (a == '/?')}))
				{
					var name = _.find(process.argv, function (a) {return _.includes(a, '/n:')});

					if (name != undefined)
					{
						name = _.replace(name, '/n:', '');
						mydigitalstructure._util.controller.show({name: name});
					}
					else
					{
						mydigitalstructure._util.controller.show()
					}
				}
				else
				{
					mydigitalstructure._util.message(
					[
						'',
						'To show list of controllers add argument: /? e.g. node learn.js /?'
					]);
				}

				mydigitalstructure._util.message(
				[
					'',
					'To show the code for a controller add argument: /n:[name of controller]',
					''
				]);
			}
		}
	])
}<|endoftext|>