<commit_before>
/*Global Configuration*/

var request = require('request');
var lyft = require('node-lyft');
let defaultClient = lyft.ApiClient.instance;

/**
* REQUEST A LYFT RIDE
*/

// Configure OAuth2 access token for authorization: User Authentication
//let accessToken = defaultClient.authentications['User Authentication'].accessToken;
let accessToken = db.run(SELECT access FROM user_info ORDER BY id DESC LIMIT 1);
let ride = {'ride_type' : 'lyft', 'origin' : {'lat' : 37.77663, 'lng' : -122.39227 },  'destination' : {'lat' : 37.771, 'lng' : -122.39123, 'address' : 'Mission Bay Boulevard North' }};

let req = {
  method: 'post',
  body: ride,
  json: true,
  url: 'https://api.lyft.com/v1/rides',
  headers: {
    'Authorization': 'Bearer ' + accessToken
  }
}

function callback(error, response, body) {
  console.log(error);
  console.log(response);
  console.log(body);
}

request(req,callback);

/**
* CANCEL A LYFT RIDE
*/
/*
let id = "<ride_id>"; // String | The ID of the ride

apiInstance.cancelRide(id).then(() => {
  console.log('API called successfully.');
}, (error) => {
  console.error(error);
});*/
<commit_msg>bug fix in  databases<commit_after>
/*Global Configuration*/

var request = require('request');
var lyft = require('node-lyft');
let defaultClient = lyft.ApiClient.instance;

/**
* REQUEST A LYFT RIDE
*/

// Configure OAuth2 access token for authorization: User Authentication
//let accessToken = defaultClient.authentications['User Authentication'].accessToken;
let accessToken = db.run(SELECT access * FROM user_info ORDER BY id DESC LIMIT 1;);
let ride = {'ride_type' : 'lyft', 'origin' : {'lat' : 37.77663, 'lng' : -122.39227 },  'destination' : {'lat' : 37.771, 'lng' : -122.39123, 'address' : 'Mission Bay Boulevard North' }};

let req = {
  method: 'post',
  body: ride,
  json: true,
  url: 'https://api.lyft.com/v1/rides',
  headers: {
    'Authorization': 'Bearer ' + accessToken
  }
}

function callback(error, response, body) {
  console.log(error);
  console.log(response);
  console.log(body);
}

request(req,callback);

/**
* CANCEL A LYFT RIDE
*/
/*
let id = "<ride_id>"; // String | The ID of the ride

apiInstance.cancelRide(id).then(() => {
  console.log('API called successfully.');
}, (error) => {
  console.error(error);
});*/
<|endoftext|>


<commit_before>var childProcess = require('child_process');
var fs = require('fs-extra');
var glob = require('glob');
var path = require('path');
var sortPackageJson = require('sort-package-json');

// Get the current version of JupyterLab
// var cwd = path.resolve('..');
// var version = childProcess.execSync('python setup.py --version', { cwd: cwd });
// version = version.toString().trim();

var corePackage = require('./package.json');
corePackage.jupyterlab.extensions = {};
corePackage.jupyterlab.mimeExtensions = {};
corePackage.jupyterlab.version = 'test';
corePackage.dependencies = {};

var basePath = path.resolve('..');
var packages = glob.sync(path.join(basePath, 'packages/*'));
packages.forEach(function(packagePath) {

   var dataPath = path.join(packagePath, 'package.json');
   try {
    var data = require(dataPath);
  } catch (e) {
    return;
  }

  if (data.private === true) {
    return;
  }

  // Make sure it is included as a dependency.
  corePackage.dependencies[data.name] = '^' + String(data.version);

  var jlab = data.jupyterlab;
  if (!jlab) {
    return;
  }

  // Add its dependencies to the core dependencies.
  var deps = data.dependencies || [];
  for (var dep in deps) {
    corePackage.dependencies[dep] = deps[dep];
  }

  // Handle extensions.
  ['extension', 'mimeExtension'].forEach(function(item) {
    var ext = jlab[item];
    if (ext === true) {
      ext = ''
    }
    if (typeof ext !== 'string') {
      return;
    }
    corePackage.jupyterlab[item + 's'][data.name] = ext;
  });
});

// Write the package.json back to disk.
var text = JSON.stringify(sortPackageJson(corePackage), null, 2) + '\n';
fs.writeFileSync('./package.json', text);
<commit_msg>Reinstate update-core versioning<commit_after>var childProcess = require('child_process');
var fs = require('fs-extra');
var glob = require('glob');
var path = require('path');
var sortPackageJson = require('sort-package-json');

// Get the current version of JupyterLab
var cwd = path.resolve('..');
var version = childProcess.execSync('python setup.py --version', { cwd: cwd });
version = version.toString().trim();

var corePackage = require('./package.json');
corePackage.jupyterlab.extensions = {};
corePackage.jupyterlab.mimeExtensions = {};
corePackage.jupyterlab.version = version;
corePackage.dependencies = {};

var basePath = path.resolve('..');
var packages = glob.sync(path.join(basePath, 'packages/*'));
packages.forEach(function(packagePath) {

   var dataPath = path.join(packagePath, 'package.json');
   try {
    var data = require(dataPath);
  } catch (e) {
    return;
  }

  if (data.private === true) {
    return;
  }

  // Make sure it is included as a dependency.
  corePackage.dependencies[data.name] = '^' + String(data.version);

  var jlab = data.jupyterlab;
  if (!jlab) {
    return;
  }

  // Add its dependencies to the core dependencies.
  var deps = data.dependencies || [];
  for (var dep in deps) {
    corePackage.dependencies[dep] = deps[dep];
  }

  // Handle extensions.
  ['extension', 'mimeExtension'].forEach(function(item) {
    var ext = jlab[item];
    if (ext === true) {
      ext = ''
    }
    if (typeof ext !== 'string') {
      return;
    }
    corePackage.jupyterlab[item + 's'][data.name] = ext;
  });
});

// Write the package.json back to disk.
var text = JSON.stringify(sortPackageJson(corePackage), null, 2) + '\n';
fs.writeFileSync('./package.json', text);
<|endoftext|>


<commit_before>var tokenCheck = require('../checkToken');
var userService = require('../userService');
var DocumentClient = require('documentdb').DocumentClient;
var client = new DocumentClient(process.env.dbHost, { masterKey: process.env.dbMasterKey });
var docDb = require('../docDbHelper');

module.exports = function (context, req, doc) {
    context.log('Token: ' + req.headers.token);
    let userToken = tokenCheck(req.headers.token, context)
    if (userToken) {
        userService.getUserInformation(userToken.sub, (err, result) => {
            if (err) {
                context.res = {
                    status: 500,
                    body: err
                };
                context.done();
            }
            let participantData = {
                userId: result.user_id,
                userName: result.name,
                value: req.body.value,
                specialNeeds: req.body.special,
                payed: req.body.payed
            }
            if (doc.filter(x => x._self === req.body.eventId).length <= 0) {
                context.res = {
                    status: 404
                };
                context.done();
            }
            if (doc.filter(x => x._self === req.body.eventId)[0].participants.filter(part => part.userId === result.user_id).length <= 0) {
                context.res = {
                    status:'409',
                    body: {
                        'message':'you are not subscribed, dont try to call my api by hand ;) '
                    }
                }
                context.done();
            } else {
                updateItem(req.body.eventId, participantData, (err, result) => {
                    if (err) {
                        context.res = {
                            status: 500,
                            body: err
                        };
                        context.done();
                    } else {
                        context.res = {
                            body: result
                        };
                        context.done();
                    }
                });
            }
        });
    }
    else {
        context.res = {
            status: 401,
            body: 'token was wrong expired or missing'
        };
        context.done();
    }
};

function updateItem(eventId, participant, callback) {
    client.readDocument(eventId, (err, result) => {
        if (err) {
            callback(err);
        }
        else {
            let event = result;
            event.partticipants =  event.participants.splice(event.participants.findIndex(part => part.userId === participant.user_id),1);

            client.replaceDocument(eventId, event, (repErr, repRes) => {
                if (repErr) {
                    callback(repErr);
                }
                else {
                    callback(null, repRes);
                }
            });
        }
    });
}
<commit_msg>Changed unscribed and removed participantmodel<commit_after>var tokenCheck = require('../checkToken');
var userService = require('../userService');
var DocumentClient = require('documentdb').DocumentClient;
var client = new DocumentClient(process.env.dbHost, { masterKey: process.env.dbMasterKey });
var docDb = require('../docDbHelper');

module.exports = function (context, req, doc) {
    context.log('Token: ' + req.headers.token);
    let userToken = tokenCheck(req.headers.token, context)
    if (userToken) {
        userService.getUserInformation(userToken.sub, (err, result) => {
            if (err) {
                context.res = {
                    status: 500,
                    body: err
                };
                context.done();
            }
            context.log(result);
            if (doc.filter(x => x._self === req.body.eventId).length <= 0) {
                context.res = {
                    status: 404
                };
                context.done();
            }
            if (doc.filter(x => x._self === req.body.eventId)[0].participants.filter(part => part.userId === result.user_id).length <= 0) {
                context.res = {
                    status:'409',
                    body: {
                        'message':'you are not subscribed, dont try to call my api by hand ;) '
                    }
                }
                context.done();
            } else {
                updateItem(req.body.eventId, result.user_id, (err, result) => {
                    if (err) {
                        context.res = {
                            status: 500,
                            body: err
                        };
                        context.done();
                    } else {
                        context.res = {
                            body: result
                        };
                        context.done();
                    }
                });
            }
        });
    }
    else {
        context.res = {
            status: 401,
            body: 'token was wrong expired or missing'
        };
        context.done();
    }
};

function updateItem(eventId, userId, callback) {
    client.readDocument(eventId, (err, result) => {
        if (err) {
            callback(err);
        }
        else {
            let event = result;
            event.partticipants =  event.participants.splice(event.participants.findIndex(part => part.userId === userId),1);

            client.replaceDocument(eventId, event, (repErr, repRes) => {
                if (repErr) {
                    callback(repErr);
                }
                else {
                    callback(null, 'unscribed');
                }
            });
        }
    });
}
<|endoftext|>


<commit_before>// Set listeners for rendering based on user status.
// Listener that triggers when a new or different user signs in.
var userChanged = setIcons;

// Listener that triggers when sign-in status changes (but not when user changes).
var signInChanged = function(signedIn) {
  if (!signedIn) {
    const recipeCards = document.getElementsByClassName("recipe-card");
    for (let i = 0; i < recipeCards.length; i++) {
      let recipeCard = recipeCards[i];
      const addToCookbookButton = recipeCard.getElementsByClassName("add-to-cookbook-btn")[0];
      const addToPlannerButton = recipeCard.getElementsByClassName("add-to-planner-btn")[0];
      // removes the checkmark (nothing happens if the class does not exist)
      addToCookbookButton.classList.remove("fa-check");
      addToPlannerButton.classList.remove("fa-check");
      // adds the plus sign (nothing is added if it already exists)
      addToCookbookButton.classList.add("fa-plus");
      addToPlannerButton.classList.add("fa-plus");
    }
  }
}

