<commit_before>'use strict';

import core from 'metal';
import Soy from 'metal-soy';
import { TooltipBase } from 'metal-tooltip';
import templates from './Popover.soy';

/**
 * Popover component. Extends the behavior from `TooltipBase`, adding
 * just some UI to it.
 */
class Popover extends TooltipBase {
	/**
	 * State synchronization logic for `alignElement`. Overrides the original
	 * method from `TooltipBase` so the `content` state can be retrived from
	 * the new aligned element.
	 * @param {Element} alignElement
	 * @param {Element} prevAlignElement
	 * @override
	 */
	syncAlignElement(alignElement) {
		super.syncAlignElement(alignElement);

		if (alignElement) {
			var dataContent = alignElement.getAttribute('data-content');
			if (dataContent) {
				this.content = dataContent;
			}
		}
	}

	/**
	 * State synchronization logic for `visible`. Updates the element's display,
	 * since bootstrap makes it 'none' by default, so we need to change it to
	 * 'block' when the popover becomes visible.
	 * @param {boolean} visible
	 * @override
	 */
	syncVisible(visible) {
		this.element.style.display = visible ? 'block' : '';
		super.syncVisible(visible);
	}
}
Soy.register(Popover, templates);

/**
 * State definition.
 * @type {!Object}
 * @static
 */
Popover.STATE = {
	/**
	 * The popover's content.
	 * @type {string}
	 */
	content: {
		isHtml: true,
		validator: val => core.isString(val) || core.isFunction(val)
	},

	/**
	 * Trigger events used to bind handlers to show and hide popover.
	 * @type {!Array<string>}
	 * @default ['click', 'click']
	 */
	triggerEvents: {
		validator: Array.isArray,
		value: ['click', 'click']
	},

	/**
	 * Flag indicating if an arrow should be rendered for the popover.
	 * @type {boolean}
	 * @default true
	 */
	withArrow: {
		value: true
	}
};

/**
 * @inheritDoc
 * @see `Align` class.
 * @static
 */
Popover.Align = TooltipBase.Align;

export default Popover;
<commit_msg>Adds ".js" extension to soy import to avoid conflicts<commit_after>'use strict';

import core from 'metal';
import Soy from 'metal-soy';
import { TooltipBase } from 'metal-tooltip';
import templates from './Popover.soy.js';

/**
 * Popover component. Extends the behavior from `TooltipBase`, adding
 * just some UI to it.
 */
class Popover extends TooltipBase {
	/**
	 * State synchronization logic for `alignElement`. Overrides the original
	 * method from `TooltipBase` so the `content` state can be retrived from
	 * the new aligned element.
	 * @param {Element} alignElement
	 * @param {Element} prevAlignElement
	 * @override
	 */
	syncAlignElement(alignElement) {
		super.syncAlignElement(alignElement);

		if (alignElement) {
			var dataContent = alignElement.getAttribute('data-content');
			if (dataContent) {
				this.content = dataContent;
			}
		}
	}

	/**
	 * State synchronization logic for `visible`. Updates the element's display,
	 * since bootstrap makes it 'none' by default, so we need to change it to
	 * 'block' when the popover becomes visible.
	 * @param {boolean} visible
	 * @override
	 */
	syncVisible(visible) {
		this.element.style.display = visible ? 'block' : '';
		super.syncVisible(visible);
	}
}
Soy.register(Popover, templates);

/**
 * State definition.
 * @type {!Object}
 * @static
 */
Popover.STATE = {
	/**
	 * The popover's content.
	 * @type {string}
	 */
	content: {
		isHtml: true,
		validator: val => core.isString(val) || core.isFunction(val)
	},

	/**
	 * Trigger events used to bind handlers to show and hide popover.
	 * @type {!Array<string>}
	 * @default ['click', 'click']
	 */
	triggerEvents: {
		validator: Array.isArray,
		value: ['click', 'click']
	},

	/**
	 * Flag indicating if an arrow should be rendered for the popover.
	 * @type {boolean}
	 * @default true
	 */
	withArrow: {
		value: true
	}
};

/**
 * @inheritDoc
 * @see `Align` class.
 * @static
 */
Popover.Align = TooltipBase.Align;

export default Popover;
<|endoftext|>


<commit_before>/*! @license ©2016 Ruben Taelman - Multimedia Lab / iMinds / Ghent University */

/** A CompositeDatasource delegates queries to an consecutive list of datasources. */

var Datasource = require('./Datasource');

// Creates a new CompositeDatasource
function CompositeDatasource(options) {
  if (!(this instanceof CompositeDatasource))
    return new CompositeDatasource(options);
  Datasource.call(this, options);

  if (!options.references) {
    throw new Error("A CompositeDatasource requires a `references` array of datasource id's in its settings.");
  }

  var allDatasources = options.datasources;
  this._datasources = {};
  this._datasourceNames = [];
  for (var i = 0; i < options.references.length; i++) {
    var datasourceName = options.references[i];
    var datasource = allDatasources[datasourceName];
    if (!datasource) {
      throw new Error("No datasource " + datasourceName + " could be found!");
    }
    if (datasource.enabled === false) {
      throw new Error("Datasource " + datasourceName + " must be enabled!");
    }
    this._datasources[datasourceName] = datasource;
    this._datasourceNames.push(datasourceName);
  }
}
Datasource.extend(CompositeDatasource);

// Checks whether the data source can evaluate the given query
CompositeDatasource.prototype.supportsQuery = function (query) {
  for (var datasourceName in this._datasources) {
    if (this._getDatasourceByName(datasourceName).supportsQuery(query)) {
      return true;
    }
  }
  return false;
};

// Find a datasource by datasource name
CompositeDatasource.prototype._getDatasourceByName = function(datasourceName) {
  return this._datasources[datasourceName].datasource;
};

// Find a datasource by datasource id inside this composition
CompositeDatasource.prototype._getDatasourceById = function(datasourceIndex) {
  return this._datasources[this._datasourceNames[datasourceIndex]].datasource;
};

// Recursively find all required datasource composition info to perform a query.
// The callback will provide the parameters:
//   Datasource id to start querying from
//   The offset to use to start querying from the given datasource id
//   The total count for all datasources
CompositeDatasource.prototype._getDatasourceInfo = function(query, absoluteOffset, cb) {
  var self = this;
  var emptyQuery = {
    offset: 0, limit: 1,
    subject: query.subject, predicate: query.predicate, object: query.object
  };
  return findRecursive(0, absoluteOffset, -1, -1, 0, cb);

  function findRecursive(datasourceIndex, offset, chosenDatasource, chosenOffset, totalCount) {
    if (datasourceIndex >= self._datasourceNames.length) {
      // We checked all datasources, return our accumulated information
      cb(chosenDatasource, chosenOffset, totalCount);
    } else {
      var emptyTripleStream = { push: noop };
      self._getDatasourceById(datasourceIndex)._executeQuery(emptyQuery, emptyTripleStream, function (metadata) {
        var count = metadata.totalCount;
        if (chosenDatasource < 0 && offset < count) {
          // We can start querying from this datasource
          setImmediate(function () {
            findRecursive(datasourceIndex + 1, offset - count, datasourceIndex, offset, totalCount + count);
          });
        } else {
          // We forward our accumulated information and go check the next datasource
          setImmediate(function () {
            findRecursive(datasourceIndex + 1, offset - count, chosenDatasource, chosenOffset, totalCount + count);
          });
        }
      });
    }
  }
};

function noop() {}

// Writes the results of the query to the given triple stream
CompositeDatasource.prototype._executeQuery = function (query, tripleStream, metadataCallback) {
  var offset =  query.offset || 0, limit = query.limit || Infinity;
  var self = this;
  this._getDatasourceInfo(query, offset, function(datasourceIndex, relativeOffset, totalCount) {
    if (datasourceIndex < 0) {
      // No valid datasource has been found
      metadataCallback({ totalCount: totalCount });
      tripleStream.push(null);
    } else {
      // Send query to first applicable datasource and optionally emit triples from consecutive datasources
      metadataCallback({ totalCount: totalCount });
      var emitted = 0;

      // Modify our triple stream so that if all results from one datasource have arrived,
      // check if we haven't reached the limit and if so, trigger a new query for the next datasource.
      tripleStream.push = makeSmartPush(tripleStream, function(localEmittedCount) {
        // This is called after the last element has been pushed

        // If we haven't reached our limit, try to fill it with other datasource query results.
        emitted += localEmittedCount;
        datasourceIndex++;
        if (emitted < limit && datasourceIndex < self._datasourceNames.length) {
          var localLimit = limit - emitted;
          var subQuery = { offset: 0, limit: localLimit,
            subject: query.subject, predicate: query.predicate, object: query.object };
          self._getDatasourceById(datasourceIndex)._executeQuery(subQuery, tripleStream, function(){});
          return true;
        } else {
          return false;
        }
      });

      // Initiate query to the first datasource.
      var subQuery = { offset: relativeOffset, limit: limit,
        subject: query.subject, predicate: query.predicate, object: query.object };
      self._getDatasourceById(datasourceIndex)._executeQuery(subQuery, tripleStream, function(){});
    }
  });

  // Replaces a tripleStream.push
  // It takes the tripleStream as first argument and a callback as second argument.
  // The callback will be called when the push function is called with a falsy value.
  // Returning a falsy value inside the callback will delegate the falsy value to the original
  // push function anyways.
  function makeSmartPush(self, nullCb) {
    var count = 0;
    var originalPush = self.push;
    return function(element) {
      if (!element) {
        if(!nullCb(count)) {
          originalPush.call(self, element);
        }
      } else {
        count++;
        originalPush.call(self, element);
      }
    };
  }
};

module.exports = CompositeDatasource;
<commit_msg>Allow composed datasources to be disabled<commit_after>/*! @license ©2016 Ruben Taelman - Multimedia Lab / iMinds / Ghent University */

/** A CompositeDatasource delegates queries to an consecutive list of datasources. */

var Datasource = require('./Datasource');

// Creates a new CompositeDatasource
function CompositeDatasource(options) {
  if (!(this instanceof CompositeDatasource))
    return new CompositeDatasource(options);
  Datasource.call(this, options);

  if (!options.references) {
    throw new Error("A CompositeDatasource requires a `references` array of datasource id's in its settings.");
  }

  var allDatasources = options.datasources;
  this._datasources = {};
  this._datasourceNames = [];
  for (var i = 0; i < options.references.length; i++) {
    var datasourceName = options.references[i];
    var datasource = allDatasources[datasourceName];
    if (!datasource) {
      throw new Error("No datasource " + datasourceName + " could be found!");
    }
    if (datasource.enabled !== false) {
      this._datasources[datasourceName] = datasource;
      this._datasourceNames.push(datasourceName);
    }
  }
}
Datasource.extend(CompositeDatasource);