/**
 * Takes the recipe info of a recipe as a JS object and the div that the recipe
 * card will be added to. Creates only one recipe card. For the method to work,
 * recipeInfo is expected to have the following data saved as properties,
 * regardless of the explicit property name:
 * a recipe name, a recipe description, and a recipe
 */
createRecipeCard = (divID, recipeInfo) => {
  let docDiv = document.getElementById(divID);

  let recipeDiv = createElement("div", "", {"class": "recipe-card"});
  let imageDiv = createElement("div", "", {"class": "image-div"});
  let textDiv = createElement("div", "", {"class": "text-div"});

  const id = recipeInfo["id"];
  const name = recipeInfo["name"];

  const addToPlannerButton = createElement("button", " Planner", {"class": "card-button action-button bottom more-left add-to-planner-btn fas fa-plus"});
  addToPlannerButton.addEventListener('click', () => manageList("add", id, name, "planner"));

  const addToCookbookButton = createElement("button", " Cookbook", {"class": "card-button action-button bottom more-right add-to-cookbook-btn fas fa-plus"});
  addToCookbookButton.addEventListener('click', () => manageList("add", id, name, "cookbook"));

  const removeFromPlannerButton = createElement("button", " Planner ", {"class": "card-button action-button bottom more-left fa fa-remove remove-from-planner-btn"});
  removeFromPlannerButton.addEventListener('click', () => manageList("remove", id, name, "planner"));
  removeFromPlannerButton.style.display = "none";

  const removeFromToCookbookButton = createElement("button", " Cookbook ", {"class": "card-button action-button bottom more-right fa fa-remove remove-from-cookbook-btn"});
  removeFromToCookbookButton.addEventListener('click', () => manageList("remove", id, name, "cookbook"));
  removeFromToCookbookButton.style.display = "none";

  let elementsToAddToImageDiv = [
    createImage(recipeInfo["name"], recipeInfo["imageBlobKey"]),
    addToPlannerButton, addToCookbookButton, removeFromPlannerButton, removeFromToCookbookButton,
  ];
  elementsToAddToImageDiv.forEach(elem => imageDiv.appendChild(elem));
  let elementsToAddToTextDiv = [
    createElement("button", recipeInfo["name"],
      {"class": "recipe-card-name",
      "onClick": "redirectRecipePage(" + recipeInfo["id"].toString() + ")"}),
    createElement("p", recipeInfo["id"], {"class": "hidden recipe-id"}),
    createElement("p", recipeInfo["description"], {"class": "recipe-card-description"}),
  ];
  elementsToAddToTextDiv.forEach(elem => textDiv.appendChild(elem));

  let allElementsToAdd = [imageDiv, textDiv];
  allElementsToAdd.forEach(elem => recipeDiv.appendChild(elem));
  docDiv.appendChild(recipeDiv);
}

/**
 * Takes the id for a recipe in Datastore, and redirects to the recipe page template
 * with the recipe ID as a search param.
 */
function redirectRecipePage(id) {
  window.location.assign("/pages/RecipePageTemplate.jsp?id=" + id.toString());
}

/**
 * Function for loading the recipe template page based on the id in the URL
 * search params.
 */
async function fillRecipeTemplate() {
  const recipeId = (new URL(document.location)).searchParams.get("id");

  // Gets the servlet data for the recipe
  // TODO: put this code in an if statement to handle recipe not found scenarios
  let response = await fetch("/search-id?recipeId=" + recipeId.toString());
  let responseText = await response.text();
  let recipeInfo = JSON.parse(responseText);

  let detailsSection = document.getElementById("details");
  let imageSection = document.getElementById("image-container");
  let descriptionSection = document.getElementById("description");
  let ingredientSection = document.getElementById("ingredients");
  let stepsSection = document.getElementById("steps");

  const id = recipeInfo["id"];
  const name = recipeInfo["name"];

  const addToPlannerButton = createElement("button", " Planner", {"class": "card-button action-button bottom more-left add-to-planner-btn fas fa-plus"});
  addToPlannerButton.addEventListener('click', () => manageList("add", id, name, "planner"));

  const addToCookbookButton = createElement("button", " Cookbook", {"class": "card-button action-button bottom more-right add-to-cookbook-btn fas fa-plus"});
  addToCookbookButton.addEventListener('click', () => manageList("add", id, name, "cookbook"));

  addRecipeInfo(recipeInfo, detailsSection);
  imageSection.appendChild(createImage(recipeInfo["name"], recipeInfo["imageBlobKey"]));
  descriptionSection.appendChild(createElement(
      "p", recipeInfo["description"], {"id": "description-text"}));
  addAsList(recipeInfo["ingredients"], ingredientSection, "Ingredients");
  addAsList(recipeInfo["steps"], stepsSection, "Steps");
}

/**
 * Creates the HTML for the information about the recipe and adds it to the div.
 * Current implementation adds the recipe name and the author.
 * Takes the recipe object and div (not div name) being used.
 */
addRecipeInfo = (recipeObj, infoDiv) => {
  let elementsForDiv = [
    createElement("h1", recipeObj["name"], {"id": "recipe-name"})/*,
    createElement("h3", recipeObj["author"], {"id": "recipe-author"})*/
    // Uncomment once the backend can handle sending author info too
  ];

  // Adds all the recipe info to the passed div
  elementsForDiv.forEach(elem => infoDiv.appendChild(elem));
}

/**
 * Creates the HTML for some part of the recipe which needs to shown as a list
 * (ingredients, steps, etc.) and adds it to the given div.
 * Takes a list and div (not div name) being used.
 */
addAsList = (listObj, listDiv, listName) => {
  // Constructs the base of how all item created in the function will be
  // named for CSS
  let cssRef = listName.toLowerCase() + "-list";

  // Creates the title for the list, and the list element
  let listForDiv = createElement("ol", "", {"id": cssRef})
  let listTitle = createElement("h2", listName, {"id": cssRef + "-title"});

  // Goes through all the objects in listObj and adds them as items to listForDiv
  listObj.forEach(item => listForDiv.appendChild(
    createElement("li", item, {"class": cssRef + "-item"})));

  listDiv.appendChild(listTitle);
  listDiv.appendChild(listForDiv);
}

/**
 * Takes an object which can be represented as a string or a string, an html
 * tag, and the html tag options stored as an object. Returns the reference to the
 * constructed html element.
 * Default values are set for object and tag options for instances where these aren't
 * needed, such as when making a new container div.
 */
createElement = (htmlTag, object = "", tagOptions = {}) => {
  // Create an HTML element with the given tag
  let htmlElement = document.createElement(htmlTag.toLowerCase());

  // If the object parameter is not null or an empty string, it
  // creates a textnode and adds it to the HTML element
  if (object !== null && object !== "") {
    let htmlText = document.createTextNode(object);
    htmlElement.appendChild(htmlText);
  }

  // If the tagOptions object is not null or empty, it goes through each
  // option and adds the attribute to the new HTML element.
  if (tagOptions !== null && Object.keys(tagOptions).length > 0) {
    for (opt in tagOptions) {
      htmlElement.setAttribute(opt, tagOptions[opt]);
    }
  }
  return htmlElement;
}

/**
 * Takes two objects which represent the name and the blobkey
 * Returns the reference to the constructed image element.
 */
createImage = (name, blobkey) => {
  let imageElement = document.createElement('img');
  imageElement.alt = name + " image";
  imageElement.className = "recipe-card-image";
  imageElement.src = "/serve?blobkey="+blobkey;
  return imageElement;
}

function setIcons() {
  const recipeCards = document.getElementsByClassName("recipe-card");
  for (let i = 0; i < recipeCards.length; i++) {
    const recipeCard = recipeCards[i];
    const recipeID = recipeCard.getElementsByClassName("recipe-id")[0].innerText;
    const addToPlannerButton = recipeCard.getElementsByClassName("add-to-planner-btn")[0];
    const addToCookbookButton = recipeCard.getElementsByClassName("add-to-cookbook-btn")[0];

    setIcon(addToPlannerButton, recipeID, "planner");
    setIcon(addToCookbookButton, recipeID, "cookbook");
  }
}

/**
 * Sets the icon of the button to a checkmark if already added to list
 * and a plus otherwise
 * Takes in button you wish to change, the id of the recipe its part of, and which
 * list the button is adding to
 */
function setIcon(button, id, type) {
  if (auth2 != null && auth2.isSignedIn.get()) {
    const idToken = getIdToken();
    // checks if the current recipe is in the user's planner
    fetch("/manage-list?id=" + id + "&idToken=" + idToken + "&type=" + type)
        .then(response => response.text()).then((contains) => {
      if ((/true/i).test(contains)) {
        button.classList.remove("fa-plus");
        button.classList.add("fa-check");
      }
    });
  }
}

// lets the user know if they have already added a recipe to a particular list
// otherwise adds the recipe
function manageList(action, id, name, type) {
  let idToken;
  confirmUser().then((googleUser) => {
    idToken = getIdToken();
    fetch("/manage-list?id=" + id + "&idToken=" + idToken + "&type=" + type)
        .then(response => response.text()).then((contains) => {
      if ((/true/i).test(contains)) {
        if (action == "add") {
          // if the user is trying to add a recipe and the list already contains it
          // alerts the user that the recipe is already in the list
          alert("You have already added the " + name + " recipe to your " + type);
        } else {
          // if the user is trying to remove a precipe and the list contains it
          // asks the user to confirm that they wish to remove the recipe
          const confirmedRemove = confirm("Are you sure you want to remove the " + name + " recipe from your " + type + "?");
          // tells the server to remove the recipe's key from the user's cookbook/planner
          if (confirmedRemove) {
            const params = new URLSearchParams();
            params.append("action", action);
            params.append("id", id);
            params.append("idToken", getIdToken());
            params.append("type", type);
            fetch("/manage-list", {method: "POST", body: params});
            if (document.URL.includes("UserPage")) {
              location.reload();
            }
          }
        }
      } else {
        if (action == "add") {
          // if the user is trying to add a recipe not already in the list
          const params = new URLSearchParams();
          params.append("action", action);
          params.append("id", id);
          params.append("idToken", getIdToken());
          params.append("type", type);
          fetch("/manage-list", {method: "POST", body: params});
          // finds the button that was clicked using the recipe id
          let recipeCards = document.getElementsByClassName("recipe-card");
          for (let i = 0; i < recipeCards.length; i++) {
            let recipeID = recipeCards[i].getElementsByClassName("recipe-id")[0].innerText;
            let button = recipeCards[i].getElementsByClassName("add-to-" + type + "-btn")[0];
            if (recipeID == id) {
              // makes the icon a checkmark
              button.classList.remove("fa-plus");
              button.classList.add("fa-check");
              break;
            }
          }
          if (document.URL.includes("UserPage")) {
            location.reload();
          }
        }
      }
    });
  });
}
<commit_msg>remove code<commit_after>// Set listeners for rendering based on user status.
// Listener that triggers when a new or different user signs in.
var userChanged = setIcons;