// Checks whether the data source can evaluate the given query
CompositeDatasource.prototype.supportsQuery = function (query) {
  for (var datasourceName in this._datasources) {
    if (this._getDatasourceByName(datasourceName).supportsQuery(query)) {
      return true;
    }
  }
  return false;
};

// Find a datasource by datasource name
CompositeDatasource.prototype._getDatasourceByName = function(datasourceName) {
  return this._datasources[datasourceName].datasource;
};

// Find a datasource by datasource id inside this composition
CompositeDatasource.prototype._getDatasourceById = function(datasourceIndex) {
  return this._datasources[this._datasourceNames[datasourceIndex]].datasource;
};

// Recursively find all required datasource composition info to perform a query.
// The callback will provide the parameters:
//   Datasource id to start querying from
//   The offset to use to start querying from the given datasource id
//   The total count for all datasources
CompositeDatasource.prototype._getDatasourceInfo = function(query, absoluteOffset, cb) {
  var self = this;
  var emptyQuery = {
    offset: 0, limit: 1,
    subject: query.subject, predicate: query.predicate, object: query.object
  };
  return findRecursive(0, absoluteOffset, -1, -1, 0, cb);

  function findRecursive(datasourceIndex, offset, chosenDatasource, chosenOffset, totalCount) {
    if (datasourceIndex >= self._datasourceNames.length) {
      // We checked all datasources, return our accumulated information
      cb(chosenDatasource, chosenOffset, totalCount);
    } else {
      var emptyTripleStream = { push: noop };
      self._getDatasourceById(datasourceIndex)._executeQuery(emptyQuery, emptyTripleStream, function (metadata) {
        var count = metadata.totalCount;
        if (chosenDatasource < 0 && offset < count) {
          // We can start querying from this datasource
          setImmediate(function () {
            findRecursive(datasourceIndex + 1, offset - count, datasourceIndex, offset, totalCount + count);
          });
        } else {
          // We forward our accumulated information and go check the next datasource
          setImmediate(function () {
            findRecursive(datasourceIndex + 1, offset - count, chosenDatasource, chosenOffset, totalCount + count);
          });
        }
      });
    }
  }
};

function noop() {}

// Writes the results of the query to the given triple stream
CompositeDatasource.prototype._executeQuery = function (query, tripleStream, metadataCallback) {
  var offset =  query.offset || 0, limit = query.limit || Infinity;
  var self = this;
  this._getDatasourceInfo(query, offset, function(datasourceIndex, relativeOffset, totalCount) {
    if (datasourceIndex < 0) {
      // No valid datasource has been found
      metadataCallback({ totalCount: totalCount });
      tripleStream.push(null);
    } else {
      // Send query to first applicable datasource and optionally emit triples from consecutive datasources
      metadataCallback({ totalCount: totalCount });
      var emitted = 0;

      // Modify our triple stream so that if all results from one datasource have arrived,
      // check if we haven't reached the limit and if so, trigger a new query for the next datasource.
      tripleStream.push = makeSmartPush(tripleStream, function(localEmittedCount) {
        // This is called after the last element has been pushed

        // If we haven't reached our limit, try to fill it with other datasource query results.
        emitted += localEmittedCount;
        datasourceIndex++;
        if (emitted < limit && datasourceIndex < self._datasourceNames.length) {
          var localLimit = limit - emitted;
          var subQuery = { offset: 0, limit: localLimit,
            subject: query.subject, predicate: query.predicate, object: query.object };
          self._getDatasourceById(datasourceIndex)._executeQuery(subQuery, tripleStream, function(){});
          return true;
        } else {
          return false;
        }
      });

      // Initiate query to the first datasource.
      var subQuery = { offset: relativeOffset, limit: limit,
        subject: query.subject, predicate: query.predicate, object: query.object };
      self._getDatasourceById(datasourceIndex)._executeQuery(subQuery, tripleStream, function(){});
    }
  });

  // Replaces a tripleStream.push
  // It takes the tripleStream as first argument and a callback as second argument.
  // The callback will be called when the push function is called with a falsy value.
  // Returning a falsy value inside the callback will delegate the falsy value to the original
  // push function anyways.
  function makeSmartPush(self, nullCb) {
    var count = 0;
    var originalPush = self.push;
    return function(element) {
      if (!element) {
        if(!nullCb(count)) {
          originalPush.call(self, element);
        }
      } else {
        count++;
        originalPush.call(self, element);
      }
    };
  }
};

module.exports = CompositeDatasource;
<|endoftext|>