// Listener that triggers when sign-in status changes (but not when user changes).
var signInChanged = function(signedIn) {
  if (!signedIn) {
    const recipeCards = document.getElementsByClassName("recipe-card");
    for (let i = 0; i < recipeCards.length; i++) {
      let recipeCard = recipeCards[i];
      const addToCookbookButton = recipeCard.getElementsByClassName("add-to-cookbook-btn")[0];
      const addToPlannerButton = recipeCard.getElementsByClassName("add-to-planner-btn")[0];
      // removes the checkmark (nothing happens if the class does not exist)
      addToCookbookButton.classList.remove("fa-check");
      addToPlannerButton.classList.remove("fa-check");
      // adds the plus sign (nothing is added if it already exists)
      addToCookbookButton.classList.add("fa-plus");
      addToPlannerButton.classList.add("fa-plus");
    }
  }
}

/**
 * Takes the recipe info of a recipe as a JS object and the div that the recipe
 * card will be added to. Creates only one recipe card. For the method to work,
 * recipeInfo is expected to have the following data saved as properties,
 * regardless of the explicit property name:
 * a recipe name, a recipe description, and a recipe
 */
createRecipeCard = (divID, recipeInfo) => {
  let docDiv = document.getElementById(divID);

  let recipeDiv = createElement("div", "", {"class": "recipe-card"});
  let imageDiv = createElement("div", "", {"class": "image-div"});
  let textDiv = createElement("div", "", {"class": "text-div"});

  const id = recipeInfo["id"];
  const name = recipeInfo["name"];

  const addToPlannerButton = createElement("button", " Planner", {"class": "card-button action-button bottom more-left add-to-planner-btn fas fa-plus"});
  addToPlannerButton.addEventListener('click', () => manageList("add", id, name, "planner"));

  const addToCookbookButton = createElement("button", " Cookbook", {"class": "card-button action-button bottom more-right add-to-cookbook-btn fas fa-plus"});
  addToCookbookButton.addEventListener('click', () => manageList("add", id, name, "cookbook"));

  const removeFromPlannerButton = createElement("button", " Planner ", {"class": "card-button action-button bottom more-left fa fa-remove remove-from-planner-btn"});
  removeFromPlannerButton.addEventListener('click', () => manageList("remove", id, name, "planner"));
  removeFromPlannerButton.style.display = "none";

  const removeFromToCookbookButton = createElement("button", " Cookbook ", {"class": "card-button action-button bottom more-right fa fa-remove remove-from-cookbook-btn"});
  removeFromToCookbookButton.addEventListener('click', () => manageList("remove", id, name, "cookbook"));
  removeFromToCookbookButton.style.display = "none";

  let elementsToAddToImageDiv = [
    createImage(recipeInfo["name"], recipeInfo["imageBlobKey"]),
    addToPlannerButton, addToCookbookButton, removeFromPlannerButton, removeFromToCookbookButton,
  ];
  elementsToAddToImageDiv.forEach(elem => imageDiv.appendChild(elem));
  let elementsToAddToTextDiv = [
    createElement("button", recipeInfo["name"],
      {"class": "recipe-card-name",
      "onClick": "redirectRecipePage(" + recipeInfo["id"].toString() + ")"}),
    createElement("p", recipeInfo["id"], {"class": "hidden recipe-id"}),
    createElement("p", recipeInfo["description"], {"class": "recipe-card-description"}),
  ];
  elementsToAddToTextDiv.forEach(elem => textDiv.appendChild(elem));

  let allElementsToAdd = [imageDiv, textDiv];
  allElementsToAdd.forEach(elem => recipeDiv.appendChild(elem));
  docDiv.appendChild(recipeDiv);
}

/**
 * Takes the id for a recipe in Datastore, and redirects to the recipe page template
 * with the recipe ID as a search param.
 */
function redirectRecipePage(id) {
  window.location.assign("/pages/RecipePageTemplate.jsp?id=" + id.toString());
}

/**
 * Function for loading the recipe template page based on the id in the URL
 * search params.
 */
async function fillRecipeTemplate() {
  const recipeId = (new URL(document.location)).searchParams.get("id");

  // Gets the servlet data for the recipe
  // TODO: put this code in an if statement to handle recipe not found scenarios
  let response = await fetch("/search-id?recipeId=" + recipeId.toString());
  let responseText = await response.text();
  let recipeInfo = JSON.parse(responseText);

  let detailsSection = document.getElementById("details");
  let imageSection = document.getElementById("image-container");
  let descriptionSection = document.getElementById("description");
  let ingredientSection = document.getElementById("ingredients");
  let stepsSection = document.getElementById("steps");

  addRecipeInfo(recipeInfo, detailsSection);
  imageSection.appendChild(createImage(recipeInfo["name"], recipeInfo["imageBlobKey"]));
  descriptionSection.appendChild(createElement(
      "p", recipeInfo["description"], {"id": "description-text"}));
  addAsList(recipeInfo["ingredients"], ingredientSection, "Ingredients");
  addAsList(recipeInfo["steps"], stepsSection, "Steps");
}

/**
 * Creates the HTML for the information about the recipe and adds it to the div.
 * Current implementation adds the recipe name and the author.
 * Takes the recipe object and div (not div name) being used.
 */
addRecipeInfo = (recipeObj, infoDiv) => {
  let elementsForDiv = [
    createElement("h1", recipeObj["name"], {"id": "recipe-name"})/*,
    createElement("h3", recipeObj["author"], {"id": "recipe-author"})*/
    // Uncomment once the backend can handle sending author info too
  ];

  // Adds all the recipe info to the passed div
  elementsForDiv.forEach(elem => infoDiv.appendChild(elem));
}

/**
 * Creates the HTML for some part of the recipe which needs to shown as a list
 * (ingredients, steps, etc.) and adds it to the given div.
 * Takes a list and div (not div name) being used.
 */
addAsList = (listObj, listDiv, listName) => {
  // Constructs the base of how all item created in the function will be
  // named for CSS
  let cssRef = listName.toLowerCase() + "-list";

  // Creates the title for the list, and the list element
  let listForDiv = createElement("ol", "", {"id": cssRef})
  let listTitle = createElement("h2", listName, {"id": cssRef + "-title"});

  // Goes through all the objects in listObj and adds them as items to listForDiv
  listObj.forEach(item => listForDiv.appendChild(
    createElement("li", item, {"class": cssRef + "-item"})));

  listDiv.appendChild(listTitle);
  listDiv.appendChild(listForDiv);
}

/**
 * Takes an object which can be represented as a string or a string, an html
 * tag, and the html tag options stored as an object. Returns the reference to the
 * constructed html element.
 * Default values are set for object and tag options for instances where these aren't
 * needed, such as when making a new container div.
 */
createElement = (htmlTag, object = "", tagOptions = {}) => {
  // Create an HTML element with the given tag
  let htmlElement = document.createElement(htmlTag.toLowerCase());

  // If the object parameter is not null or an empty string, it
  // creates a textnode and adds it to the HTML element
  if (object !== null && object !== "") {
    let htmlText = document.createTextNode(object);
    htmlElement.appendChild(htmlText);
  }

  // If the tagOptions object is not null or empty, it goes through each
  // option and adds the attribute to the new HTML element.
  if (tagOptions !== null && Object.keys(tagOptions).length > 0) {
    for (opt in tagOptions) {
      htmlElement.setAttribute(opt, tagOptions[opt]);
    }
  }
  return htmlElement;
}

/**
 * Takes two objects which represent the name and the blobkey
 * Returns the reference to the constructed image element.
 */
createImage = (name, blobkey) => {
  let imageElement = document.createElement('img');
  imageElement.alt = name + " image";
  imageElement.className = "recipe-card-image";
  imageElement.src = "/serve?blobkey="+blobkey;
  return imageElement;
}

function setIcons() {
  const recipeCards = document.getElementsByClassName("recipe-card");
  for (let i = 0; i < recipeCards.length; i++) {
    const recipeCard = recipeCards[i];
    const recipeID = recipeCard.getElementsByClassName("recipe-id")[0].innerText;
    const addToPlannerButton = recipeCard.getElementsByClassName("add-to-planner-btn")[0];
    const addToCookbookButton = recipeCard.getElementsByClassName("add-to-cookbook-btn")[0];

    setIcon(addToPlannerButton, recipeID, "planner");
    setIcon(addToCookbookButton, recipeID, "cookbook");
  }
}

/**
 * Sets the icon of the button to a checkmark if already added to list
 * and a plus otherwise
 * Takes in button you wish to change, the id of the recipe its part of, and which
 * list the button is adding to
 */
function setIcon(button, id, type) {
  if (auth2 != null && auth2.isSignedIn.get()) {
    const idToken = getIdToken();
    // checks if the current recipe is in the user's planner
    fetch("/manage-list?id=" + id + "&idToken=" + idToken + "&type=" + type)
        .then(response => response.text()).then((contains) => {
      if ((/true/i).test(contains)) {
        button.classList.remove("fa-plus");
        button.classList.add("fa-check");
      }
    });
  }
}

// lets the user know if they have already added a recipe to a particular list
// otherwise adds the recipe
function manageList(action, id, name, type) {
  let idToken;
  confirmUser().then((googleUser) => {
    idToken = getIdToken();
    fetch("/manage-list?id=" + id + "&idToken=" + idToken + "&type=" + type)
        .then(response => response.text()).then((contains) => {
      if ((/true/i).test(contains)) {
        if (action == "add") {
          // if the user is trying to add a recipe and the list already contains it
          // alerts the user that the recipe is already in the list
          alert("You have already added the " + name + " recipe to your " + type);
        } else {
          // if the user is trying to remove a precipe and the list contains it
          // asks the user to confirm that they wish to remove the recipe
          const confirmedRemove = confirm("Are you sure you want to remove the " + name + " recipe from your " + type + "?");
          // tells the server to remove the recipe's key from the user's cookbook/planner
          if (confirmedRemove) {
            const params = new URLSearchParams();
            params.append("action", action);
            params.append("id", id);
            params.append("idToken", getIdToken());
            params.append("type", type);
            fetch("/manage-list", {method: "POST", body: params});
            if (document.URL.includes("UserPage")) {
              location.reload();
            }
          }
        }
      } else {
        if (action == "add") {
          // if the user is trying to add a recipe not already in the list
          const params = new URLSearchParams();
          params.append("action", action);
          params.append("id", id);
          params.append("idToken", getIdToken());
          params.append("type", type);
          fetch("/manage-list", {method: "POST", body: params});
          // finds the button that was clicked using the recipe id
          let recipeCards = document.getElementsByClassName("recipe-card");
          for (let i = 0; i < recipeCards.length; i++) {
            let recipeID = recipeCards[i].getElementsByClassName("recipe-id")[0].innerText;
            let button = recipeCards[i].getElementsByClassName("add-to-" + type + "-btn")[0];
            if (recipeID == id) {
              // makes the icon a checkmark
              button.classList.remove("fa-plus");
              button.classList.add("fa-check");
              break;
            }
          }
          if (document.URL.includes("UserPage")) {
            location.reload();
          }
        }
      }
    });
  });
}
<|endoftext|>


<commit_before>import {compareTranspiled} from "./helpers";

describe('require', () => {
	test('should change relative paths', () => {
		return compareTranspiled("examples/require/relative2relative");
	});

	test('should change relative paths dynamically', () => {
		return compareTranspiled("examples/require/relative2relativeD");
	});

	test('should change path from a node module to relative', () => {
		return compareTranspiled("examples/require/module2relative");
	});

	test('should dynamically change path from a node module to relative', () => {
		return compareTranspiled("examples/require/module2relativeD");
	});

	test('should change path from a node module to a different node module', () => {
		return compareTranspiled("examples/require/module2module");
	});

	test('should dynamically change path from a node module to a different node module', () => {
		return compareTranspiled("examples/require/module2moduleD");
	});

	test('should change path from relative to a node module', () => {
		return compareTranspiled("examples/require/relative2module");
	});

	test('should dynamically change path from relative to a node module', () => {
		return compareTranspiled("examples/require/relative2moduleD");
	});

	test('should not change when no matching redirect is found', () => {
		return compareTranspiled("examples/require/no_match");
	});

	describe('should change even when', () => {
		test('file at original relative path doesn\'t exist', () => {
			return compareTranspiled("examples/require/original_relative_not_exist");
		});

		test('file at the final path doesn\'t exist', () => {
			return compareTranspiled("examples/require/final_relative_not_exist");
		});

		test('module at original path doesn\'t exist', () => {
			return compareTranspiled("examples/require/original_module_not_exist");
		});

		test('module at the final path doesn\'t exist', () => {
			return compareTranspiled("examples/require/final_module_not_exist");
		});
	});
});<commit_msg>refactor(tests): Refactor require tests to later extend to import/export<commit_after>import {compareTranspiled} from "./helpers";

const tests = {
	'should change relative paths': "examples/require/relative2relative",
	'should change relative paths dynamically': "examples/require/relative2relativeD",
	'should change path from a node module to relative': "examples/require/module2relative",
	'should dynamically change path from a node module to relative': "examples/require/module2relativeD",
	'should change path from a node module to a different node module': "examples/require/module2module",
	'should dynamically change path from a node module to a different node module': "examples/require/module2moduleD",
	'should change path from relative to a node module': "examples/require/relative2module",
	'should dynamically change path from relative to a node module': "examples/require/relative2moduleD",
	'should not change when no matching redirect is found': "examples/require/no_match",
	'should change even when': {
		'file at original relative path doesn\'t exist': "examples/require/original_relative_not_exist",
		'file at the final path doesn\'t exist': "examples/require/final_relative_not_exist",
		'module at original path doesn\'t exist': "examples/require/original_module_not_exist",
		'module at the final path doesn\'t exist': "examples/require/final_module_not_exist"
	}
};

const declarations = ["reqiuire"];

function describeTests(tests) {
	Object.keys(tests).map(description => {
		const dir = tests[description];
		if(typeof dir === "object") {
			describe(description, () => {
				describeTests(dir);
			});
		} else {
			test(description, () => {
				console.log(description);
				return compareTranspiled(dir);
			});
		}
	});
}

for(let decl of declarations) {
	describe(decl, () => {
		describeTests(tests);
	});
}<|endoftext|>


<commit_before>var util = require('util');
var bleno = require('bleno');
var redis = require("redis");

var publisher  = redis.createClient();
var channel = 'msg.ble.2.uart';

var BlenoCharacteristic = bleno.Characteristic;

var characterID = '9a10ba1d-cd1c-4f00-9cca-1f3178d5fe8a';

var DBCCharacteristic = function() {
  DBCCharacteristic.super_.call(this, {
    uuid: characterID,
    properties: ['read', 'write', 'notify'],
    value: null
  });

  this._value = new Buffer(0);
  this._updateValueCallback = null;
};

util.inherits(DBCCharacteristic, BlenoCharacteristic);

DBCCharacteristic.prototype.onReadRequest = function(offset, callback) {
  console.log('DBCCharacteristic - onReadRequest: value = ' + this._value.toString('hex'));

  callback(this.RESULT_SUCCESS, this._value);
};

DBCCharacteristic.prototype.onWriteRequest = function(data, offset, withoutResponse, callback) {
  this._value = data;

  //console.log('DBCCharacteristic - onWriteRequest: value = ' + this._value.toString('hex'));
  console.log('DBCCharacteristic - onWriteRequest: value = ' + this._value);
  publisher.publish(channel, this._value);
  if (this._updateValueCallback) {
    console.log('DBCCharacteristic - onWriteRequest: notifying');

    this._updateValueCallback(this._value);
  }

  callback(this.RESULT_SUCCESS);
};

DBCCharacteristic.prototype.onSubscribe = function(maxValueSize, updateValueCallback) {
  console.log('DBCCharacteristic - onSubscribe');

  this._updateValueCallback = updateValueCallback;
};

DBCCharacteristic.prototype.onUnsubscribe = function() {
  console.log('DBCCharacteristic - onUnsubscribe');

  this._updateValueCallback = null;
};

module.exports = DBCCharacteristic;
<commit_msg>Update characteristic.js<commit_after>var util = require('util');
var bleno = require('bleno');
var redis = require("redis");

var publisher  = redis.createClient();
var channel = '/dbc/webui2uart';

var BlenoCharacteristic = bleno.Characteristic;

var characterID = '9a10ba1d-cd1c-4f00-9cca-1f3178d5fe8a';

var DBCCharacteristic = function() {
  DBCCharacteristic.super_.call(this, {
    uuid: characterID,
    properties: ['read', 'write', 'notify'],
    value: null
  });

  this._value = new Buffer(0);
  this._updateValueCallback = null;
};

util.inherits(DBCCharacteristic, BlenoCharacteristic);

DBCCharacteristic.prototype.onReadRequest = function(offset, callback) {
  console.log('DBCCharacteristic - onReadRequest: value = ' + this._value.toString('hex'));

  callback(this.RESULT_SUCCESS, this._value);
};

DBCCharacteristic.prototype.onWriteRequest = function(data, offset, withoutResponse, callback) {
  this._value = data;

  //console.log('DBCCharacteristic - onWriteRequest: value = ' + this._value.toString('hex'));
  console.log('DBCCharacteristic - onWriteRequest: value=<',this._value,'>');
  publisher.publish(channel, this._value);
  if (this._updateValueCallback) {
    console.log('DBCCharacteristic - onWriteRequest: notifying');

    this._updateValueCallback(this._value);
  }

  callback(this.RESULT_SUCCESS);
};

DBCCharacteristic.prototype.onSubscribe = function(maxValueSize, updateValueCallback) {
  console.log('DBCCharacteristic - onSubscribe');

  this._updateValueCallback = updateValueCallback;
};

DBCCharacteristic.prototype.onUnsubscribe = function() {
  console.log('DBCCharacteristic - onUnsubscribe');

  this._updateValueCallback = null;
};

module.exports = DBCCharacteristic;
<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process');
var request = require('request');
var Promise = require('bluebird');
var qs = require('querystring')

var env = process.env.NODE_ENV;

if(!env){
	console.error("Please set NODE_ENV variable.");
	return 1;
}

var VIEWSDIR = 'views/';

const getConfigFile = function (env, base_directory) {
  try {
    // Try to load the user's personal configuration file
    return require(base_directory + '/conf.my.' + env + '.json');
  } catch (e) {
    // Else, read the default configuration file
    return require(base_directory + '/conf.' + env + '.json');
  }
};

const getAllProviders = function(conf){
	var temp = [];
	for(var servercodename in conf.couchdblist){
    	var couchdbparams = conf.couchdblist[servercodename];
    	temp.push(couchdbparams.couchdb + couchdbparams.database);
    }
	return temp;
}

const createDB = function(name){
	return new Promise(function(resolve, reject){
		request.put(name, function(err, res, body){
			if(err) reject(err.message);
			try{
				if(JSON.parse(body).error === "not_found"){
					request.put(name, function(err, res, body){
						resolve(JSON.parse(body));
					});
				}else{
					resolve(JSON.parse(body));
				}
			}catch(e){
				console.error(name);
				console.error(e);
				reject(e);
			}

		})
	});
}

const updateDocuments = function(db, viewsdir){

	var fileviews = fs.readdirSync(viewsdir);

	var testView = function(file){
		return new Promise(function(resolve, reject){
			try{
				if(file.indexOf(".json") === -1) reject(file);

				fs.readFile(viewsdir+file, function (err, data) {
					if (err) throw err;

					var designdoc = JSON.parse(data);

					var options = {
						uri: db + "/" + designdoc._id
					}

					request(options, function(err, res, body){
						var couchdesigndoc = body;

				  		if(JSON.stringify(designdoc.views) !== JSON.stringify(couchdesigndoc.views)){

				  			var uri = db + "/" + designdoc._id;
				  			if(couchdesigndoc._rev){
				  				designdoc._rev = couchdesigndoc._rev;
				  				uri += "?rev="+designdoc._rev;
				  			}

					  		var options = {
								uri :  uri,
								method : 'PUT',
								json : designdoc
							}

							request(options, function(err, res, body){
								if(err) reject(err.message);
								resolve(body);
							});

					  	}else{
				  			console.log("No changes in document: " + viewsdir+file + ", in db: " + db);
				  		}
					});
				});
			}catch(e){
				reject(e);
			}
		});
	}

	return Promise.map(fileviews, testView);
}

var conf = getConfigFile(env, "../");
var dataprovider = conf.dataproviders[conf.default.dataprovider];
var clusterdb = dataprovider.hostname + "/" + dataprovider.database;