<commit_before>$(document).ready(function () {
    var sessionId = $("#hidden").val();

    $("select").chosen();

    $(document).on("click", ".chosen-choices", function (e) {
        if ($(".search-field").length < 1) {
            $(".chosen-choices").append("
<input type=\"text\" value=\"\" class=\"default\" autocomplete=\"off\" style=\"width: 100%;\">
");
        }
        $(".search-field .default").focus();
    });

    $(document).on("click", ".result-selected", function (e) {
        $(".chosen-results").empty();
        $(".chosen-choices").append("
" + $(this).text() + "
");
        $(".search-field").remove();
    });

    $(document).on("focus", ".search-field .default", function () {
        if ($(".chosen-drop").length == 0) {
            $("#body_UserList_chosen").append("

");
        }
        $(".no-results").remove();
        $(".chosen-results").append("
Почніть вводити одержувача...
");
    });

    $(document).on("focusout", ".search-field .default", function () {
        $(".chosen-drop").remove();
    });

    $(document).on("keyup", ".search-field .default", function () {
        if (!$(this).val()) {
            $(".no-results").remove();
            $(".chosen-results").append("
Почніть вводити одержувача...
");
        }
        if ($(this).val().length >= 2) {
            $(".chosen-results").empty();
            var text = $(this).val();
            var url = "http://api.ecampus.kpi.ua/User/GetAllUsers?name=" + text + "&sessionId=" + sessionId;
            $.getJSON(url, function (data, status) {
                if (data.Data.length > 0) {
                    $.each(data.Data, function (key, value) {
                        var newItem = "" + value.UserAccountId;
                        var same = "false";
                        var sameCh = "false";
                        $.each($(".chosen-results").children(), function () {
                            if ($(this).attr("uid") === newItem) {
                                same = "true";
                                return (same != "false");
                            }
                        });
                        $.each($(".search-choice"), function () {
                            if ($(this).attr("uid") === newItem) {
                                sameCh = "true";
                                return (sameCh != "false");
                            }
                        });

                        if (same === "false" && sameCh === "false") {
                            $(".chosen-results").append("
" + value.FullName + "
");
                        } else {
                            $(".no-results").remove();
                            $(".chosen-results").append("
Немає співпадінь \"" + $(".search-field input").val() + "\"
");
                        }
                    });
                } else {
                    $(".no-results").remove();
                    $(".chosen-results").append("
Немає співпадінь \"" + $(".search-field input").val() + "\"
");
                };

            });

        } else if ($(this).val().length == 1) {
            $(".no-results").remove();
            $(".active-result").remove();
            $(".chosen-results").append("
Однієї літери замало \"" + $(".search-field input").val() + "\"
");
        }
    });

    $(document).on("click", ".search-choice-close", function (e) {
        $(this).parent().remove();
    });

    $(document).on("focusout", ".search-field", function (e) {
        if ($(".search-choice").length > 0) $(".search-field").remove();
    });

    $(document).on("click", "#SendMessage", function (e) {
        if ($("#body_Text").val() != "" && $(".search-choice").length > 0) {
            var userList = "";
            $.each($(".search-choice"), function (index, value) {
                if (index != $(".search-choice").length - 1) userList += $(this).attr("uid") + ",";
                else userList += $(this).attr("uid");
            });
            var url = "http://api.ecampus.kpi.ua/Message/CreateGroup?sessionId=" + sessionId + "&userIdList=" + userList + "&name=" + $("#body_Subject").val();
            $.getJSON(url, function (data, status) {
                url = "http://api.ecampus.kpi.ua/message/SendMessage?sessionId=" + sessionId + "&groupId=" + data.Data + "&text=" + $("#body_Text").val() + "&subject=" + $("#body_Subject").val();
                $.getJSON(url, function (data, status) {
                    console.log(status);
                    alert("Діалог створено, повідомленні розіслано!");
                    $(".chosen-choices").empty();
                    $(".chosen-choices").append("
<input type=\"text\" value=\"Оберіть одержувачів\" class=\"default\" autocomplete=\"off\" style=\"width: 100%;\">
");
                    $("#body_Subject").val("");
                    $("#body_Text").val("");
                });
            });

        } else alert("Заповніть отримувачів та текст повідомлення!");
    });

});
<commit_msg>chosen problem fixed<commit_after>$(document).ready(function () {
    var sessionId = $("#hidden").val();

    $("select").chosen();

    $(document).on("click", ".chosen-choices", function (e) {
        if ($(".search-field").length < 1) {
            $(".chosen-choices").append("
<input type=\"text\" value=\"\" class=\"default\" autocomplete=\"off\" style=\"width: 100%;\">
");
        }
        $(".search-field .default").focus();
    });

    $(document).on("click", ".result-selected", function (e) {
        $(".chosen-results").empty();
        $(".chosen-choices").append("
" + $(this).text() + "
");
        $(".search-field").remove();
        //$(".chosen-drop").remove();
    });

    $(document).on("focus", ".search-field .default", function () {
        //if ($(".chosen-drop").length == 0) {
        //    $("#body_UserList_chosen").append("

");
        //}
        $(".no-results").remove();
        $(".chosen-results").append("
Почніть вводити одержувача...
");
    });

    $(document).on("focusout", ".search-field .default", function () {
        //$(".chosen-drop").remove();
    });

    $(document).on("keyup", ".search-field .default", function () {
        if (!$(this).val()) {
            $(".no-results").remove();
            $(".chosen-results").append("
Почніть вводити одержувача...
");
        }
        if ($(this).val().length >= 2) {
            $(".chosen-results").empty();
            var text = $(this).val();
            var url = "http://api.ecampus.kpi.ua/User/GetAllUsers?name=" + text + "&sessionId=" + sessionId;
            $.getJSON(url, function (data, status) {
                if (data.Data.length > 0) {
                    $.each(data.Data, function (key, value) {
                        var newItem = "" + value.UserAccountId;
                        var same = "false";
                        var sameCh = "false";
                        $.each($(".chosen-results").children(), function () {
                            if ($(this).attr("uid") === newItem) {
                                same = "true";
                                return (same != "false");
                            }
                        });
                        $.each($(".search-choice"), function () {
                            if ($(this).attr("uid") === newItem) {
                                sameCh = "true";
                                return (sameCh != "false");
                            }
                        });

                        if (same === "false" && sameCh === "false") {
                            $(".chosen-results").append("
" + value.FullName + "
");
                        } else {
                            $(".no-results").remove();
                            $(".chosen-results").append("
Немає співпадінь \"" + $(".search-field input").val() + "\"
");
                        }
                    });
                } else {
                    $(".no-results").remove();
                    $(".chosen-results").append("
Немає співпадінь \"" + $(".search-field input").val() + "\"
");
                };

            });

        } else if ($(this).val().length == 1) {
            $(".no-results").remove();
            $(".active-result").remove();
            $(".chosen-results").append("
Однієї літери замало \"" + $(".search-field input").val() + "\"
");
        }
    });

    $(document).on("click", ".search-choice-close", function (e) {
        $(this).parent().remove();
    });

    $(document).on("focusout", ".search-field", function (e) {
        if ($(".search-choice").length > 0) $(".search-field").remove();
    });

    $(document).on("click", "#SendMessage", function (e) {
        if ($("#body_Text").val() != "" && $(".search-choice").length > 0) {
            var userList = "";
            $.each($(".search-choice"), function (index, value) {
                if (index != $(".search-choice").length - 1) userList += $(this).attr("uid") + ",";
                else userList += $(this).attr("uid");
            });
            var url = "http://api.ecampus.kpi.ua/Message/CreateGroup?sessionId=" + sessionId + "&userIdList=" + userList + "&name=" + $("#body_Subject").val();
            $.getJSON(url, function (data, status) {
                url = "http://api.ecampus.kpi.ua/message/SendMessage?sessionId=" + sessionId + "&groupId=" + data.Data + "&text=" + $("#body_Text").val() + "&subject=" + $("#body_Subject").val();
                $.getJSON(url, function (data, status) {
                    console.log(status);
                    alert("Діалог створено, повідомленні розіслано!");
                    $(".chosen-choices").empty();
                    $(".chosen-choices").append("
<input type=\"text\" value=\"Оберіть одержувачів\" class=\"default\" autocomplete=\"off\" style=\"width: 100%;\">
");
                    $("#body_Subject").val("");
                    $("#body_Text").val("");
                });
            });

        } else alert("Заповніть отримувачів та текст повідомлення!");
    });

});
<|endoftext|>


<commit_before>let fs = require('fs');
let path = require('path');
let PriorityQueue = require('priorityqueuejs');
import {addUser, addQuestion, addAnswer, addTag, getQuestionsStream, getAnswers, uninitDB} from './datastore.js';
let strict = true;

const siteSlug = process.argv[2];
const siteSlugTemp = siteSlug  + '-temp';
const baseLang = 'en';
const usersXml = path.join('./data', siteSlug, 'Users.xml');
const postsXml = path.join('./data', siteSlug, 'Posts.xml');
const tagsXml = path.join('./data', siteSlug, 'Tags.xml');

const maxQuestions = 20;

let pq = new PriorityQueue((a, b) => b.weight - a.weight);

let parseFile = (filePath, onOpenTag) => {
  return new Promise((resolve, reject) => {
    var saxStream = require('sax').createStream(strict, {});
    let promises = [];
    saxStream.on('error', (e) => {
      // unhandled errors will throw, since this is a proper node
      // event emitter.
      console.error('error!', e);
      // clear the error
      //this._parser.error = null
      //this._parser.resume()
      reject(e);
    });

    saxStream.on('opentag', (node) => {
      if (node.name !== 'row') {
        return;
      }
      let p = onOpenTag(node);
      if (p) {
        promises.push(p);
      }
    });

    saxStream.on('end', () => {
      // parser stream is done, and ready to have more stuff written to it.
      console.log('waiting for all promises for file:', filePath);
      Promise.all(promises).then(resolve).catch((err) => console.error('Promise.all err is: ', err));
    });

    fs.createReadStream(filePath)
      .pipe(saxStream);
  });
};

export let parseUsers = parseFile.bind(null, usersXml, (node) => {
  let user = {
    id: node.attributes.Id,
    //reputation: Number(node.attributes.Reputation),
    //creationdate: new Date(node.attributes.CreationDate),
    displayName: node.attributes.DisplayName,
    //lastAccessDate: new Date(node.attributes.LastAccessDate),
    websiteUrl: node.attributes.websiteUrl,
    location: node.attributes.Location,
    aboutMe: node.attributes.AboutMe,
    //views: Number(node.attributes.Views),
    //upVotes: Number(node.attributes.UpVotes),
    //downVotes: Number(node.attributes.DownVotes),
    //emailHash: node.attributes.EmailHash,
    //accountId: node.attributes.AccountId,
    profileImageUrl: node.attributes.ProfileImageUrl,
    age: node.attributes.age,
  };
  if (!user.id) {
    console.warn('user has blanks for user: ', user);
    return Promise.resolve();
  }

  console.log('add user:', user);
  return addUser(siteSlugTemp, user).catch((err) => {
    console.error(`Could not add user id: ${user.id}, err: ${err}`);
  });
});

export let parseQuestions = parseFile.bind(null, postsXml, (node) => {
  let data = {
    id: node.attributes.Id,
    postTypeId: Number(node.attributes.PostTypeId),
    //creationDate: new Date(node.attributes.CreationDate),
    score: Number(node.attributes.Score),
    viewCount: Number(node.attributes.ViewCount),
    body: node.attributes.Body,
    ownerUserId: node.attributes.OwnerUserId,
    // Data dump doesn't always include this field!
    // ownerDisplayName: node.attributes.OwnerDisplayName,
    //lastEditorUserId: node.attributes.LastEditorUserId,
    lastEditDate: new Date(node.attributes.LastEditDate),
    //lastActivityDate: new Date(node.attributes.LastActivityDate),
    title: node.attributes.Title,
    tags: node.attributes.Tags,
    //answerCount: Number(node.attributes.AnswerCount),
    //commentCount: Number(node.attributes.CommentCount),
    //favoriteCount: Number(node.attributes.favoriteCount),
    //communityOwnedDate: new Date(node.attributes.CommunityOwnedDate),
  };

  if (node.attributes.ClosedDate) {
    data.closedDate = new Date(node.attributes.ClosedDate);
  }

  if (data.postTypeId === 1) {
    data.acceptedAnswerId = node.attributes.AcceptedAnswerId;
    if (!data.id) {
      console.warn('question has blanks for question: ', data);
      return;
    }
    return addQuestion(siteSlugTemp, data).catch((err) => {
      console.error(`Could not add question: ${data.id}: ${err}`);
    });
  } else if (data.postTypeId === 2) {
    data.parentId = node.attributes.ParentId;
    if (!data.id || !data.parentId) {
      console.warn('answer has blanks for answer: ', data);
      return;
    }
    return addAnswer(siteSlugTemp, data).catch((err) => {
      console.error(`Could not add answer for question: ${data.parentId}: ${err}`);
    });
  }
});

export let parseTags = parseFile.bind(null, tagsXml, (node) => {
  let tag = {
    id: node.attributes.Id,
    tagName: node.attributes.TagName,
    count: node.attributes.Count,
    excerptPostId: node.attributes.ExcerptPostId,
    wikiPostId: node.attributes.WikiPostId,
  };

  if (!tag.tagName) {
    console.warn('tagName is blank for tag: ', tag);
    return;
  }

  // For whatever reason the other dumps reference tags by their tagName, so index that way
  console.log('Adding tag for tag:', tag);
  return addTag(siteSlugTemp, tag).catch((err) => {
    console.error(`Could not add tagName: ${tag.tagName}: ${err}`);
  });
});

function queueQuestion(question) {
  pq.enq(question);
  if (pq.size() > maxQuestions) {
    pq.deq();
  }
}

export let selectBestAnswersAndWeigh = () => {
  return new Promise((resolve, reject) => {
    let promises = [];
    promises.push(getQuestionsStream(siteSlugTemp, baseLang, question => {
      promises.push(getAnswers(siteSlugTemp, baseLang, question.id).then(answers => {
        // Create a PQ for weighing all the answers to find the best one
        let answersPQ = new PriorityQueue((a, b) => {
          if (question.acceptedAnswerId === a.id) {
            return 1;
          }
          if (question.acceptedAnswerId === b.id) {
            return -1;
          }
          return a.score - b.score;
        });

        let wordCount = question.title.split(' ').length + question.body.split(' ').length;

        // Now add all answers to a PQ to get the best one
        answers.forEach(answer => answersPQ.enq(answer));
        if (answers.length > 0) {
          let bestAnswer = answersPQ.deq();
          wordCount += bestAnswer.body.split(' ').length;
          question.bestAnswerId = bestAnswer.id;
        }
        question.weight = question.ViewCount * 0.01 * 0.25 - wordCount * 0.12;
        queueQuestion(question);
      }));
    }));
    Promise.all(promises).then(resolve).catch(reject);
  });
};

parseUsers().then(parseQuestions).then(parseTags).then(selectBestAnswersAndWeigh).then(uninitDB).catch(err => {
  console.log('pq size is: ', pq.size());
  console.error('top err: ', err);
});
<commit_msg>Keep best questions in a db<commit_after>let fs = require('fs');
let path = require('path');
let PriorityQueue = require('priorityqueuejs');
import {addUser, addQuestion, addAnswer, addTag, getQuestionsStream, getAnswers, setStats, uninitDB} from './datastore.js';
let strict = true;

const siteSlug = process.argv[2];
const siteSlugTemp = siteSlug  + '-temp';
const baseLang = 'en';
const usersXml = path.join('./data', siteSlug, 'Users.xml');
const postsXml = path.join('./data', siteSlug, 'Posts.xml');
const tagsXml = path.join('./data', siteSlug, 'Tags.xml');

const maxQuestions = 20;
const usersPerPage = 5;
const questionsPerPage = 5;

let tagMap = new Map();
let bestAnswerIdSet = new Set();
let userIdSet = new Set();
let questionIdSet = new Set();

let questionWordCount = 0;
let answerWordCount = 0;
let userWordCount = 0;
let questionViews = 0;

let pq = new PriorityQueue((a, b) => b.weight - a.weight);

let parseFile = (filePath, onOpenTag) => {
  return new Promise((resolve, reject) => {
    var saxStream = require('sax').createStream(strict, {});
    let promises = [];
    saxStream.on('error', (e) => {
      // unhandled errors will throw, since this is a proper node
      // event emitter.
      console.error('error!', e);
      // clear the error
      //this._parser.error = null
      //this._parser.resume()
      reject(e);
    });

    saxStream.on('opentag', (node) => {
      if (node.name !== 'row') {
        return;
      }
      let p = onOpenTag(node);
      if (p) {
        promises.push(p);
      }
    });

    saxStream.on('end', () => {
      // parser stream is done, and ready to have more stuff written to it.
      console.log('waiting for all promises for file:', filePath);
      Promise.all(promises).then(resolve).catch((err) => console.error('Promise.all err is: ', err));
    });

    fs.createReadStream(filePath)
      .pipe(saxStream);
  });
};

export let parseUsers = parseFile.bind(null, usersXml, (node) => {
  let user = {
    id: node.attributes.Id,
    //reputation: Number(node.attributes.Reputation),
    //creationdate: new Date(node.attributes.CreationDate),
    displayName: node.attributes.DisplayName,
    //lastAccessDate: new Date(node.attributes.LastAccessDate),
    websiteUrl: node.attributes.websiteUrl,
    location: node.attributes.Location,
    aboutMe: node.attributes.AboutMe,
    //views: Number(node.attributes.Views),
    //upVotes: Number(node.attributes.UpVotes),
    //downVotes: Number(node.attributes.DownVotes),
    //emailHash: node.attributes.EmailHash,
    //accountId: node.attributes.AccountId,
    profileImageUrl: node.attributes.ProfileImageUrl,
    age: node.attributes.age,
  };
  if (!user.id) {
    console.warn('user has blanks for user: ', user);
    return Promise.resolve();
  }

  console.log('add user:', user);
  return addUser(siteSlugTemp, user).catch((err) => {
    console.error(`Could not add user id: ${user.id}, err: ${err}`);
  });
});

export let parseQuestions = parseFile.bind(null, postsXml, (node) => {
  let data = {
    id: node.attributes.Id,
    postTypeId: Number(node.attributes.PostTypeId),
    //creationDate: new Date(node.attributes.CreationDate),
    score: Number(node.attributes.Score),
    viewCount: Number(node.attributes.ViewCount),
    body: node.attributes.Body,
    ownerUserId: node.attributes.OwnerUserId,
    // Data dump doesn't always include this field!
    // ownerDisplayName: node.attributes.OwnerDisplayName,
    //lastEditorUserId: node.attributes.LastEditorUserId,
    lastEditDate: new Date(node.attributes.LastEditDate),
    //lastActivityDate: new Date(node.attributes.LastActivityDate),
    title: node.attributes.Title,
    tags: node.attributes.Tags,
    //answerCount: Number(node.attributes.AnswerCount),
    //commentCount: Number(node.attributes.CommentCount),
    //favoriteCount: Number(node.attributes.favoriteCount),
    //communityOwnedDate: new Date(node.attributes.CommunityOwnedDate),
  };

  if (node.attributes.ClosedDate) {
    data.closedDate = new Date(node.attributes.ClosedDate);
  }

  if (data.postTypeId === 1) {
    data.acceptedAnswerId = node.attributes.AcceptedAnswerId;
    if (!data.id) {
      console.warn('question has blanks for question: ', data);
      return;
    }
    return addQuestion(siteSlugTemp, data).catch((err) => {
      console.error(`Could not add question: ${data.id}: ${err}`);
    });
  } else if (data.postTypeId === 2) {
    data.parentId = node.attributes.ParentId;
    if (!data.id || !data.parentId) {
      console.warn('answer has blanks for answer: ', data);
      return;
    }
    return addAnswer(siteSlugTemp, data).catch((err) => {
      console.error(`Could not add answer for question: ${data.parentId}: ${err}`);
    });
  }
});

export let parseTags = parseFile.bind(null, tagsXml, (node) => {
  let tag = {
    id: node.attributes.Id,
    tagName: node.attributes.TagName,
    count: node.attributes.Count,
    excerptPostId: node.attributes.ExcerptPostId,
    wikiPostId: node.attributes.WikiPostId,
  };

  if (!tag.tagName) {
    console.warn('tagName is blank for tag: ', tag);
    return;
  }

  // For whatever reason the other dumps reference tags by their tagName, so index that way
  console.log('Adding tag for tag:', tag);
  return addTag(siteSlugTemp, tag).catch((err) => {
    console.error(`Could not add tagName: ${tag.tagName}: ${err}`);
  });
});

function queueQuestion(question) {
  pq.enq(question);
  if (pq.size() > maxQuestions) {
    pq.deq();
  }
}

export let selectBestAnswersAndWeigh = () => {
  return new Promise((resolve, reject) => {
    let promises = [];
    promises.push(getQuestionsStream(siteSlugTemp, baseLang, question => {
      promises.push(getAnswers(siteSlugTemp, baseLang, question.id).then(answers => {
        // Create a PQ for weighing all the answers to find the best one
        let answersPQ = new PriorityQueue((a, b) => {
          if (question.acceptedAnswerId === a.id) {
            return 1;
          }
          if (question.acceptedAnswerId === b.id) {
            return -1;
          }
          return a.score - b.score;
        });

        let wordCount = question.title.split(' ').length + question.body.split(' ').length;

        // Now add all answers to a PQ to get the best one
        answers.forEach(answer => answersPQ.enq(answer));
        if (answers.length > 0) {
          let bestAnswer = answersPQ.deq();
          wordCount += bestAnswer.body.split(' ').length;
          question.bestAnswerId = bestAnswer.id;
        }
        question.weight = question.ViewCount * 0.01 * 0.25 - wordCount * 0.12;
        queueQuestion(question);
      }));
    }));
    Promise.all(promises).then(resolve).catch(reject);
  });
};

export let insertBestQuestions = () => {
  return new Promise((resolve, reject) => {
    let promises = [];
    let addTagFn = tagName => {
      let tagCount = 0;
      if (tagMap.has(tagName)) {
        tagCount = tagMap.get(tagName);
      }
      tagMap.set(tagName, tagCount + 1);
    };

    while (!pq.isEmpty()) {
      let question = pq.deq();
      questionIdSet.add(question.id);
      if (question.ownerUserId) {
        userIdSet.add(question.ownerUserId);
      } else {
        console.warn('null user specified for question:', question);
      }
      if (question.acceptedAnswerId) {
        bestAnswerIdSet.add(question.bestAnswerId);
      }
      if (question.tags) {
        // Split up tags like <tag1><tag2><tag3> into an array of strings iwth the tag names
        // Do this by replacing the starting < and the ending > with nothing, then split on the middle ><
        question.tags = question.tags.replace(/^</, '').replace(/>$/, '').split('><');
        question.tags.forEach(addTagFn);
      }

      questionWordCount += question.title.split(' ').length + question.body.split(' ').length;
      if (question.viewCount) {
        questionViews += question.viewCount;
      }

      // Add in the page for per page querying
      question.page = Math.ceil(questionIdSet.size / questionsPerPage);
      promises.push(addQuestion(siteSlug, question));
    }
    console.log('waiting for all questions to insert');
    Promise.all(promises).then(resolve).catch(reject);
  });
};

export let insertAnswers = () => {
  // TODO
};

export let insertUsers = () => {
  // TODO
};

export let insertTags = () => {
  // TODO
};

export let insertStats = () => {
  let stats = {
    userCount: userIdSet.size,
    tagCount: tagMap.size,
    questionCount: questionIdSet.size,
    questionWordCount,
    answerWordCount,
    userWordCount,
    questionViews,
  };
  console.log('Stats:', stats);
  return setStats(siteSlug, stats);
};

parseUsers()
  .then(parseQuestions)
  .then(parseTags)
  .then(selectBestAnswersAndWeigh)
  .then(insertBestQuestions)
  .then(insertAnswers)
  .then(insertUsers)
  .then(insertTags)
  .then(insertStats)
  .then(uninitDB)
  .then(() => {
  console.log('pq size is: ', pq.size());
}).catch(err => {
  console.error('top err: ', err);
});
<|endoftext|>


<commit_before>/*jshint esversion: 6 */

/*
  Manage Menu View to select and unselect proposition of element/link
*/
var AskomicsMenuView = function () {

  AskomicsMenuView.prototype.buildLiView = function(uri,submenu) {

    var icheck = $("")
        .attr("class","glyphicon glyphicon-check");

    var a = $("")
            .attr("href","#")
            .attr("class","small")
            .attr("data-value","option1")
            .attr("tabIndex","-1") ;
    if (submenu) {
      a.html($("").append(" "+userAbstraction.removePrefix(uri)+" ")).append(icheck);
    } else {
      a.html($("").append(userAbstraction.removePrefix(uri)+" ")).append(icheck);
    }
    var li = $("

");
    li.attr("uri",uri);
    li.css("display","table-cell");
    li.css("vertical-align","middle");
    li.append(a);
    return li;
  };

  /* initialize the view. The abstraction have to be done */
  AskomicsMenuView.prototype.start = function(node) {
    menuView = this;

    $("#viewListNodesAndLinks").css("display","table-row");

    //
<input type="checkbox"/> Option 1

    lentities = userAbstraction.getEntities();

    $.each(lentities, function(i) {
      nodeuri = lentities[i];
      var li = menuView.buildLiView(nodeuri,false);
      li.on('click', function() {
        var span = $(this).find(".glyphicon");
        var cur_uri = $(this).attr("uri");
        if ( span.css("visibility") == "visible" ) {
          span.css("visibility","hidden");
          forceLayoutManager.offProposedUri("node",cur_uri);
          // disable all predicate associated with this node
          $(this).parent().parent().find("li[nodeuri='"+cur_uri+"']").attr("class","disabled");
        } else {
          span.css("visibility","visible");
          forceLayoutManager.onProposedUri("node",cur_uri);
          // enable all predicate associated with this node
          $(this).parent().parent().find("li[nodeuri='"+cur_uri+"']").removeAttr("class");
        }
        // remove old suggestion
        forceLayoutManager.removeSuggestions();
        // insert new suggestion
        forceLayoutManager.insertSuggestions();
        // regenerate the graph
        forceLayoutManager.update();
      });
      $("#viewListNodesAndLinks").append(li);
      /* --------------------------- */
      /* Adding filter on relations  */
      /* --------------------------- */
      var tab = userAbstraction.getRelationsObjectsAndSubjectsWithURI(nodeuri);
      var listRelObj = tab[0];

      $.each(listRelObj, function(objecturi) {
        $.each(listRelObj[objecturi], function(idxrel) {
          var rel = listRelObj[objecturi][idxrel];
          var li = menuView.buildLiView(rel,true);
          li.attr("nodeuri",nodeuri)
            .on('click', function() {
              var span = $(this).find(".glyphicon");
              var cur_uri = $(this).attr("uri");
              if ( span.css("visibility") == "visible" ) {
               span.css("visibility","hidden");
               forceLayoutManager.offProposedUri("link",cur_uri);
              } else {
               span.css("visibility","visible");
               forceLayoutManager.onProposedUri("link",cur_uri);
             }
             /* remove old suggestion */
             forceLayoutManager.removeSuggestions();
             /* insert new suggestion */
             forceLayoutManager.insertSuggestions();
             /* regenerate the graph */
             forceLayoutManager.update();
          });
          $("#viewListNodesAndLinks").append(li);
        });
      });
      $("#viewListNodesAndLinks").append($("

").attr("class","divider"));
      /* next entity */
    });

    positionableEntities = userAbstraction.getPositionableEntities();
    if (Object.keys(positionableEntities).length>0) {
      /* positionable object */
      posuri = "positionable";
      var li = menuView.buildLiView(posuri,true);
      li.attr("nodeuri",posuri)
        .on('click', function() {
          var span = $(this).find(".glyphicon");
          var cur_uri = $(this).attr("uri");
          if ( span.css("visibility") == "visible" ) {
            span.css("visibility","hidden");
            forceLayoutManager.offProposedUri("link",cur_uri);
          } else {
            span.css("visibility","visible");
            forceLayoutManager.onProposedUri("link",cur_uri);
          }
          /* remove old suggestion */
          forceLayoutManager.removeSuggestions();
          /* insert new suggestion */
          forceLayoutManager.insertSuggestions();
          /* regenerate the graph */
          forceLayoutManager.update();
        });
        $("#viewListNodesAndLinks").append(li);
        //$("#viewListNodesAndLinks").append($("

").attr("class","divider"));
      }

      var r= $('<input type="button" value="close"/>');
      r.on('click', function() {
        $("#viewListNodesAndLinks").hide();
      });

      var liClose = $("

");
      liClose.css("display","table-cell");
      //liClose.css("vertical-align","right");
      liClose.append(r);
      $("#viewListNodesAndLinks").append(liClose);

  } ;
};
<commit_msg>repair the open and close view menu<commit_after>/*jshint esversion: 6 */

/*
  Manage Menu View to select and unselect proposition of element/link
*/
var AskomicsMenuView = function () {

  AskomicsMenuView.prototype.buildLiView = function(uri,submenu) {

    var icheck = $("")
        .attr("class","glyphicon glyphicon-check");

    var a = $("")
            .attr("href","#")
            .attr("class","small")
            .attr("data-value","option1")
            .attr("tabIndex","-1") ;
    if (submenu) {
      a.html($("").append(" "+userAbstraction.removePrefix(uri)+" ")).append(icheck);
    } else {
      a.html($("").append(userAbstraction.removePrefix(uri)+" ")).append(icheck);
    }
    var li = $("

");
    li.attr("uri",uri);
    li.css("display","table-cell");
    li.css("vertical-align","middle");
    li.append(a);
    return li;
  };

  /* initialize the view. The abstraction have to be done */
  AskomicsMenuView.prototype.start = function(node) {
    menuView = this;

    /* to close the menu when a click event outside */
    $(window).click(function() {
      $("#viewListNodesAndLinks").slideUp();
    });

    $("#buttonViewListNodesAndLinks")
    .on('click', function(event) {
      if ( $("#viewListNodesAndLinks").is(':visible') ) {
        $("#viewListNodesAndLinks").slideUp();
      }
      else {
        $("#viewListNodesAndLinks").slideDown();
      }
    });

    $("#viewListNodesAndLinks")
      .css("display","table-row")
      /* let the menu open when something is clicked inside !! */
      .on('click', function(event) {
        event.stopPropagation();
      });

    //
<input type="checkbox"/> Option 1

    lentities = userAbstraction.getEntities();

    $.each(lentities, function(i) {
      nodeuri = lentities[i];
      var li = menuView.buildLiView(nodeuri,false);
      li.on('click', function() {
        var span = $(this).find(".glyphicon");
        var cur_uri = $(this).attr("uri");
        if ( span.css("visibility") == "visible" ) {
          span.css("visibility","hidden");
          forceLayoutManager.offProposedUri("node",cur_uri);
          // disable all predicate associated with this node
          $(this).parent().parent().find("li[nodeuri='"+cur_uri+"']").attr("class","disabled");
        } else {
          span.css("visibility","visible");
          forceLayoutManager.onProposedUri("node",cur_uri);
          // enable all predicate associated with this node
          $(this).parent().parent().find("li[nodeuri='"+cur_uri+"']").removeAttr("class");
        }
        // remove old suggestion
        forceLayoutManager.removeSuggestions();
        // insert new suggestion
        forceLayoutManager.insertSuggestions();
        // regenerate the graph
        forceLayoutManager.update();
      });
      $("#viewListNodesAndLinks").append(li);
      /* --------------------------- */
      /* Adding filter on relations  */
      /* --------------------------- */
      var tab = userAbstraction.getRelationsObjectsAndSubjectsWithURI(nodeuri);
      var listRelObj = tab[0];

      $.each(listRelObj, function(objecturi) {
        $.each(listRelObj[objecturi], function(idxrel) {
          var rel = listRelObj[objecturi][idxrel];
          var li = menuView.buildLiView(rel,true);
          li.attr("nodeuri",nodeuri)
            .on('click', function() {
              var span = $(this).find(".glyphicon");
              var cur_uri = $(this).attr("uri");
              if ( span.css("visibility") == "visible" ) {
               span.css("visibility","hidden");
               forceLayoutManager.offProposedUri("link",cur_uri);
              } else {
               span.css("visibility","visible");
               forceLayoutManager.onProposedUri("link",cur_uri);
             }
             /* remove old suggestion */
             forceLayoutManager.removeSuggestions();
             /* insert new suggestion */
             forceLayoutManager.insertSuggestions();
             /* regenerate the graph */
             forceLayoutManager.update();
          });
          $("#viewListNodesAndLinks").append(li);
        });
      });
      $("#viewListNodesAndLinks").append($("

").attr("class","divider"));
      /* next entity */
    });

    positionableEntities = userAbstraction.getPositionableEntities();
    if (Object.keys(positionableEntities).length>0) {
      /* positionable object */
      posuri = "positionable";
      var li = menuView.buildLiView(posuri,true);
      li.attr("nodeuri",posuri)
        .on('click', function() {
          var span = $(this).find(".glyphicon");
          var cur_uri = $(this).attr("uri");
          if ( span.css("visibility") == "visible" ) {
            span.css("visibility","hidden");
            forceLayoutManager.offProposedUri("link",cur_uri);
          } else {
            span.css("visibility","visible");
            forceLayoutManager.onProposedUri("link",cur_uri);
          }
          /* remove old suggestion */
          forceLayoutManager.removeSuggestions();
          /* insert new suggestion */
          forceLayoutManager.insertSuggestions();
          /* regenerate the graph */
          forceLayoutManager.update();
        });
        $("#viewListNodesAndLinks").append(li);
        //$("#viewListNodesAndLinks").append($("

").attr("class","divider"));
      }

      //hide by default
      $("#viewListNodesAndLinks").hide();
  } ;
};
<|endoftext|>


<commit_before>/**
 * Settings notice component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import classnames from 'classnames';

export const TYPE_WARNING = 'warning';
export const TYPE_INFO = 'info';
export const TYPE_SUGGESTION = 'suggestion';

export default function SettingsNotice( { children, type, Icon, LearnMore } ) {
	return (
		<div className={ classnames(
			'mdc-layout-grid',
			'googlesitekit-settings-notice',
			`googlesitekit-settings-notice--${ type }`
		) } >

					{ Icon }

					{ children }

					{ LearnMore }

	);
}

SettingsNotice.propTypes = {
	children: PropTypes.node.isRequired,
	type: PropTypes.string,
	Icon: PropTypes.node,
	LearnMore: PropTypes.node,
};

SettingsNotice.defaultProps = {
	type: TYPE_WARNING,
	Icon: null,
	LearnMore: null,
};
<commit_msg>Make text flush left.<commit_after>/**
 * Settings notice component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import classnames from 'classnames';

/**
 * WordPress dependencies
 */
import { Fragment } from '@wordpress/element';

export const TYPE_WARNING = 'warning';
export const TYPE_INFO = 'info';
export const TYPE_SUGGESTION = 'suggestion';

export default function SettingsNotice( { children, type, Icon, LearnMore } ) {
	const innerChildren = Icon ? (
		<Fragment>

				{ Icon }

				{ children }

		</Fragment>
	) : (

			{ children }

	);
	return (
		<div className={ classnames(
			'mdc-layout-grid',
			'googlesitekit-settings-notice',
			`googlesitekit-settings-notice--${ type }`
		) } >

				{ innerChildren }

					{ LearnMore }

	);
}

SettingsNotice.propTypes = {
	children: PropTypes.node.isRequired,
	type: PropTypes.string,
	Icon: PropTypes.node,
	LearnMore: PropTypes.node,
};

SettingsNotice.defaultProps = {
	type: TYPE_WARNING,
	Icon: null,
	LearnMore: null,
};
<|endoftext|>


<commit_before>/*!

 =========================================================
 * Light Bootstrap Dashboard Free Angular2 - v1.3.0.0
 =========================================================

 * Product Page: http://www.creative-tim.com/product/light-bootstrap-dashboard-angular2
 * Copyright 2016 Creative Tim (http://www.creative-tim.com)
 * Licensed under MIT

 =========================================================

 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

 */

var searchVisible = 0;
var transparent = true;

var transparentDemo = true;
var fixedTop = false;

var navbar_initialized = false;

var bootstrap_nav_initialized = false;
var mobile_menu_visible = 0;

$(document).ready(function(){
    window_width = $(window).width();
    $('#menuresize a').click(function(){
        var href = $(this).attr('href');
        console.log(href);
        $('html,body').animate({
            'scrollTop': $($(this).attr('href')).offset().top - 100
        }, 200);
    })

    // check if there is an image set for the sidebar's background
    lbd.checkSidebarImage();

    // Init navigation toggle for small screens
    if($(window).width() <= 991){
        if($sidebar.length != 0){
            lbd.initRightMenu();

        } else {
            lbd.initBootstrapNavbarMenu();
        }
    }

    //  Activate the tooltips
    $('[rel="tooltip"]').tooltip();

    //      Activate the switches with icons
    if($('.switch').length != 0){
        $('.switch')['bootstrapSwitch']();
    }
    // if($('[data-toggle="checkbox"]').length != 0){
    //     $('[data-toggle="checkbox"]')['bootstrapSwitch']();
    // }
    //      Activate regular switches
    if($("[data-toggle='switch']").length != 0){
         $("[data-toggle='switch']").wrap('
').parent().bootstrapSwitch();
    }

    $('.form-control').on("focus", function(){
        $(this).parent('.input-group').addClass("input-group-focus");
    }).on("blur", function(){
        $(this).parent(".input-group").removeClass("input-group-focus");
    });

    // Fixes sub-nav not working as expected on IOS
$('body').on('touchstart.dropdown', '.dropdown-menu', function (e) { e.stopPropagation(); });
});

// activate collapse right menu when the windows is resized
$(window).resize(function(){
    lbd.initSidebarsCheck()
});

function scrollTo(){
    var href = $(this).attr('href');
    $('html,body').animate({
        'scrollTop': $($(this).attr('href')).offset().top - 350
    }, 200);
}

lbd = {
    misc:{
        navbar_menu_visible: 0
    },
    checkScrollForTransparentNavbar: debounce(function() {
            if($(document).scrollTop() > 381 ) {
                if(transparent) {
                    transparent = false;
                    $('.navbar-color-on-scroll').removeClass('navbar-transparent');
                    $('.navbar-title').removeClass('hidden');
                }
            } else {
                if( !transparent ) {
                    transparent = true;
                    $('.navbar-color-on-scroll').addClass('navbar-transparent');
                    $('.navbar-title').addClass('hidden');
                }
            }
    }, 17),

    checkSidebarImage: function(){
        $sidebar = $('.sidebar');
        image_src = $sidebar.data('image');

        if(image_src !== undefined){
            sidebar_container = '
'
            $sidebar.append(sidebar_container);
        }
    },
    initSidebarsCheck: function(){
        if($(window).width() <= 991){
            if($sidebar.length != 0){
                lbd.initRightMenu();

            } else {
                lbd.initBootstrapNavbarMenu();
            }
        }

    },
    initRightMenu: function(){
         if(!navbar_initialized){
            $navbar = $('nav').find('.navbar-collapse').first().clone(true);

            $sidebar = $('.sidebar');
            sidebar_color = $sidebar.data('color');

            $logo = $sidebar.find('.logo').first();
            logo_content = $logo[0].outerHTML;

            ul_content = '';

            $navbar.attr('data-color',sidebar_color);

            //add the content from the regular header to the right menu
            $navbar.children('ul').each(function(){
                content_buff = $(this).html();
                ul_content = ul_content + content_buff;
            });

            // add the content from the sidebar to the right menu
            content_buff = $sidebar.find('.nav').html();
            ul_content = ul_content + content_buff;

            ul_content = '
' +
                            '
' +
                                ul_content +
                            '
' +
                          '
';

            navbar_content = logo_content + ul_content;

            $navbar.html(navbar_content);

            $('body').append($navbar);

            background_image = $sidebar.data('image');
            if(background_image != undefined){
                $navbar.css('background',"url('" + background_image + "')")
                       .removeAttr('data-nav-image')
                       .addClass('has-image');
            }

             $toggle = $('.navbar-toggle');

             $navbar.find('a').removeClass('btn btn-round btn-default');
             $navbar.find('button').removeClass('btn-round btn-fill btn-info btn-primary btn-success btn-danger btn-warning btn-neutral');
             $navbar.find('button').addClass('btn-simple btn-block');

             $toggle.click(function (){
                if(lbd.misc.navbar_menu_visible == 1) {
                    $('html').removeClass('nav-open');
                    lbd.misc.navbar_menu_visible = 0;
                    $('#bodyClick').remove();
                     setTimeout(function(){
                        $toggle.removeClass('toggled');
                     }, 400);

                } else {
                    setTimeout(function(){
                        $toggle.addClass('toggled');
                    }, 430);

                    div = '

';
                    $(div).appendTo("body").click(function() {
                        $('html').removeClass('nav-open');
                        lbd.misc.navbar_menu_visible = 0;
                        $('#bodyClick').remove();
                         setTimeout(function(){
                            $toggle.removeClass('toggled');
                         }, 400);
                    });

                    $('html').addClass('nav-open');
                    lbd.misc.navbar_menu_visible = 1;

                }
            });
            navbar_initialized = true;
        }

    },
    initBootstrapNavbarMenu: debounce(function(){

        if(!bootstrap_nav_initialized){
            $navbar = $('nav').find('.navbar-collapse').first().clone(true);

            nav_content = '';
            mobile_menu_content = '';

            //add the content from the regular header to the mobile menu
            $navbar.children('ul').each(function(){
                content_buff = $(this).html();
                nav_content = nav_content + content_buff;
            });

            nav_content = '
' + nav_content + '
';

            $navbar.html(nav_content);
            $navbar.addClass('bootstrap-navbar');

            // append it to the body, so it will come from the right side of the screen
            $('body').append($navbar);

            $toggle = $('.navbar-toggle');

            $navbar.find('a').removeClass('btn btn-round btn-default');
            $navbar.find('button').removeClass('btn-round btn-fill btn-info btn-primary btn-success btn-danger btn-warning btn-neutral');
            $navbar.find('button').addClass('btn-simple btn-block');

            $toggle.click(function (){
                if(mobile_menu_visible == 1) {
                    $('html').removeClass('nav-open');

                    $('.close-layer').remove();
                    setTimeout(function(){
                        $toggle.removeClass('toggled');
                    }, 400);

                    mobile_menu_visible = 0;
                } else {
                    setTimeout(function(){
                        $toggle.addClass('toggled');
                    }, 430);

                    $layer = $('

');
                    $layer.appendTo(".wrapper-full-page");

                    setTimeout(function(){
                        $layer.addClass('visible');
                    }, 100);

                    $layer.click(function() {
                        $('html').removeClass('nav-open');
                        mobile_menu_visible = 0;

                        $layer.removeClass('visible');

                         setTimeout(function(){
                            $layer.remove();
                            $toggle.removeClass('toggled');

                         }, 400);
                    });

                    $('html').addClass('nav-open');
                    mobile_menu_visible = 1;

                }

            });
            bootstrap_nav_initialized = true;
        }
    }, 500)
}

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.

function debounce(func, wait, immediate) {
	var timeout;
	return function() {
		var context = this, args = arguments;
		clearTimeout(timeout);
		timeout = setTimeout(function() {
			timeout = null;
			if (!immediate) func.apply(context, args);
		}, wait);
		if (immediate && !timeout) func.apply(context, args);
	};
};
<commit_msg>Reparat charts la resize<commit_after>/*!

 =========================================================
 * Light Bootstrap Dashboard Free Angular2 - v1.3.0.0
 =========================================================

 * Product Page: http://www.creative-tim.com/product/light-bootstrap-dashboard-angular2
 * Copyright 2016 Creative Tim (http://www.creative-tim.com)
 * Licensed under MIT

 =========================================================

 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

 */

var searchVisible = 0;
var transparent = true;

var transparentDemo = true;
var fixedTop = false;

var navbar_initialized = false;

var bootstrap_nav_initialized = false;
var mobile_menu_visible = 0;

$(document).ready(function(){
    window_width = $(window).width();
    $('#menuresize a').click(function(){
        var href = $(this).attr('href');
        $('html,body').animate({
            'scrollTop': $($(this).attr('href')).offset().top - 100
        }, 200);
    })
    // we simulate the window Resize so the charts will get updated in realtime.
                var simulateWindowResize = setInterval(function(){
                    window.dispatchEvent(new Event('resize'));
                },180);

                // we stop the simulation of Window Resize after the animations are completed
                setTimeout(function(){
                    clearInterval(simulateWindowResize);
                },1000);
    // check if there is an image set for the sidebar's background
    lbd.checkSidebarImage();

    // Init navigation toggle for small screens
    if($(window).width() <= 991){
        if($sidebar.length != 0){
            lbd.initRightMenu();

        } else {
            lbd.initBootstrapNavbarMenu();
        }
    }

    //  Activate the tooltips
    $('[rel="tooltip"]').tooltip();

    //      Activate the switches with icons
    if($('.switch').length != 0){
        $('.switch')['bootstrapSwitch']();
    }
    // if($('[data-toggle="checkbox"]').length != 0){
    //     $('[data-toggle="checkbox"]')['bootstrapSwitch']();
    // }
    //      Activate regular switches
    if($("[data-toggle='switch']").length != 0){
         $("[data-toggle='switch']").wrap('
').parent().bootstrapSwitch();
    }

    $('.form-control').on("focus", function(){
        $(this).parent('.input-group').addClass("input-group-focus");
    }).on("blur", function(){
        $(this).parent(".input-group").removeClass("input-group-focus");
    });

    // Fixes sub-nav not working as expected on IOS
$('body').on('touchstart.dropdown', '.dropdown-menu', function (e) { e.stopPropagation(); });
});

// activate collapse right menu when the windows is resized
$(window).resize(function(){
    lbd.initSidebarsCheck();

});

$(window).on("resize", function(){
    // we simulate the window Resize so the charts will get updated in realtime.
            var simulateWindowResize = setInterval(function(){
                window.dispatchEvent(new Event('resize'));
            },100);

            // we stop the simulation of Window Resize after the animations are completed
            setTimeout(function(){
                clearInterval(simulateWindowResize);
            },120);
});
function scrollTo(){
    var href = $(this).attr('href');
    $('html,body').animate({
        'scrollTop': $($(this).attr('href')).offset().top - 350
    }, 200);
}

lbd = {
    misc:{
        navbar_menu_visible: 0
    },
    checkScrollForTransparentNavbar: debounce(function() {
            if($(document).scrollTop() > 381 ) {
                if(transparent) {
                    transparent = false;
                    $('.navbar-color-on-scroll').removeClass('navbar-transparent');
                    $('.navbar-title').removeClass('hidden');
                }
            } else {
                if( !transparent ) {
                    transparent = true;
                    $('.navbar-color-on-scroll').addClass('navbar-transparent');
                    $('.navbar-title').addClass('hidden');
                }
            }
    }, 17),

    checkSidebarImage: function(){
        $sidebar = $('.sidebar');
        image_src = $sidebar.data('image');

        if(image_src !== undefined){
            sidebar_container = '
'
            $sidebar.append(sidebar_container);
        }
    },
    initSidebarsCheck: function(){
        if($(window).width() <= 991){
            if($sidebar.length != 0){
                lbd.initRightMenu();

            } else {
                lbd.initBootstrapNavbarMenu();
            }
        }

    },
    initRightMenu: function(){
         if(!navbar_initialized){
            $navbar = $('nav').find('.navbar-collapse').first().clone(true);

            $sidebar = $('.sidebar');
            sidebar_color = $sidebar.data('color');

            $logo = $sidebar.find('.logo').first();
            logo_content = $logo[0].outerHTML;

            ul_content = '';

            $navbar.attr('data-color',sidebar_color);

            //add the content from the regular header to the right menu
            $navbar.children('ul').each(function(){
                content_buff = $(this).html();
                ul_content = ul_content + content_buff;
            });

            // add the content from the sidebar to the right menu
            content_buff = $sidebar.find('.nav').html();
            ul_content = ul_content + content_buff;

            ul_content = '
' +
                            '
' +
                                ul_content +
                            '
' +
                          '
';

            navbar_content = logo_content + ul_content;

            $navbar.html(navbar_content);

            $('body').append($navbar);

            background_image = $sidebar.data('image');
            if(background_image != undefined){
                $navbar.css('background',"url('" + background_image + "')")
                       .removeAttr('data-nav-image')
                       .addClass('has-image');
            }

             $toggle = $('.navbar-toggle');

             $navbar.find('a').removeClass('btn btn-round btn-default');
             $navbar.find('button').removeClass('btn-round btn-fill btn-info btn-primary btn-success btn-danger btn-warning btn-neutral');
             $navbar.find('button').addClass('btn-simple btn-block');

             $toggle.click(function (){
                if(lbd.misc.navbar_menu_visible == 1) {
                    $('html').removeClass('nav-open');
                    lbd.misc.navbar_menu_visible = 0;
                    $('#bodyClick').remove();
                     setTimeout(function(){
                        $toggle.removeClass('toggled');
                     }, 400);

                } else {
                    setTimeout(function(){
                        $toggle.addClass('toggled');
                    }, 430);

                    div = '

';
                    $(div).appendTo("body").click(function() {
                        $('html').removeClass('nav-open');
                        lbd.misc.navbar_menu_visible = 0;
                        $('#bodyClick').remove();
                         setTimeout(function(){
                            $toggle.removeClass('toggled');
                         }, 400);
                    });

                    $('html').addClass('nav-open');
                    lbd.misc.navbar_menu_visible = 1;

                }
            });
            navbar_initialized = true;
        }

    },
    initBootstrapNavbarMenu: debounce(function(){

        if(!bootstrap_nav_initialized){
            $navbar = $('nav').find('.navbar-collapse').first().clone(true);

            nav_content = '';
            mobile_menu_content = '';

            //add the content from the regular header to the mobile menu
            $navbar.children('ul').each(function(){
                content_buff = $(this).html();
                nav_content = nav_content + content_buff;
            });

            nav_content = '
' + nav_content + '
';

            $navbar.html(nav_content);
            $navbar.addClass('bootstrap-navbar');

            // append it to the body, so it will come from the right side of the screen
            $('body').append($navbar);

            $toggle = $('.navbar-toggle');

            $navbar.find('a').removeClass('btn btn-round btn-default');
            $navbar.find('button').removeClass('btn-round btn-fill btn-info btn-primary btn-success btn-danger btn-warning btn-neutral');
            $navbar.find('button').addClass('btn-simple btn-block');

            $toggle.click(function (){
                if(mobile_menu_visible == 1) {
                    $('html').removeClass('nav-open');

                    $('.close-layer').remove();
                    setTimeout(function(){
                        $toggle.removeClass('toggled');
                    }, 400);

                    mobile_menu_visible = 0;
                } else {
                    setTimeout(function(){
                        $toggle.addClass('toggled');
                    }, 430);

                    $layer = $('

');
                    $layer.appendTo(".wrapper-full-page");

                    setTimeout(function(){
                        $layer.addClass('visible');
                    }, 100);

                    $layer.click(function() {
                        $('html').removeClass('nav-open');
                        mobile_menu_visible = 0;

                        $layer.removeClass('visible');

                         setTimeout(function(){
                            $layer.remove();
                            $toggle.removeClass('toggled');

                         }, 400);
                    });

                    $('html').addClass('nav-open');
                    mobile_menu_visible = 1;

                }

            });
            bootstrap_nav_initialized = true;
        }
    }, 500)
}

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.

function debounce(func, wait, immediate) {
	var timeout;
	return function() {
		var context = this, args = arguments;
		clearTimeout(timeout);
		timeout = setTimeout(function() {
			timeout = null;
			if (!immediate) func.apply(context, args);
		}, wait);
		if (immediate && !timeout) func.apply(context, args);
	};
};
<|endoftext|>


<commit_before>import {
  ADD_SEGMENT,
  REMOVE_SEGMENT,
  MOVE_SEGMENT,
  REPLACE_STREET_DATA,
  CHANGE_SEGMENT_WIDTH,
  CHANGE_SEGMENT_VARIANT,
  ADD_LOCATION,
  CLEAR_LOCATION,
  SAVE_STREET_NAME,
  // BUILDINGS
  ADD_BUILDING_FLOOR,
  REMOVE_BUILDING_FLOOR,
  SET_BUILDING_FLOOR_VALUE,
  SET_BUILDING_VARIANT
} from './'
import { DEFAULT_NAME } from '../../streets/data_model'

export function addSegment (index, segment) {
  return {
    type: ADD_SEGMENT,
    index,
    segment
  }
}

export function removeSegment (index) {
  return {
    type: REMOVE_SEGMENT,
    index
  }
}

export function moveSegment (index, newIndex) {
  return {
    type: MOVE_SEGMENT,
    index,
    newIndex
  }
}

// temporary while we migrate data stores
export function updateStreetData (street) {
  return {
    type: REPLACE_STREET_DATA,
    street
  }
}

export function addLocation (location) {
  return {
    type: ADD_LOCATION,
    location
  }
}

export function clearLocation () {
  return {
    type: CLEAR_LOCATION,
    defaultName: DEFAULT_NAME
  }
}

export function saveStreetName (streetName, userUpdated) {
  return {
    type: SAVE_STREET_NAME,
    streetName,
    userUpdated
  }
}

export function changeSegmentWidth (index, width) {
  return {
    type: CHANGE_SEGMENT_WIDTH,
    index,
    width
  }
}

export function changeSegmentVariant (index, set, selection) {
  return {
    type: CHANGE_SEGMENT_VARIANT,
    index,
    set,
    selection
  }
}

// Buildings

/**
 * Adds one more building floor
 *
 * @param {string} position - must be 'left' or 'right
 */
export function addBuildingFloor (position) {
  return {
    type: ADD_BUILDING_FLOOR,
    position
  }
}

/**
 * Removes one building floor
 *
 * @param {string} position - must be 'left' or 'right
 */
export function removeBuildingFloor (position) {
  return {
    type: REMOVE_BUILDING_FLOOR,
    position
  }
}

/**
 * Sets building floor to specific value
 *
 * @param {string} position - must be 'left' or 'right
 * @param {Number} value - the value to set it to
 */
export function setBuildingFloorValue (position, value) {
  return {
    type: SET_BUILDING_FLOOR_VALUE,
    position,
    value
  }
}

/**
 * Sets building to a selected variant
 *
 * @param {string} position - must be 'left' or 'right
 * @param {string} variant - the variant to set it to
 */
export function setBuildingVariant (position, variant) {
  return {
    type: SET_BUILDING_VARIANT,
    position,
    variant
  }
}
<commit_msg>manually save "Unnamed St" as defaultName in clearLocation action creator<commit_after>import {
  ADD_SEGMENT,
  REMOVE_SEGMENT,
  MOVE_SEGMENT,
  REPLACE_STREET_DATA,
  CHANGE_SEGMENT_WIDTH,
  CHANGE_SEGMENT_VARIANT,
  ADD_LOCATION,
  CLEAR_LOCATION,
  SAVE_STREET_NAME,
  // BUILDINGS
  ADD_BUILDING_FLOOR,
  REMOVE_BUILDING_FLOOR,
  SET_BUILDING_FLOOR_VALUE,
  SET_BUILDING_VARIANT
} from './'

export function addSegment (index, segment) {
  return {
    type: ADD_SEGMENT,
    index,
    segment
  }
}

export function removeSegment (index) {
  return {
    type: REMOVE_SEGMENT,
    index
  }
}

export function moveSegment (index, newIndex) {
  return {
    type: MOVE_SEGMENT,
    index,
    newIndex
  }
}

// temporary while we migrate data stores
export function updateStreetData (street) {
  return {
    type: REPLACE_STREET_DATA,
    street
  }
}

export function addLocation (location) {
  return {
    type: ADD_LOCATION,
    location
  }
}

export function clearLocation () {
  return {
    type: CLEAR_LOCATION,
    defaultName: 'Unnamed St'
  }
}

export function saveStreetName (streetName, userUpdated) {
  return {
    type: SAVE_STREET_NAME,
    streetName,
    userUpdated
  }
}

export function changeSegmentWidth (index, width) {
  return {
    type: CHANGE_SEGMENT_WIDTH,
    index,
    width
  }
}

export function changeSegmentVariant (index, set, selection) {
  return {
    type: CHANGE_SEGMENT_VARIANT,
    index,
    set,
    selection
  }
}

// Buildings

/**
 * Adds one more building floor
 *
 * @param {string} position - must be 'left' or 'right
 */
export function addBuildingFloor (position) {
  return {
    type: ADD_BUILDING_FLOOR,
    position
  }
}

/**
 * Removes one building floor
 *
 * @param {string} position - must be 'left' or 'right
 */
export function removeBuildingFloor (position) {
  return {
    type: REMOVE_BUILDING_FLOOR,
    position
  }
}

/**
 * Sets building floor to specific value
 *
 * @param {string} position - must be 'left' or 'right
 * @param {Number} value - the value to set it to
 */
export function setBuildingFloorValue (position, value) {
  return {
    type: SET_BUILDING_FLOOR_VALUE,
    position,
    value
  }
}

/**
 * Sets building to a selected variant
 *
 * @param {string} position - must be 'left' or 'right
 * @param {string} variant - the variant to set it to
 */
export function setBuildingVariant (position, variant) {
  return {
    type: SET_BUILDING_VARIANT,
    position,
    variant
  }
}
<|endoftext|>


<commit_before>var _ = require('underscore'),
    EventEmitter = require('events').EventEmitter,
    cx = React.addons.classSet,
    ES = require('./es'),
    forWhere = require('./forWhere');

// Stolen from http://bl.ocks.org/tgk/5744943
function hashCode(str){
    var hash = 0;
    if (str.length == 0) return hash;
    for (i = 0; i < str.length; i++) {
        char = str.charCodeAt(i);
        hash = ((hash<<5)-hash)+char;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
}

function traversedSpans(rootSpan){
  var spans = [];
  ES.visitSpanTreeDepthFirstPreOrder(rootSpan, function(span){
    spans.push(span);
    return span.expandChildren;
  });
  return spans;
}

var WaterfallLine = React.createClass({
  handleClick: function(){
    this.props.eventBus.emit('toggleSpanExpansion',this.props.spanId);
  },
  handleEnter: function(){
    this.props.eventBus.emit('spanHovered',this.props.spanId);
  },
  handleLeave: function(){
    this.props.eventBus.emit('spanUnhovered',this.props.spanId);
  },
  label: function(){
    if( this.props.hasChildren ){
      prefix = "";
    }else if( this.props.expandChildren ){
      prefix = "[-] ";
    }else{
      prefix = "[+] ";
    }
    return prefix + this.props.name;
  },
  render: function(){
    var props=this.props;
    return <g transform={"translate("+props.x+","+props.y+")"}>
          <rect
            onClick={this.handleClick}
            onMouseEnter={this.handleEnter}
            onMouseLeave={this.handleLeave}
            height={props.dy}
            width={props.dx}
            className={cx({'waterfall-line':true, highlighted:props.highlighted})}
          />
          <text x="1em" dy={props.dy/2} textAnchor="left">{this.label()}</text>
    </g>
  }
});

var WaterfallChart = React.createClass({
  getDefaultProps: function(){
    var margin = {top: 1, right: 1, bottom: 6, left: 1};
    return {
      margin: margin,
      width: 960 - margin.left - margin.right,
      height: 800 - margin.top - margin.bottom,
      rowHeight: 30,
      rowVertPadding: 5
    };
  },

  onWaterfallLineToggled: function(spanId){
    var span = _.findBy(this.props.spans,'spanId');
  },

  renderWaterfallLines: function(){
    var self = this;
    var props = this.props;

    var rootSpan = ES.findRootSpan(props.spans);
    var sequencedSpans = traversedSpans(rootSpan);

    var x = d3.scale.linear()
      .domain([0,rootSpan.elapsedMillis])
      .range([0,props.width]);

    var rowHeightWithPadding = props.rowHeight + props.rowVertPadding;

    var baseTimeOffset = rootSpan.startTime;

    var lines =  _.map(sequencedSpans,function(span,ix){
      return <WaterfallLine
                key={span.spanId}
                eventBus={props.eventBus}
                onToggle={self.onWaterfallLineToggled}

                spanId={span.spanId}
                name={span.name}
                expandChildren={span.expandChildren}
                hasChildren={_.isEmpty(span.children)}
                highlighted={span.highlighted}

                dx={x(span.elapsedMillis)}
                dy={props.rowHeight}
                x={x(5+span.startTime-baseTimeOffset)}
                y={ix*rowHeightWithPadding}
                />
    });

    return lines;
  },

  render: function() {
    return React.DOM.svg( {
      width: this.props.width + this.props.margin.left + this.props.margin.right,
      height: this.props.height + this.props.margin.top + this.props.margin.bottom
    },
      React.DOM.g({
        transform: "translate(" + this.props.margin.left + "," + this.props.margin.top + ")"
      },
        this.renderWaterfallLines()
      )
    );
  }
});

function decorateSpansWithViewSpecificStuff(spans){
  _.each(spans,function(span){
    span.expandChildren = true;
  });
};

function renderTraceSpanTree(spans){
  decorateSpansWithViewSpecificStuff(spans);

  console.log( 'root', ES.findRootSpan(spans) );

  var eventBus = new EventEmitter();
  var appContainer = document.getElementById('appContainer');

  function render(spans){
    React.render(
        <WaterfallChart eventBus={eventBus} spans={spans}/>,
        appContainer
    );
  }

  eventBus.on('toggleSpanExpansion', function(spanId){
    forWhere(spans, {spanId:spanId}, function(span){
      span.expandChildren = !span.expandChildren;
    });
    render(spans);
  });

  eventBus.on('spanHovered', function(spanId){
    _.each(spans, function(span){
      span.highlighted = false;
    });
    forWhere(spans, {spanId:spanId}, function(span){
      ES.visitSpanTreeDepthFirstPreOrder(span,function(subSpan){
        subSpan.highlighted = true;
        return true;
      });
    });
    render(spans);
  });

  eventBus.on('spanUnhovered', function(spanId){
    _.each(spans, function(span){
      span.highlighted = false;
    });
    render(spans);
  });

  render(spans);
}

var traceId = window.location.search.substr(1);
ES.getConstructedTrace(traceId).then( renderTraceSpanTree );
<commit_msg>include duration in label<commit_after>var _ = require('underscore'),
    EventEmitter = require('events').EventEmitter,
    cx = React.addons.classSet,
    ES = require('./es'),
    forWhere = require('./forWhere');

// Stolen from http://bl.ocks.org/tgk/5744943
function hashCode(str){
    var hash = 0;
    if (str.length == 0) return hash;
    for (i = 0; i < str.length; i++) {
        char = str.charCodeAt(i);
        hash = ((hash<<5)-hash)+char;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
}

function traversedSpans(rootSpan){
  var spans = [];
  ES.visitSpanTreeDepthFirstPreOrder(rootSpan, function(span){
    spans.push(span);
    return span.expandChildren;
  });
  return spans;
}

var WaterfallLine = React.createClass({
  handleClick: function(){
    this.props.eventBus.emit('toggleSpanExpansion',this.props.spanId);
  },
  handleEnter: function(){
    this.props.eventBus.emit('spanHovered',this.props.spanId);
  },
  handleLeave: function(){
    this.props.eventBus.emit('spanUnhovered',this.props.spanId);
  },
  label: function(){
    if( this.props.hasChildren ){
      prefix = "";
    }else if( this.props.expandChildren ){
      prefix = "[-] ";
    }else{
      prefix = "[+] ";
    }
    return prefix + this.props.name + " [" +this.props.elapsedMillis+"ms]";
  },
  render: function(){
    var props=this.props;
    return <g transform={"translate("+props.x+","+props.y+")"}>
          <rect
            onClick={this.handleClick}
            onMouseEnter={this.handleEnter}
            onMouseLeave={this.handleLeave}
            height={props.dy}
            width={props.dx}
            className={cx({'waterfall-line':true, highlighted:props.highlighted})}
          />
          <text x="1em" dy={props.dy/2} textAnchor="left">{this.label()}</text>
    </g>
  }
});

var WaterfallChart = React.createClass({
  getDefaultProps: function(){
    var margin = {top: 1, right: 1, bottom: 6, left: 1};
    return {
      margin: margin,
      width: 960 - margin.left - margin.right,
      height: 800 - margin.top - margin.bottom,
      rowHeight: 30,
      rowVertPadding: 5
    };
  },

  onWaterfallLineToggled: function(spanId){
    var span = _.findBy(this.props.spans,'spanId');
  },

  renderWaterfallLines: function(){
    var self = this;
    var props = this.props;

    var rootSpan = ES.findRootSpan(props.spans);
    var sequencedSpans = traversedSpans(rootSpan);

    var x = d3.scale.linear()
      .domain([0,rootSpan.elapsedMillis])
      .range([0,props.width]);

    var rowHeightWithPadding = props.rowHeight + props.rowVertPadding;

    var baseTimeOffset = rootSpan.startTime;

    var lines =  _.map(sequencedSpans,function(span,ix){
      return <WaterfallLine
                key={span.spanId}
                eventBus={props.eventBus}
                onToggle={self.onWaterfallLineToggled}

                spanId={span.spanId}
                name={span.name}
                elapsedMillis={span.elapsedMillis}
                expandChildren={span.expandChildren}
                hasChildren={_.isEmpty(span.children)}
                highlighted={span.highlighted}

                dx={x(span.elapsedMillis)}
                dy={props.rowHeight}
                x={x(5+span.startTime-baseTimeOffset)}
                y={ix*rowHeightWithPadding}
                />
    });

    return lines;
  },

  render: function() {
    return React.DOM.svg( {
      width: this.props.width + this.props.margin.left + this.props.margin.right,
      height: this.props.height + this.props.margin.top + this.props.margin.bottom
    },
      React.DOM.g({
        transform: "translate(" + this.props.margin.left + "," + this.props.margin.top + ")"
      },
        this.renderWaterfallLines()
      )
    );
  }
});

function decorateSpansWithViewSpecificStuff(spans){
  _.each(spans,function(span){
    span.expandChildren = true;
  });
};

function renderTraceSpanTree(spans){
  decorateSpansWithViewSpecificStuff(spans);

  console.log( 'root', ES.findRootSpan(spans) );

  var eventBus = new EventEmitter();
  var appContainer = document.getElementById('appContainer');

  function render(spans){
    React.render(
        <WaterfallChart eventBus={eventBus} spans={spans}/>,
        appContainer
    );
  }

  eventBus.on('toggleSpanExpansion', function(spanId){
    forWhere(spans, {spanId:spanId}, function(span){
      span.expandChildren = !span.expandChildren;
    });
    render(spans);
  });

  eventBus.on('spanHovered', function(spanId){
    _.each(spans, function(span){
      span.highlighted = false;
    });
    forWhere(spans, {spanId:spanId}, function(span){
      ES.visitSpanTreeDepthFirstPreOrder(span,function(subSpan){
        subSpan.highlighted = true;
        return true;
      });
    });
    render(spans);
  });

  eventBus.on('spanUnhovered', function(spanId){
    _.each(spans, function(span){
      span.highlighted = false;
    });
    render(spans);
  });

  render(spans);
}

var traceId = window.location.search.substr(1);
ES.getConstructedTrace(traceId).then( renderTraceSpanTree );
<|endoftext|>


<commit_before>/*jshint esversion:6*/
/**
 * Copyright 2016 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Assigning modules to local constants
var gulp = require('gulp');
// Required for sw-precache
var path = require('path');
var swPrecache = require('sw-precache');
// Array of paths. Currently only uses the src to represent the path to source
var paths = {
  src: './'
};

gulp.task('service-worker', function(callback) {
  swPrecache.write(path.join(paths.src, 'service-worker.js'), {
    staticFileGlobs: [
      paths.src + 'index.html',
      paths.src + 'css/main.css',
    ],
    importScripts: [
      paths.src + 'node_modules/sw-toolbox/sw-toolbox.js',
      paths.src + 'js/toolbox-script.js'
    ],
    stripPrefix: paths.src
  }, callback);
});
<commit_msg>sw-precache-lab: remove path prefix from imported scripts<commit_after>/*jshint esversion:6*/
/**
 * Copyright 2016 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Assigning modules to local constants
var gulp = require('gulp');
// Required for sw-precache
var path = require('path');
var swPrecache = require('sw-precache');
// Array of paths. Currently only uses the src to represent the path to source
var paths = {
  src: './'
};

gulp.task('service-worker', function(callback) {
  swPrecache.write(path.join(paths.src, 'service-worker.js'), {
    staticFileGlobs: [
      paths.src + 'index.html',
      paths.src + 'css/main.css',
    ],
    importScripts: [
      'node_modules/sw-toolbox/sw-toolbox.js',
      'js/toolbox-script.js'
    ],
    stripPrefix: paths.src
  }, callback);
});
<|endoftext|>


<commit_before>(function() {
  var el,
      hash = (location.hash || '').replace(/^#/, '');

  if ((el = document.getElementById('section_' + hash)))
    window.setTimeout(function() {
      window.scrollTo(0, el.offsetTop);
      el.setAttribute('class', 'target');
    }, 0);
}).call(window);
<commit_msg>prepare glossary in bulletin<commit_after>// Fix chrome anchor bug
(function() {
  var el,
      hash = (location.hash || '').replace(/^#/, '');

  if ((el = document.getElementById('section_' + hash)))
    window.setTimeout(function() {
      window.scrollTo(0, el.offsetTop);
      el.setAttribute('class', 'target');
    }, 0);
}).call(window);

// Glossary
(function(){

})();<|endoftext|>