createDB(clusterdb)
.then(function(result){
	return updateDocuments(clusterdb, VIEWSDIR);
})
.then(console.log)
.catch(console.error)

<commit_msg>BUG: Change the views dir to use complete path<commit_after>var fs = require('fs');
var child_process = require('child_process');
var request = require('request');
var Promise = require('bluebird');
var qs = require('querystring');
var path = require('path');

var env = process.env.NODE_ENV;

if(!env){
	console.error("Please set NODE_ENV variable.");
	return 1;
}

const getConfigFile = function (env, base_directory) {
  try {
    // Try to load the user's personal configuration file
    return require(base_directory + '/conf.my.' + env + '.json');
  } catch (e) {
    // Else, read the default configuration file
    return require(base_directory + '/conf.' + env + '.json');
  }
};

const getAllProviders = function(conf){
	var temp = [];
	for(var servercodename in conf.couchdblist){
    	var couchdbparams = conf.couchdblist[servercodename];
    	temp.push(couchdbparams.couchdb + couchdbparams.database);
    }
	return temp;
}

const createDB = function(name){
	return new Promise(function(resolve, reject){
		request.put(name, function(err, res, body){
			if(err) reject(err.message);
			try{
				if(JSON.parse(body).error === "not_found"){
					request.put(name, function(err, res, body){
						resolve(JSON.parse(body));
					});
				}else{
					resolve(JSON.parse(body));
				}
			}catch(e){
				console.error(name);
				console.error(e);
				reject(e);
			}

		})
	});
}

const updateDocuments = function(db, viewsdir){

	var fileviews = fs.readdirSync(viewsdir);

	var testView = function(file){
		return new Promise(function(resolve, reject){
			try{
				if(file.indexOf(".json") === -1) reject(file);

				fs.readFile(viewsdir+file, function (err, data) {
					if (err) throw err;

					var designdoc = JSON.parse(data);

					var options = {
						uri: db + "/" + designdoc._id
					}

					request(options, function(err, res, body){
						var couchdesigndoc = body;

				  		if(JSON.stringify(designdoc.views) !== JSON.stringify(couchdesigndoc.views)){

				  			var uri = db + "/" + designdoc._id;
				  			if(couchdesigndoc._rev){
				  				designdoc._rev = couchdesigndoc._rev;
				  				uri += "?rev="+designdoc._rev;
				  			}

					  		var options = {
								uri :  uri,
								method : 'PUT',
								json : designdoc
							}

							request(options, function(err, res, body){
								if(err) reject(err.message);
								resolve(body);
							});

					  	}else{
				  			console.log("No changes in document: " + viewsdir+file + ", in db: " + db);
				  		}
					});
				});
			}catch(e){
				reject(e);
			}
		});
	}

	return Promise.map(fileviews, testView);
}

var basedir = path.dirname(process.argv[1]);
var conf = getConfigFile(env, "../");
var dataprovider = conf.dataproviders[conf.default.dataprovider];
var clusterdb = dataprovider.hostname + "/" + dataprovider.database;
var viewsdir = basedir + '/views/';

createDB(clusterdb)
.then(function(result){
	return updateDocuments(clusterdb, viewsdir);
})
.then(console.log)
.catch(console.error)

<|endoftext|>


<commit_before>angular.module('app.controllers').
	controller('AddCtrl', ['$scope', '$rootScope', 'bookmarkFactory', '$state', '$stateParams',
		function($scope, $rootScope, bookmarkFactory, $state, $stateParams) {

			console.log("Add new bookmark...");

			$scope.model = {
				currentBookmark: {}
			};

			$scope.store = function() {
				bookmarkFactory.addBookmark($scope.model.currentBookmark).then(function(result) {
					console.log("Added new bookmark: " + $scope.model.currentBookmark.name);

					Liferay.fire('reloadBookmarks', {portletId: $scope.portletId});
					$state.go('list');
				});
			};
		}
	]
);<commit_msg>Formatting<commit_after>angular.module('app.controllers').
	controller('AddCtrl', ['$scope', '$rootScope', 'bookmarkFactory', '$state', '$stateParams',
		function($scope, $rootScope, bookmarkFactory, $state, $stateParams) {

			console.log("Add new bookmark...");

			$scope.model = {
				currentBookmark: {}
			};

			$scope.store = function() {
				bookmarkFactory.addBookmark($scope.model.currentBookmark).then(function(result) {
					console.log("Added new bookmark: " + $scope.model.currentBookmark.name);

					Liferay.fire('reloadBookmarks', { portletId: $scope.portletId });
					$state.go('list');
				});
			};
		}
	]
);<|endoftext|>


<commit_before>#!/usr/bin/env node

const path = require('path');
const proc = require('child_process');
const startCase = require('lodash.startcase');

const baseDir = process.argv[2];

const files = proc.execFileSync(
  'find', [baseDir, '-type', 'f'], { encoding: 'utf8' }
).split('\n').filter(s => s !== '');

console.log('.API');

const links = files.map((file) => {
    const doc = file.replace(baseDir, '');
    const title = path.parse(file).name;

    return {
      xref: `* xref:${doc}[${startCase(title)}]`,
      title,
    };
});

// Case-insensitive sort based on titles (so 'token/ERC20' gets sorted as 'erc20')
const sortedLinks = links.sort(function (a, b) {
  return a.title.toLowerCase().localeCompare(b.title.toLowerCase());
});

for (const link of sortedLinks) {
   console.log(link.xref);
}
<commit_msg>Fix linter errors<commit_after>#!/usr/bin/env node

const path = require('path');
const proc = require('child_process');
const startCase = require('lodash.startcase');

const baseDir = process.argv[2];

const files = proc.execFileSync(
  'find', [baseDir, '-type', 'f'], { encoding: 'utf8' }
).split('\n').filter(s => s !== '');

console.log('.API');

const links = files.map((file) => {
  const doc = file.replace(baseDir, '');
  const title = path.parse(file).name;

  return {
    xref: `* xref:${doc}[${startCase(title)}]`,
    title,
  };
});

// Case-insensitive sort based on titles (so 'token/ERC20' gets sorted as 'erc20')
const sortedLinks = links.sort(function (a, b) {
  return a.title.toLowerCase().localeCompare(b.title.toLowerCase());
});

for (const link of sortedLinks) {
  console.log(link.xref);
}
<|endoftext|>


<commit_before>var fs = require('fs');
var separator = '############################################################################\n';
var respId = 0;
var variables = require('./variables');
var feedback_chatId = variables['feedback_chatId'];

function processOnText(msg, match) {
    var resp = null;
    var timestamp = new Date();
    var messagesToSend = [];
    var openingh = require('./openingh');
    var chatId = msg.chat.id;

    //Mensas, die Abendessen Haben
    var dinner_dict = {
        "poly" : "Mensa Polyterrasse",
        "pizzapasta" : "food market - pizza pasta"
    }

    //Übersetzt den einfacheren Befehl zum komplizierteren Mensanamen im JSON
    var dict = {
                "cliff" : "Clausiusbar",
                "haoyi" : "Woka",
                "poly" : "Mensa Polyterrasse",
                "foodlab" : "foodLAB",
                "clausiusbar" : "Clausiusbar",
                "asia" : "Clausiusbar",
                "fusion" : "FUSION meal",
                "woka" : "Woka",
                "tannenbar" : "Tannenbar",
                "trailer" : "Foodtrailer ETZ",
                "dozentenfoyer" : "Dozentenfoyer",
                "grill" : "food market - grill bbQ",
                "pizzapasta" : "food market - pizza pasta",
                "green" : "food market - green day",
        };

    console.log(msg);
    console.log(JSON.stringify(match));
    fs.appendFile('logs/requests.log', separator + timestamp + '\n\n' + JSON.stringify(msg) + '\n' + separator, function (err) {
        console.log(err);
    });
    //Feedback
    if(match[0].indexOf('/feedback') != -1 || match[0].indexOf('/respond') != -1) {
        if (match[0] === '/feedback'){
            resp = '*Feedback für Dummies:*\n/feedback <Deine Nachricht>';

        }else if(match[0].indexOf('/feedback')!=-1){
            respId=chatId;
            fs.appendFile('logs/feedback.log', separator + '\n\n' + timestamp + '\n\n' + JSON.stringify(msg) + '\n\n', function (err) {
                console.log(err);
            });
            resp = 'Vielen Dank für Dein Feedback!';

            messagesToSend.push({chatId:-106064170, message:'New feedback:\n\n' + JSON.stringify(msg)});
        }else if(match[0].indexOf('/respond') != -1){

            resp = match[0].split('respond');
            resp = resp[1];

            chatId = respId;
        }
    }else{
        //Chopping '@...' from the command if needed
        var command = match[1].split('@');
        command = command[0];
        //Nicht ideal weil ja nicht ein Strang, aber funktioniert so weit ganz gut (denke ich):
        //Checking whether a cafeteria has dinner and if its late enough to display the dinner menu
        if (command in dinner_dict && timestamp.getHours() >= 14){
            command = dinner_dict[command];
            var mensas = require('./mensas_abig.json');
            var t = 1;
        //Checking whether its a known cafeteria
        }else if (command in dict){
            command = dict[command];
            var mensas = require('./mensas.json');
            var t = 0;
        //...help/start, opening hours
        }

        if(command in openingh){
            resp = openingh[command];
        //Mensa
        }else if(command in mensas){

            //Weekend?
            if(timestamp.getDay() === 6 || timestamp.getDay() === 0){
                resp = "Heute haben leider alle Mensen geschlossen, sorry!";
            //If weekday, wanted information is formatted as follows:
            }else{
                //In case the cafeteria is closed
                resp = "Tut mir Leid, aber es sieht so aus als gäbe es für diese Mensa heute leider kein Menü.";

                resp = "*" + command + "*\n_Essen von " + mensas[command].hours.mealtime[t]["from"] +" bis " +mensas[command].hours.mealtime[t]["to"] + " Uhr_\n\n";
                for (var meal in mensas[command]["meals"]){
                    var description = "";
                    for (i in mensas[command]["meals"][meal]["description"]){
                        description += mensas[command]["meals"][meal]["description"][i]+ " " ;
                        if (i === "0"){
                            description += "\n";
                        }
                    }
                    resp += "*" +mensas[command]["meals"][meal]["label"] + " (" + mensas[command]["meals"][meal]["prices"]["student"]+ "/" +mensas[command]["meals"][meal]["prices"]["staff"] +  "/" + mensas[command]["meals"][meal]["prices"]["extern"]+"):*\n" + description + "\n";
                }
            }
        }
}

    messagesToSend.push({chatId:chatId, message:resp, options:{parse_mode: 'Markdown'}});

    fs.appendFile('logs/handled_requests.log', separator + timestamp + '\n\n' + JSON.stringify(msg,null,2) + '\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\nRESPONSE:\n\n' + resp + '\n', function (err) {
        console.log(err);
    });

    return messagesToSend;
}
module.exports.processOnText = processOnText;
<commit_msg>undid changes<commit_after>var fs = require('fs');
var separator = '############################################################################\n';
var respId = 0;
var variables = require('./variables');
var feedback_chatId = variables['feedback_chatId'];

function processOnText(msg, match) {
    var resp = null;
    var timestamp = new Date();
    var messagesToSend = [];
    var openingh = require('./openingh');
    var chatId = msg.chat.id;

    //Mensas, die Abendessen Haben
    var dinner_dict = {
        "poly" : "Mensa Polyterrasse",
        "pizzapasta" : "food market - pizza pasta"
    }

    //Übersetzt den einfacheren Befehl zum komplizierteren Mensanamen im JSON
    var dict = {
                "cliff" : "Clausiusbar",
                "haoyi" : "Woka",
                "poly" : "Mensa Polyterrasse",
                "foodlab" : "foodLAB",
                "clausiusbar" : "Clausiusbar",
                "asia" : "Clausiusbar",
                "fusion" : "FUSION meal",
                "woka" : "Woka",
                "tannenbar" : "Tannenbar",
                "trailer" : "Foodtrailer ETZ",
                "dozentenfoyer" : "Dozentenfoyer",
                "grill" : "food market - grill bbQ",
                "pizzapasta" : "food market - pizza pasta",
                "green" : "food market - green day",
        };

    console.log(msg);
    console.log(JSON.stringify(match));
    fs.appendFile('logs/requests.log', separator + timestamp + '\n\n' + JSON.stringify(msg) + '\n' + separator, function (err) {
        console.log(err);
    });
    //Feedback
    if(match[0].indexOf('/feedback') != -1 || match[0].indexOf('/respond') != -1) {
        if (match[0] === '/feedback'){
            resp = '*Feedback für Dummies:*\n/feedback <Deine Nachricht>';

        }else if(match[0].indexOf('/feedback')!=-1){
            respId=chatId;
            fs.appendFile('logs/feedback.log', separator + '\n\n' + timestamp + '\n\n' + JSON.stringify(msg) + '\n\n', function (err) {
                console.log(err);
            });
            resp = 'Vielen Dank für Dein Feedback!';

            messagesToSend.push({chatId:-106064170, message:'New feedback:\n\n' + JSON.stringify(msg)});
        }else if(match[0].indexOf('/respond') != -1){

            resp = match[0].split('respond');
            resp = resp[1];

            chatId = respId;
        }
    }else{
        //Chopping '@...' from the command if needed
        var command = match[1].split('@');
        command = command[0];
        //Nicht ideal weil ja nicht ein Strang, aber funktioniert so weit ganz gut (denke ich):
        //Checking whether a cafeteria has dinner and if its late enough to display the dinner menu
        if (command in dinner_dict && timestamp.getHours() >= 14){
            command = dinner_dict[command];
            var mensas = require('./mensas_abig.json');
            var t = 1;
        //Checking whether its a known cafeteria
        }else if (command in dict){
            command = dict[command];
            var mensas = require('./mensas.json');
            var t = 0;
        //...help/start, opening hours
        }

        if(command in openingh){
            resp = openingh[command];
        //Mensa
        }else if(command in mensas){

            //Weekend?
            if(timestamp.getDay() === 6 || timestamp.getDay() === 0){
                resp = "Heute haben leider alle Mensen geschlossen, sorry!";
            //If weekday, wanted information is formatted as follows:
            }else{
                resp = "*" + command + "*\n_Essen von " + mensas[command].hours.mealtime[t]["from"] +" bis " +mensas[command].hours.mealtime[t]["to"] + " Uhr_\n\n";
                for (var meal in mensas[command]["meals"]){
                    var description = "";
                    for (i in mensas[command]["meals"][meal]["description"]){
                        description += mensas[command]["meals"][meal]["description"][i]+ " " ;
                        if (i === "0"){
                            description += "\n";
                        }
                    }
                    resp += "*" +mensas[command]["meals"][meal]["label"] + " (" + mensas[command]["meals"][meal]["prices"]["student"]+ "/" +mensas[command]["meals"][meal]["prices"]["staff"] +  "/" + mensas[command]["meals"][meal]["prices"]["extern"]+"):*\n" + description + "\n";
                }
            }
        }
}

    messagesToSend.push({chatId:chatId, message:resp, options:{parse_mode: 'Markdown'}});

    fs.appendFile('logs/handled_requests.log', separator + timestamp + '\n\n' + JSON.stringify(msg,null,2) + '\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\nRESPONSE:\n\n' + resp + '\n', function (err) {
        console.log(err);
    });

    return messagesToSend;
}
module.exports.processOnText = processOnText;
<|endoftext|>


<commit_before>'use strict';

var async = require('async');

var logger = require.main.logger;
var config = require.main.config;

var Router = require('express').Router;
var router = new Router();

var ensureAuthenticated = require('../api').ensureAuthenticated;
var getRequestHeaders = require('../api').getRequestHeaders;
var traverson = require('traverson');

module.exports = router;

router.get('', ensureAuthenticated, getRepositories);

router.get('/:repositoryId/report',
  ensureAuthenticated,
  extractRepository,
  generateReport);

function getRepositories(req, res) {
  logger.trace('getRepositories');

  loadRepositories(req, function(err, repositories) {
    if (err) {
      return res.status(500).json({
        message: 'error requesting repository list'
      });
    }
    return res.json(repositories);
  });
}

function generateReport(req, res) {
  logger.trace('generateReport');

  var user = req.user;
  var repo = req.repository;
  var from = req.query.from;

  loadRepositoryIssues(user, repo, from, function(error, issues) {
    if (error) {
      return res.status(400).json(error);
    }
    return res.json(issues);
  });
}

function loadRepositories(req, fetchedCb) {
  logger.trace('loadRepositories');

  var user = req.user;

  if (user.repositories && user.repositories.length > 0) {
    return fetchedCb(null, user.repositories);
  }

  traverson.from('https://api.github.com')
  .json()
  .follow('current_user_repositories_url')
  .withRequestOptions({ headers: getRequestHeaders(user) })
  .getResource(function(error, resource) {
    if (error) {
      return fetchedCb(error);
    }

    var repositories = [];

    for (var i = 0; i < resource.length; i++) {
      var repo = {
        id: resource[i].id,
        name: resource[i].name,
        fullName: resource[i].full_name,
        description: resource[i].description,
        createdAt: resource[i].created_at,
        updatedAt: resource[i].updated_at,
        issuesUrl: resource[i].issues_url,
        reportUrl: config.server.baseUrl + req.originalUrl + '/' + resource[i].id + '/report{?from}'
      };
      repositories.push(repo);
    }

    user.repositories = repositories;
    return fetchedCb(null, repositories);
  });
}

function loadRepositoryIssues(user, repository, from, issuesLoadedCb) {
  loadFullPaginatedResource(user, repository.issuesUrl, { state: 'all', since: from }, function(error, issues) {
    if (error) {
      return issuesLoadedCb(error);
    }

    logger.debug('loadFullPaginatedResource returned ' + issues.length + ' issues');

    var relevant = { };

    async.each(issues, function(issue, doneCb) {
      // skip pull-requests
      if ('pull_request' in issue) {
        return doneCb();
      }

      loadInvolvedUsers(user, issue.events_url, function(err, involvedUsers) {
        logger.trace('loadInvolvedUsers for ' + issue.title + ' returned');

        if (err) {
          return doneCb(err);
        }

        var relevantParts = {
          title: issue.title,
          id: issue.id,
          number: issue.number,
          description: issue.body,
          labels: issue.labels,
          state: issue.state,
          assignee: (issue.assignee && {
            id: issue.assignee.id,
            login: issue.assignee.login
          }) || null,
          createdAt: issue.created_at,
          lastUpdate: issue.updated_at,
          closedAt: issue.closed_at,
          involvedUsers: []
        };

        // remove the assignee from the involved users list
        for (var i = 0; i < involvedUsers.length; i++) {
          if (involvedUsers[i].id === relevantParts.assignee.id) {
            relevantParts.involvedUsers = involvedUsers.splice(i, 1);
            break;
          }
        }

        var milestone = (issue.milestone && issue.milestone.title) || 'unassigned';

        if (!(milestone in relevant)) {
          relevant[milestone] = [];
        }

        relevant[milestone].push(relevantParts);

        logger.trace('exiting async.each for ' + issue.title);
        return doneCb();
      });
    }, function(err) {
      logger.trace('loadRepositoryIssues exit');
      issuesLoadedCb(err, relevant);
    });
  });
}

function loadInvolvedUsers(user, issueEventsUrl, usersFetchedCb) {
  loadFullPaginatedResource(user, issueEventsUrl, {}, function(error, events) {
    if (error) {
      return usersFetchedCb(error);
    }

    var mentionedUsers = [];
    for (var i = 0; i < events.length; i++) {
      var update = events[i];
      if (update.event === 'mentioned' && update.actor) {
        var mentioned = {
          id: update.actor.id,
          name: update.actor.login
        };
        var alreadyIn = false;
        for (var j = 0; j < mentionedUsers.length; j++) {
          if (mentionedUsers[j].id === mentioned.id) {
            alreadyIn = true;
            break;
          }
        }
        if (!alreadyIn) {
          mentionedUsers.push(mentioned);
        }
      }
    }
    usersFetchedCb(null, mentionedUsers);
  });
}

function loadFullPaginatedResource(user, link, queryOptions, fetchedCb, previousItems) {
  logger.trace('loadFullPaginatedResource', link, queryOptions);

  var items = previousItems || [];

  traverson.from(link)
  .withRequestOptions({
    headers: getRequestHeaders(user),
    qs: queryOptions
  })
  .get(function(error, response) {
    if (error) {
      return fetchedCb(error);
    }
    items = items.concat(JSON.parse(response.body));

    var links = parseLinkHeader(response.headers['link']);

    if (!links || !links.last || link === links.last || !links.next || links.next === '') {
      return fetchedCb(null, items);
    } else {
      // there are more pages to fetch!
      return loadFullPaginatedResource(user, links.next, queryOptions, fetchedCb, items);
    }
  });
}

var linkHeaderRegex = /^<(http[s]?:\/\/[a-z0-9\.]+\/.*?)>; rel="([a-z0-9]+)"$/i;

function parseLinkHeader(linkHeader) {
  logger.trace('parseLinkHeader', linkHeader);

  if (!linkHeader) {
    return null;
  }

  var links = {};

  if (linkHeader && typeof linkHeader === 'string') {
    var linkSegments = linkHeader.split(', ');

    for (var i = 0; i < linkSegments.length; i++) {
      var match = linkHeaderRegex.exec(linkSegments[i]);
      if (match) {
        links[match[2]] = match[1];
      }
    }
  }

  return links;
}

// middleware
function extractRepository(req, res, next) {
  logger.trace('extractRepository');

  if (!req.params.repositoryId) {
    return next();
  }

  var repositoryId = parseInt(req.params.repositoryId, 10);
  if (isNaN(repositoryId)) {
    return next({
      message: 'malformed repositoryId'
    });
  }

  if (!req.user.repositories) {
    return loadRepositories(req, function(error) {
      if (error) {
        return next(error);
      }
      return extractRepository(req, res, next);
    });
  }
  var repos = req.user.repositories;
  for (var i = 0; i < repos.length; i++) {
    if (repos[i].id === repositoryId) {
      req.repository = repos[i];
      return next();
    }
  }
  return next({
    message: 'invalid repositoryId'
  });
}
<commit_msg>Involved users now actually get added to the issue report<commit_after>'use strict';

var async = require('async');

var logger = require.main.logger;
var config = require.main.config;

var Router = require('express').Router;
var router = new Router();

var ensureAuthenticated = require('../api').ensureAuthenticated;
var getRequestHeaders = require('../api').getRequestHeaders;
var traverson = require('traverson');

module.exports = router;

router.get('', ensureAuthenticated, getRepositories);

router.get('/:repositoryId/report',
  ensureAuthenticated,
  extractRepository,
  generateReport);

function getRepositories(req, res) {
  logger.trace('getRepositories');

  loadRepositories(req, function(err, repositories) {
    if (err) {
      return res.status(500).json({
        message: 'error requesting repository list'
      });
    }
    return res.json(repositories);
  });
}

function generateReport(req, res) {
  logger.trace('generateReport');

  var user = req.user;
  var repo = req.repository;
  var from = req.query.from;

  loadRepositoryIssues(user, repo, from, function(error, issues) {
    if (error) {
      return res.status(400).json(error);
    }
    return res.json(issues);
  });
}

function loadRepositories(req, fetchedCb) {
  logger.trace('loadRepositories');

  var user = req.user;

  if (user.repositories && user.repositories.length > 0) {
    return fetchedCb(null, user.repositories);
  }

  traverson.from('https://api.github.com')
  .json()
  .follow('current_user_repositories_url')
  .withRequestOptions({ headers: getRequestHeaders(user) })
  .getResource(function(error, resource) {
    if (error) {
      return fetchedCb(error);
    }

    var repositories = [];

    for (var i = 0; i < resource.length; i++) {
      var repo = {
        id: resource[i].id,
        name: resource[i].name,
        fullName: resource[i].full_name,
        description: resource[i].description,
        createdAt: resource[i].created_at,
        updatedAt: resource[i].updated_at,
        issuesUrl: resource[i].issues_url,
        reportUrl: config.server.baseUrl + req.originalUrl + '/' + resource[i].id + '/report{?from}'
      };
      repositories.push(repo);
    }

    user.repositories = repositories;
    return fetchedCb(null, repositories);
  });
}

function loadRepositoryIssues(user, repository, from, issuesLoadedCb) {
  loadFullPaginatedResource(user, repository.issuesUrl, { state: 'all', since: from }, function(error, issues) {
    if (error) {
      return issuesLoadedCb(error);
    }

    logger.debug('loadFullPaginatedResource returned ' + issues.length + ' issues');

    var relevant = { };

    async.each(issues, function(issue, doneCb) {
      // skip pull-requests
      if ('pull_request' in issue) {
        return doneCb();
      }

      loadInvolvedUsers(user, issue.events_url, function(err, involvedUsers) {
        logger.trace('loadInvolvedUsers for ' + issue.title + ' returned');

        if (err) {
          return doneCb(err);
        }

        var relevantParts = {
          title: issue.title,
          id: issue.id,
          number: issue.number,
          description: issue.body,
          labels: issue.labels,
          state: issue.state,
          assignee: (issue.assignee && {
            id: issue.assignee.id,
            login: issue.assignee.login
          }) || null,
          createdAt: issue.created_at,
          lastUpdate: issue.updated_at,
          closedAt: issue.closed_at,
          involvedUsers: involvedUsers
        };

        // remove the assignee from the involved users list
        if (relevantParts.assignee) {
          for (var i = 0; i < relevantParts.involvedUsers.length; i++) {
            if (relevantParts.involvedUsers[i].id === relevantParts.assignee.id) {
              relevantParts.involvedUsers = relevantParts.involvedUsers.splice(i, 1);
              break;
            }
          }
        }

        var milestone = (issue.milestone && issue.milestone.title) || 'unassigned';

        if (!(milestone in relevant)) {
          relevant[milestone] = [];
        }

        relevant[milestone].push(relevantParts);

        logger.trace('exiting async.each for ' + issue.title);
        return doneCb();
      });
    }, function(err) {
      logger.trace('loadRepositoryIssues exit');
      issuesLoadedCb(err, relevant);
    });
  });
}

function loadInvolvedUsers(user, issueEventsUrl, usersFetchedCb) {
  loadFullPaginatedResource(user, issueEventsUrl, {}, function(error, events) {
    if (error) {
      return usersFetchedCb(error);
    }

    var mentionedUsers = [];
    for (var i = 0; i < events.length; i++) {
      var update = events[i];
      if (update.event === 'mentioned' && update.actor) {
        var mentioned = {
          id: update.actor.id,
          name: update.actor.login
        };
        var alreadyIn = false;
        for (var j = 0; j < mentionedUsers.length; j++) {
          if (mentionedUsers[j].id === mentioned.id) {
            alreadyIn = true;
            break;
          }
        }
        if (!alreadyIn) {
          mentionedUsers.push(mentioned);
        }
      }
    }
    usersFetchedCb(null, mentionedUsers);
  });
}

function loadFullPaginatedResource(user, link, queryOptions, fetchedCb, previousItems) {
  logger.trace('loadFullPaginatedResource', link, queryOptions);

  var items = previousItems || [];

  traverson.from(link)
  .withRequestOptions({
    headers: getRequestHeaders(user),
    qs: queryOptions
  })
  .get(function(error, response) {
    if (error) {
      return fetchedCb(error);
    }
    items = items.concat(JSON.parse(response.body));

    var links = parseLinkHeader(response.headers['link']);

    if (!links || !links.last || link === links.last || !links.next || links.next === '') {
      return fetchedCb(null, items);
    } else {
      // there are more pages to fetch!
      return loadFullPaginatedResource(user, links.next, queryOptions, fetchedCb, items);
    }
  });
}

var linkHeaderRegex = /^<(http[s]?:\/\/[a-z0-9\.]+\/.*?)>; rel="([a-z0-9]+)"$/i;

function parseLinkHeader(linkHeader) {
  logger.trace('parseLinkHeader', linkHeader);

  if (!linkHeader) {
    return null;
  }

  var links = {};

  if (linkHeader && typeof linkHeader === 'string') {
    var linkSegments = linkHeader.split(', ');

    for (var i = 0; i < linkSegments.length; i++) {
      var match = linkHeaderRegex.exec(linkSegments[i]);
      if (match) {
        links[match[2]] = match[1];
      }
    }
  }

  return links;
}

// middleware
function extractRepository(req, res, next) {
  logger.trace('extractRepository');

  if (!req.params.repositoryId) {
    return next();
  }

  var repositoryId = parseInt(req.params.repositoryId, 10);
  if (isNaN(repositoryId)) {
    return next({
      message: 'malformed repositoryId'
    });
  }

  if (!req.user.repositories) {
    return loadRepositories(req, function(error) {
      if (error) {
        return next(error);
      }
      return extractRepository(req, res, next);
    });
  }
  var repos = req.user.repositories;
  for (var i = 0; i < repos.length; i++) {
    if (repos[i].id === repositoryId) {
      req.repository = repos[i];
      return next();
    }
  }
  return next({
    message: 'invalid repositoryId'
  });
}
<|endoftext|>


<commit_before>function marginotes(els, options) {
  var options = options || {}
  var marginTooltips = document.getElementsByClassName('margintooltip')
  var marginTooltip
  if (marginTooltips.length === 0) {
    marginTooltip = document.createElement('div')
    marginTooltip.className = 'margintooltip'
    marginTooltip.style.display = 'none'
    document.body.appendChild(marginTooltip)
  } else {
    marginTooltip = marginTooltips[0]
  }

  var field = options.field || "desc"
  Array.prototype.forEach.call(els, function(el) {
    if (el.tagName === 'SPAN') {
      el.style.cssText = "border-bottom: '1px dashed #337ab7'; cursor: 'help'"
    }
    el.onmouseenter = function () {
      var description = el.getAttribute(field)
      var parent = el.parentElement
      var position = {left: parent.offsetLeft, top: parent.offsetTop}
      var width = Math.min(options.width || 100, position.left)
      if (width < 60 || !description) return
      marginTooltip.style.position = "absolute"
      marginTooltip.style["border-right"] = "solid 2px #337ab7"
      marginTooltip.style["font-size"] = "13px"
      marginTooltip.style["text-align"] = "right"
      marginTooltip.style["padding-right"] = "7px"
      marginTooltip.style.top = String(position.top) + "px"
      marginTooltip.style.left = String(position.left - width - 5) + "px"
      marginTooltip.style["min-height"] = String(parent.clientHeight) + "px"
      marginTooltip.style.display = "block"
      marginTooltip.style.width = String(width) + "px"
      marginTooltip.textContent = description
      stopLastFadeAnimation()
      fadeIn(marginTooltip, 100)
    }
    el.onmouseleave = function () {
      stopLastFadeAnimation()
      fadeOut(marginTooltip, 100)
    }
  })
}

/* Helpers (http://youmightnotneedjquery.com/) */
var animationId;

function fadeIn(el, duration) {
  el.style.opacity = 0;
  var last = +new Date();
  var tick = function() {
    el.style.opacity = +el.style.opacity + (new Date() - last) / duration;
    last = +new Date();

    if (+el.style.opacity < 1) {
      animationId = (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
    }
  };

  tick();
}

function fadeOut(el, duration) {
  var last = +new Date();
  var tick = function() {
    el.style.opacity = +el.style.opacity - (new Date() - last) / duration;
    last = +new Date();

    if (+el.style.opacity > 0) {
      animationId = (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
    }
  };

  tick();
}

function stopLastFadeAnimation() {
  (window.cancelAnimationFrame && window.cancelAnimationFrame(animationId)) || clearTimeout(animationId);
}
<commit_msg>Encapsulate coordinating fades in an out with a simple class<commit_after>function marginotes(els, options) {
  var options = options || {}
  var marginTooltips = document.getElementsByClassName('margintooltip')
  var marginTooltip
  if (marginTooltips.length === 0) {
    marginTooltip = document.createElement('div')
    marginTooltip.className = 'margintooltip'
    marginTooltip.style.display = 'none'
    document.body.appendChild(marginTooltip)
  } else {
    marginTooltip = marginTooltips[0]
  }

  var field = options.field || "desc"
  var fader = new Fader()
  Array.prototype.forEach.call(els, function(el) {
    if (el.tagName === 'SPAN') {
      el.style.cssText = "border-bottom: '1px dashed #337ab7'; cursor: 'help'"
    }
    el.onmouseenter = function () {
      var description = el.getAttribute(field)
      var parent = el.parentElement
      var position = {left: parent.offsetLeft, top: parent.offsetTop}
      var width = Math.min(options.width || 100, position.left)
      if (width < 60 || !description) return
      marginTooltip.style.position = "absolute"
      marginTooltip.style["border-right"] = "solid 2px #337ab7"
      marginTooltip.style["font-size"] = "13px"
      marginTooltip.style["text-align"] = "right"
      marginTooltip.style["padding-right"] = "7px"
      marginTooltip.style.top = String(position.top) + "px"
      marginTooltip.style.left = String(position.left - width - 5) + "px"
      marginTooltip.style["min-height"] = String(parent.clientHeight) + "px"
      marginTooltip.style.display = "block"
      marginTooltip.style.width = String(width) + "px"
      marginTooltip.textContent = description
      fader.stop()
      fader.fadeIn(marginTooltip, 100)
    }
    el.onmouseleave = function () {
      fader.stop()
      fader.fadeOut(marginTooltip, 100)
    }
  })
}

/* Helpers (http://youmightnotneedjquery.com/) */
var Fader = function() {}

Fader.prototype.fadeIn = function(el, duration) {
  el.style.opacity = 0;
  var last = +new Date();
  var tick = function() {
    el.style.opacity = +el.style.opacity + (new Date() - last) / duration;
    last = +new Date();

    if (+el.style.opacity < 1) {
      this.animationId = (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
    }
  };

  tick();
}

Fader.prototype.fadeOut = function(el, duration) {
  var last = +new Date();
  var tick = function() {
    el.style.opacity = +el.style.opacity - (new Date() - last) / duration;
    last = +new Date();

    if (+el.style.opacity > 0) {
      this.animationId = (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
    }
  };

  tick();
}

Fader.prototype.stop = function() {
  (window.cancelAnimationFrame && window.cancelAnimationFrame(this.animationId)) || clearTimeout(this.animationId);
}
<|endoftext|>


<commit_before>( function($) { $(document).ready( function() {

    // Debugging tools
    ;;; function alert_dump(obj, name) {
    ;;;     var s = name ? name + ":\n" : '';
    ;;;     for (var i in obj) s += i + ': ' + obj[i] + "\n";
    ;;;     alert(s);
    ;;; }
    ;;; function carp(message) {
    ;;;    if (window.console) {
    ;;;        console.log(message);
    ;;;    }
    ;;; }

    // Store the #content div, so we need not always mine it from the DOM.
    var $CONTENT = $('#content');

    // We need to remember what URL is loaded in which element,
    // so we can load or not load content appropriately on hash change.
    var LOADED_URLS = {};

    // When something is loaded into an element that has no base view (in urls.js),
    // and the user hits back, we need to reload. But then we don't want to reload again,
    // so keep information about whether we manipulated the content, so we can
    // abstain from reloading if we have not.
    var PAGE_CHANGED = 0;

    // Take a container and a URL. Give the container the "loading" class,
    // fetch the URL, remove the class and stuff the content into the container.
    function load_content($container, address) {
        ;;; carp('loading '+address+' into '+$container.attr('id'));

        // An empty address means we should revert to the base state.
        // If one is not set up for the given container, reload the whole page.
        if (address.length == 0) {
            if (BASES[ $container.attr('id') ]) {
                address = BASES[ $container.attr('id') ];
            } else {
                if (PAGE_CHANGED) location.reload();
                return;
            }
        }

        var url = $('<a>').attr('href', address).get(0).href;
        if ($container && $container.length && $container.jquery) { } else {
            carp('Could not insert into container:');
            carp($container);
            return;
        }
        $container.addClass('loading');
        $.get(url, function(data) {
            $container.removeClass('loading').html(data);
            LOADED_URLS[ $container.attr('id') ] = address;
            PAGE_CHANGED++;
        });
    }

    // We want location.hash to exactly describe what's on the page.
    // #url means that the result of $.get(url) be loaded into the #content div.
    // #id::url means that the result of $.get(url) be loaded into the #id element.
    // Any number of such specifiers can be concatenated, e.g. #/some/page/#header::/my/header/
    // If URLS[ foo ] is set (in urls.js), and #foo is present,
    // then the function is called given the $target as argument
    // and nothing else is done for this specifier.
    function load_by_hash() {
        var hash = location.hash.substr(1);

        // Figure out what should be reloaded and what not by comparing the requested things with the loaded ones.
        var requested = {};
        var specifiers = hash.split('#');
        for (var i = 0; i < specifiers.length; i++) {
            var spec = specifiers[ i ];
            var address = spec;
            var $target = $CONTENT;
            if (spec.match(/^([-\w]+)::(.*)/)) {
                var id  = RegExp.$1;
                address = RegExp.$2;
                $target = $('#' + id);
                if (!$target || $target.length == 0) {
                    carp('Could not find #'+id);
                    continue;
                }
            }
            requested[ $target.attr('id') ] = address;
        }
        for (var k in LOADED_URLS) {
            // if this specifier didn't change, don't load it again
            if (LOADED_URLS[k] == requested[k]) continue;
            // if this specifier is no longer present, reload the base
            if (!requested[k]) requested[k] = '';
        }

        for (var target_id in requested) {
            var $target = $('#'+target_id);
            var address = requested[ target_id ];

            // A specially treated specifier. The callback should set up LOADED_URLS properly.
            if (URLS[address]) {
                URLS[address]($target);
                continue;
            }

            load_content($target, address);
        }
    }

    // Simulate a hashchange event fired when location.hash changes
    var CURRENT_HASH = '';
    function hashchange() {
//        carp('hash: ' + location.hash);
        load_by_hash();
    }
    setTimeout( function() {
        try {
            if (location.hash != CURRENT_HASH) {
                CURRENT_HASH = location.hash;
                hashchange();
            }
        } catch(e) { carp(e); }
        setTimeout(arguments.callee, 50);
    }, 50);
})})(jQuery);
<commit_msg>bugfix: no longer reloading things that don't need it<commit_after>( function($) { $(document).ready( function() {

    // Debugging tools
    ;;; function alert_dump(obj, name) {
    ;;;     var s = name ? name + ":\n" : '';
    ;;;     for (var i in obj) s += i + ': ' + obj[i] + "\n";
    ;;;     alert(s);
    ;;; }
    ;;; function carp(message) {
    ;;;    if (window.console) {
    ;;;        console.log(message);
    ;;;    }
    ;;; }

    // Store the #content div, so we need not always mine it from the DOM.
    var $CONTENT = $('#content');

    // We need to remember what URL is loaded in which element,
    // so we can load or not load content appropriately on hash change.
    var LOADED_URLS = {};

    // When something is loaded into an element that has no base view (in urls.js),
    // and the user hits back, we need to reload. But then we don't want to reload again,
    // so keep information about whether we manipulated the content, so we can
    // abstain from reloading if we have not.
    var PAGE_CHANGED = 0;

    // Take a container and a URL. Give the container the "loading" class,
    // fetch the URL, remove the class and stuff the content into the container.
    function load_content($container, address) {
        ;;; carp('loading '+address+' into '+$container.attr('id'));

        // An empty address means we should revert to the base state.
        // If one is not set up for the given container, reload the whole page.
        if (address.length == 0) {
            if (BASES[ $container.attr('id') ]) {
                address = BASES[ $container.attr('id') ];
            } else {
                if (PAGE_CHANGED) location.reload();
                return;
            }
        }

        var url = $('<a>').attr('href', address).get(0).href;
        if ($container && $container.length && $container.jquery) { } else {
            carp('Could not insert into container:');
            carp($container);
            return;
        }
        $container.addClass('loading');
        $.get(url, function(data) {
            $container.removeClass('loading').html(data);
            LOADED_URLS[ $container.attr('id') ] = address;
            PAGE_CHANGED++;
        });
    }

    // We want location.hash to exactly describe what's on the page.
    // #url means that the result of $.get(url) be loaded into the #content div.
    // #id::url means that the result of $.get(url) be loaded into the #id element.
    // Any number of such specifiers can be concatenated, e.g. #/some/page/#header::/my/header/
    // If URLS[ foo ] is set (in urls.js), and #foo is present,
    // then the function is called given the $target as argument
    // and nothing else is done for this specifier.
    function load_by_hash() {
        var hash = location.hash.substr(1);

        // Figure out what should be reloaded and what not by comparing the requested things with the loaded ones.
        var requested = {};
        var specifiers = hash.split('#');
        for (var i = 0; i < specifiers.length; i++) {
            var spec = specifiers[ i ];
            var address = spec;
            var $target = $CONTENT;
            if (spec.match(/^([-\w]+)::(.*)/)) {
                var id  = RegExp.$1;
                address = RegExp.$2;
                $target = $('#' + id);
                if (!$target || $target.length == 0) {
                    carp('Could not find #'+id);
                    continue;
                }
            }
            requested[ $target.attr('id') ] = address;
        }
        for (var k in LOADED_URLS) {
            // if this specifier didn't change, don't load it again
            if (LOADED_URLS[k] == requested[k]) {
                delete requested[k];
                continue;
            }
            // if this specifier is no longer present, reload the base
            if (!requested[k]) requested[k] = '';
        }

        for (var target_id in requested) {
            var $target = $('#'+target_id);
            var address = requested[ target_id ];

            // A specially treated specifier. The callback should set up LOADED_URLS properly.
            if (URLS[address]) {
                URLS[address]($target);
                continue;
            }

            load_content($target, address);
        }
    }

    // Simulate a hashchange event fired when location.hash changes
    var CURRENT_HASH = '';
    function hashchange() {
//        carp('hash: ' + location.hash);
        load_by_hash();
    }
    setTimeout( function() {
        try {
            if (location.hash != CURRENT_HASH) {
                CURRENT_HASH = location.hash;
                hashchange();
            }
        } catch(e) { carp(e); }
        setTimeout(arguments.callee, 50);
    }, 50);
})})(jQuery);
<|endoftext|>