<commit_before>import Promise from 'bluebird';
import Email from '../models/email.model';
import Box from '../models/box.model';
import User from '../models/user.model';
import Analyzer from '../core/engine/analyzer';
import Socket from '../routes/socket';
import NERService from "../core/analysis/NERService";
import GmailConnector from '../core/mail/GmailConnector';
import EWSConnector from '../core/mail/EWSConnector';

exports.sendEmail = (req, res) => {

  if (req.user.isExchangeProvider()) {

    const emailConnector = req.user.createIMAPConnector();
    emailConnector.sendMail(req.body)
      .then(result => {
        return Box.findOne({name: EWSConnector.staticBoxNames.send, user: req.user});
      })
      .then(box => {
        return req.user.createIMAPConnector().fetchBoxes(storeEmail, [box]);
      })
      .then(() => {
        res.status(200).send({message: 'Finished fetching'});
      })
      .catch((err) => {
        console.log(err);
        res.status(400).send(err);
      });

  } else {

    req.user.createSMTPConnector().sendMail(req.body)
      .then(result => {
        return Box.findOne({name: GmailConnector.staticBoxNames.send, user: req.user});
      })
      .then(box => {
        return req.user.createIMAPConnector().fetchBoxes(storeEmail, [box]);
      })
      .then(() => {
        res.status(200).send({message: 'Finished fetching'});
      })
      .catch((err) => {
        console.log(err);
        res.status(400).send(err);
      });

  }
}

exports.append = (req, res) => {
  const user = req.user;
  const boxId = req.body.boxId;
  const emailConnector = user.createIMAPConnector();

  if (req.user.isExchangeProvider()) {

    // Box.findOne({name: EWSConnector.staticBoxNames.draft, user: user})
    Box.findOne({_id: boxId, user: user})
      .then(box => {
        return [box, emailConnector.append(req.body, box.ewsId)]
      })
      .spread((box, msgData) => {
        return [msgData, emailConnector.fetchBoxes(storeEmail, [box])]
      })
      .spread((msgData, result) => {
        res.status(200).send({msgData: 'ok'});
      })
      .catch((err) => {
        console.log(err);
        res.status(400).send(err);
      });

  } else {

    // Box.findOne({name: GmailConnector.staticBoxNames.draft, user: user})
    Box.findOne({_id: boxId, user: user})
      .then(box => {
        return [box, emailConnector.append(box.name, user.email, req.body.to, req.body.subject, req.body.msgData)]
      })
      .spread((box, msgData) => {
        return [msgData, emailConnector.fetchBoxes(storeEmail, [box])]
      })
      .spread((msgData, result) => {
        res.status(200).send({msgData: msgData});
      })
      .catch((err) => {
        console.log(err);
        res.status(400).send(err);
      });

  }
}

exports.move = (req, res) => {
  const emailId = req.params.id;
  const newBoxId = req.body.newBoxId;
  const user = req.user;

  const emailConnector = user.createIMAPConnector();

  if (req.user.isExchangeProvider()) {

    Email.findOne({_id: emailId}).populate('boxes')
      .then(email => {
        return [email, Box.findOne({_id: newBoxId, user: user})]
      })
      .spread((email, destBox) => {
        const srcBox = email.boxes[0];
        return [srcBox, destBox, emailConnector.move(email, destBox.ewsId)]
      })
      .spread((srcBox, destBox, msgId) => {
        return emailConnector.fetchBoxes(storeEmail, [srcBox, destBox])
      })
      .then((messages) => {
        res.status(200).send({messages: messages});
      })
      .catch(err => {
        console.log(err);
        res.status(400).send(err);
      });

  } else {

    Email.findOne({_id: emailId}).populate('boxes')
      .then(email => {
        return [email, Box.findOne({_id: newBoxId, user: user})]
      })
      // TODO boxId from parameter
      .spread((email, destBox) => {
        const srcBox = email.boxes[0];
        return [srcBox, destBox, emailConnector.move(email.uid, srcBox.name, destBox.name)]
      })
      .spread((srcBox, destBox, msgId) => {
        return emailConnector.fetchBoxes(storeEmail, [srcBox, destBox])
      })
      .then((messages) => {
        res.status(200).send({messages: messages});
      })
      .catch(err => {
        console.log(err);
        res.status(400).send(err);
      });
  }
}

exports.moveToTrash = (req, res) => {
  if (req.user.isExchangeProvider()) {
    Box.findOne({name: EWSConnector.staticBoxNames.deleted, user: req.user})
      .then(box => {
        req.body.newBoxId = box._id;
        exports.move(req, res);
      });
  } else if (req.user.isGMailProvider()) {
    Box.findOne({name: GmailConnector.staticBoxNames.deleted, user: req.user})
      .then(box => {
        req.body.newBoxId = box._id;
        exports.move(req, res);
      });
  }
}

/**
 * @api {post} /email/:id/flags Add Email Flags
 * @apiDescription Add the specified flags to this email.
 * @apiName AddEmailFlags
 * @apiGroup Email
 * @apiParam {String} id Email unique ID.
 * @apiParam {String[]} flags Email flags.
 * @apiSuccessExample Success-Response:
 * //TODO
 *     {
 *       "firstname": "John",
 *       "lastname": "Doe"
 *     }
 */
exports.addFlags = (req, res) => {
  const emailId = req.params.id;
  const flags = req.body.flags;
  const user = req.user;
  const emailConnector = req.user.createIMAPConnector();
  let email = null;

  if (req.user.isExchangeProvider()) {

    Email.findById(emailId)//.populate('box')
      .then(mail => {
        email = mail;
        return emailConnector.addFlags(mail, flags);
      })
      .then(() => {
        email.flags = email.flags.concat(flags);
        return email.save();
      })
      .then(() => {
        res.status(200).send({message: 'Successfully added Flags'});
      })
      .catch(err => {
        res.status(400).send(err);
      });

  } else {

    Email.findById(emailId).populate('boxes')
      .then(mail => {
        email = mail;
        return emailConnector.addFlags(mail.uid, flags, email.boxes[0].name);
      })
      .then(() => {
        email.flags = email.flags.concat(flags);
        return email.save();
      })
      .then(() => {
        res.status(200).send({message: 'Successfully added Flags'});
      })
      .catch(err => {
        res.status(400).send(err);
      });
  }
}

/**
 * @api {delete} /email/:id/flags Remove Email Flags
 * @apiDescription Removes the specified flags from this email.
 * @apiName RemoveEmailFlags
 * @apiGroup Email
 * @apiParam {String} id Email unique ID.
 * @apiParam {String[]} flags Email flags.
 * @apiSuccessExample Success-Response:
 * //TODO
 *     {
 *       "firstname": "John",
 *       "lastname": "Doe"
 *     }
 */
exports.delFlags = (req, res) => {
  const emailId = req.params.id;
  const flags = req.body.flags;
  const user = req.user;
  const emailConnector = req.user.createIMAPConnector();
  let email = null;

  if (req.user.isExchangeProvider()) {

    Email.findById(emailId)//.populate('box')
      .then(mail => {
        email = mail;
        return emailConnector.delFlags(mail, flags);
      })
      .then(() => {
        flags.forEach(f => {
          const index = email.flags.indexOf(f);
          if (index > -1)
            email.flags.splice(index, 1);
        });
        return email.save()
      })
      .then(() => {
        res.status(200).send({message: 'Successfully deleted Flags'});
      })
      .catch((err) => {
        res.status(400).send(err);
      });

  } else {

    Email.findById(emailId).populate('boxes')
      .then(mail => {
        email = mail;
        return emailConnector.delFlags(mail.uid, flags, mail.boxes[0].name);
      })
      .then(() => {
        flags.forEach(f => {
          const index = email.flags.indexOf(f);
          if (index > -1)
            email.flags.splice(index, 1);
        });
        return email.save()
      })
      .then(() => {
        res.status(200).send({message: 'Successfully deleted Flags'});
      })
      .catch((err) => {
        res.status(400).send(err);
      });

  }
}

/**
 * @api {get} /email/:id Get Email
 * @apiDescription Returns one single mail with all details
 * @apiName GetEmail
 * @apiGroup Email
 * @apiParam {String} id Email unique ID.
 * @apiSuccessExample Success-Response:
 * //TODO
 *     {
 *       "firstname": "John",
 *       "lastname": "Doe"
 *     }
 */
exports.getSingleMail = (req, res) => {
  const emailId = req.params.id;
  let email;
  Email.findOne({_id: emailId}).populate('attachments')
    .lean()
    .then((mail) => {
      console.log('retrieving email id...');
      console.log(mail);
      mail = replaceInlineAttachmentsSrc(mail, req.user);
      return (mail && (req.user.trello || req.user.sociocortex)) ? new Analyzer(mail, req.user).getEmailTasks() : mail;
    })
    .then(mail => {
      email = mail;
      if (email.html)
        return NERService.recognizeEntitiesInHtml(emailId, email.html);
      else
        return NERService.recognizeEntitiesInPlainText(emailId, email.text);
    })
    .then(resultDTO => {
      email['annotations'] = resultDTO.annotations;
      res.status(200).send(email);
    })
    .catch((err) => {
      res.status(400).send(err);
    });
}

// Inline attachments URL and tokens are changed in the front-end
// they have the form AttachmentURL/attachmentId?token=JWTToken
function replaceInlineAttachmentsSrc(email, user) {
  email.attachments.forEach((a) => {
    if (a.contentDispositionInline) {
      email.html = email.html.replace(`cid:${a.contentId}`, `ATTACHMENT_POINT/${a._id}?token=TOKEN_POINT`);
    }
  })

  return email;
}

/** Stores an email in the database and
 *  pushs upates via socket to the client */
// TODO
function storeEmail(mail) {
  return new Promise((resolve, reject) => {
    Email.updateAndGetOldAndUpdated(mail)
      .spread((emailOld, boxOld, emailUpdated, boxUpdated) => {
        // TODO new box numbers do not work properly
        console.log('inside storeEmail...');
        Socket.pushEmailUpdateToClient(emailOld, boxOld, emailUpdated, boxUpdated);
        resolve(emailUpdated);
      })
      .catch(err => {
        reject(err);
      });
  });
}

exports.storeEmail = storeEmail;

/**
 * @api {get} /email/search Search Emails
 * @apiDescription Search emails either for box or custom search
 * @apiName SearchEmail
 * @apiGroup Email
 * @apiParam {String} [boxId] Box unique ID.
 * @apiParam {String{'ASC','DESC'}} [sort='ASC'] Result sort order.
 * @apiParam {String} [search] Search string.
 * @apiParam {String} [lastEmailDate] Date of last email loaded.
 * @apiSuccessExample Success-Response:
 * //TODO
 *     {
 *       "firstname": "John",
 *       "lastname": "Doe"
 *     }
 */
exports.searchEmails = (req, res) => {

  const options = {
    boxId: req.query.boxId,
    sort: req.query.sort, // ASC or DESC
    search: req.query.search,
    lastEmailDate: new Date(req.query.lastEmailDate)
  };

  Email.search(req.user._id, options)
    .then(emails => {
      return Email.filterNonTrash(req.user, req.query.boxId, emails);
    })
    .then(emails => {
      res.status(200).send(emails);
    })
    .catch(err => {
      res.status(400).send(err);
    });
}

/** Creates autocomplete suggestions for email addresses */
exports.autocomplete = (req, res) => {
  Email.autocomplete(req.user._id)
    .then(suggestions => {
      res.status(200).send(suggestions);
    })
    .catch(err => {
      res.status(500).send(err);
    });
}

exports.appendEnron = (req, res) => {

  const emailConnector = req.user.createIMAPConnector();

  // find enron user e.g Allen
  User.findOne({username: 'allen-p'})
    .then((user) => {
      console.log('this is the user');
      console.log(user);

      // get all emails for this user;
      Email.find({user: user}).limit(3)
        .then((emails) => {

          // in which box to store these emails?

          // agregate boxes according to the folder names

          Box.findOne({name: EWSConnector.staticBoxNames.inbox, user: req.user})
            .then(box => {

              // filter emails without ewsItemId (exchange)
              const emailsToAppend = emails.filter(email => !email.ewsItemId);
              //console.log(emailsToAppend);

              Promise.each(emails, (email) => {

                req.body.boxId = box._id;
                req.body.subject = email.subject;
                req.body.msgData = email.text;
                req.body.to = email.to;

                return emailConnector.append(req.body, box.ewsId)
                  .then(result => {
                    // Pair ewsItemId to the Enron email, already in DB
                    console.log('resultado...');
                    console.log(JSON.stringify(result));

                    email.box = box._id;
                    email.boxes = [box._id];
                    email.ewsItemId = result.Id;
                    email.ewsChangeKey = result.ChangeKey;
                  })
                  .then(() => {
                    return storeEmail(email);
                  });
              })
                .then(() => {
                  res.status(200).send({msgData: 'ok'});
                })
                .catch((err) => {
                  console.log(err);
                  res.status(400).send(err);
                });

            });

        });

    });

}

<commit_msg>made analyzer service optional<commit_after>import Promise from 'bluebird';
import Email from '../models/email.model';
import Box from '../models/box.model';
import User from '../models/user.model';
import Analyzer from '../core/engine/analyzer';
import Socket from '../routes/socket';
import NERService from "../core/analysis/NERService";
import GmailConnector from '../core/mail/GmailConnector';
import EWSConnector from '../core/mail/EWSConnector';

exports.sendEmail = (req, res) => {

  if (req.user.isExchangeProvider()) {

    const emailConnector = req.user.createIMAPConnector();
    emailConnector.sendMail(req.body)
      .then(result => {
        return Box.findOne({name: EWSConnector.staticBoxNames.send, user: req.user});
      })
      .then(box => {
        return req.user.createIMAPConnector().fetchBoxes(storeEmail, [box]);
      })
      .then(() => {
        res.status(200).send({message: 'Finished fetching'});
      })
      .catch((err) => {
        console.log(err);
        res.status(400).send(err);
      });

  } else {

    req.user.createSMTPConnector().sendMail(req.body)
      .then(result => {
        return Box.findOne({name: GmailConnector.staticBoxNames.send, user: req.user});
      })
      .then(box => {
        return req.user.createIMAPConnector().fetchBoxes(storeEmail, [box]);
      })
      .then(() => {
        res.status(200).send({message: 'Finished fetching'});
      })
      .catch((err) => {
        console.log(err);
        res.status(400).send(err);
      });

  }
}

exports.append = (req, res) => {
  const user = req.user;
  const boxId = req.body.boxId;
  const emailConnector = user.createIMAPConnector();

  if (req.user.isExchangeProvider()) {

    // Box.findOne({name: EWSConnector.staticBoxNames.draft, user: user})
    Box.findOne({_id: boxId, user: user})
      .then(box => {
        return [box, emailConnector.append(req.body, box.ewsId)]
      })
      .spread((box, msgData) => {
        return [msgData, emailConnector.fetchBoxes(storeEmail, [box])]
      })
      .spread((msgData, result) => {
        res.status(200).send({msgData: 'ok'});
      })
      .catch((err) => {
        console.log(err);
        res.status(400).send(err);
      });

  } else {

    // Box.findOne({name: GmailConnector.staticBoxNames.draft, user: user})
    Box.findOne({_id: boxId, user: user})
      .then(box => {
        return [box, emailConnector.append(box.name, user.email, req.body.to, req.body.subject, req.body.msgData)]
      })
      .spread((box, msgData) => {
        return [msgData, emailConnector.fetchBoxes(storeEmail, [box])]
      })
      .spread((msgData, result) => {
        res.status(200).send({msgData: msgData});
      })
      .catch((err) => {
        console.log(err);
        res.status(400).send(err);
      });

  }
}

exports.move = (req, res) => {
  const emailId = req.params.id;
  const newBoxId = req.body.newBoxId;
  const user = req.user;

  const emailConnector = user.createIMAPConnector();

  if (req.user.isExchangeProvider()) {

    Email.findOne({_id: emailId}).populate('boxes')
      .then(email => {
        return [email, Box.findOne({_id: newBoxId, user: user})]
      })
      .spread((email, destBox) => {
        const srcBox = email.boxes[0];
        return [srcBox, destBox, emailConnector.move(email, destBox.ewsId)]
      })
      .spread((srcBox, destBox, msgId) => {
        return emailConnector.fetchBoxes(storeEmail, [srcBox, destBox])
      })
      .then((messages) => {
        res.status(200).send({messages: messages});
      })
      .catch(err => {
        console.log(err);
        res.status(400).send(err);
      });

  } else {

    Email.findOne({_id: emailId}).populate('boxes')
      .then(email => {
        return [email, Box.findOne({_id: newBoxId, user: user})]
      })
      // TODO boxId from parameter
      .spread((email, destBox) => {
        const srcBox = email.boxes[0];
        return [srcBox, destBox, emailConnector.move(email.uid, srcBox.name, destBox.name)]
      })
      .spread((srcBox, destBox, msgId) => {
        return emailConnector.fetchBoxes(storeEmail, [srcBox, destBox])
      })
      .then((messages) => {
        res.status(200).send({messages: messages});
      })
      .catch(err => {
        console.log(err);
        res.status(400).send(err);
      });
  }
}

exports.moveToTrash = (req, res) => {
  if (req.user.isExchangeProvider()) {
    Box.findOne({name: EWSConnector.staticBoxNames.deleted, user: req.user})
      .then(box => {
        req.body.newBoxId = box._id;
        exports.move(req, res);
      });
  } else if (req.user.isGMailProvider()) {
    Box.findOne({name: GmailConnector.staticBoxNames.deleted, user: req.user})
      .then(box => {
        req.body.newBoxId = box._id;
        exports.move(req, res);
      });
  }
}

/**
 * @api {post} /email/:id/flags Add Email Flags
 * @apiDescription Add the specified flags to this email.
 * @apiName AddEmailFlags
 * @apiGroup Email
 * @apiParam {String} id Email unique ID.
 * @apiParam {String[]} flags Email flags.
 * @apiSuccessExample Success-Response:
 * //TODO
 *     {
 *       "firstname": "John",
 *       "lastname": "Doe"
 *     }
 */
exports.addFlags = (req, res) => {
  const emailId = req.params.id;
  const flags = req.body.flags;
  const user = req.user;
  const emailConnector = req.user.createIMAPConnector();
  let email = null;

  if (req.user.isExchangeProvider()) {

    Email.findById(emailId)//.populate('box')
      .then(mail => {
        email = mail;
        return emailConnector.addFlags(mail, flags);
      })
      .then(() => {
        email.flags = email.flags.concat(flags);
        return email.save();
      })
      .then(() => {
        res.status(200).send({message: 'Successfully added Flags'});
      })
      .catch(err => {
        res.status(400).send(err);
      });

  } else {

    Email.findById(emailId).populate('boxes')
      .then(mail => {
        email = mail;
        return emailConnector.addFlags(mail.uid, flags, email.boxes[0].name);
      })
      .then(() => {
        email.flags = email.flags.concat(flags);
        return email.save();
      })
      .then(() => {
        res.status(200).send({message: 'Successfully added Flags'});
      })
      .catch(err => {
        res.status(400).send(err);
      });
  }
}

/**
 * @api {delete} /email/:id/flags Remove Email Flags
 * @apiDescription Removes the specified flags from this email.
 * @apiName RemoveEmailFlags
 * @apiGroup Email
 * @apiParam {String} id Email unique ID.
 * @apiParam {String[]} flags Email flags.
 * @apiSuccessExample Success-Response:
 * //TODO
 *     {
 *       "firstname": "John",
 *       "lastname": "Doe"
 *     }
 */
exports.delFlags = (req, res) => {
  const emailId = req.params.id;
  const flags = req.body.flags;
  const user = req.user;
  const emailConnector = req.user.createIMAPConnector();
  let email = null;

  if (req.user.isExchangeProvider()) {

    Email.findById(emailId)//.populate('box')
      .then(mail => {
        email = mail;
        return emailConnector.delFlags(mail, flags);
      })
      .then(() => {
        flags.forEach(f => {
          const index = email.flags.indexOf(f);
          if (index > -1)
            email.flags.splice(index, 1);
        });
        return email.save()
      })
      .then(() => {
        res.status(200).send({message: 'Successfully deleted Flags'});
      })
      .catch((err) => {
        res.status(400).send(err);
      });

  } else {

    Email.findById(emailId).populate('boxes')
      .then(mail => {
        email = mail;
        return emailConnector.delFlags(mail.uid, flags, mail.boxes[0].name);
      })
      .then(() => {
        flags.forEach(f => {
          const index = email.flags.indexOf(f);
          if (index > -1)
            email.flags.splice(index, 1);
        });
        return email.save()
      })
      .then(() => {
        res.status(200).send({message: 'Successfully deleted Flags'});
      })
      .catch((err) => {
        res.status(400).send(err);
      });

  }
}

/**
 * @api {get} /email/:id Get Email
 * @apiDescription Returns one single mail with all details
 * @apiName GetEmail
 * @apiGroup Email
 * @apiParam {String} id Email unique ID.
 * @apiSuccessExample Success-Response:
 * //TODO
 *     {
 *       "firstname": "John",
 *       "lastname": "Doe"
 *     }
 */
exports.getSingleMail = (req, res) => {
  const emailId = req.params.id;
  let email;
  Email.findOne({_id: emailId}).populate('attachments')
    .lean()
    .then((mail) => {
      console.log('retrieving email id...');
      console.log(mail);
      mail = replaceInlineAttachmentsSrc(mail, req.user);
      return (mail && (req.user.trello || req.user.sociocortex)) ? new Analyzer(mail, req.user).getEmailTasks() : mail;
    })
    .then(mail => {
      email = mail;
      if (email.html)
        return NERService.recognizeEntitiesInHtml(emailId, email.html);
      else
        return NERService.recognizeEntitiesInPlainText(emailId, email.text);
    })
    .then(resultDTO => {
      email['annotations'] = resultDTO.annotations;
      res.status(200).send(email);
    })
    .catch((err) => {
      if (err && err.message && err.message === "Error: connect ECONNREFUSED 127.0.0.1:8080") {
        // TODO replace by proper error handling when analyzer is not available
        res.status(200).send(email);
        return;
      }
      res.status(400).send(err);
    });
}

// Inline attachments URL and tokens are changed in the front-end
// they have the form AttachmentURL/attachmentId?token=JWTToken
function replaceInlineAttachmentsSrc(email, user) {
  email.attachments.forEach((a) => {
    if (a.contentDispositionInline) {
      email.html = email.html.replace(`cid:${a.contentId}`, `ATTACHMENT_POINT/${a._id}?token=TOKEN_POINT`);
    }
  })

  return email;
}

/** Stores an email in the database and
 *  pushs upates via socket to the client */
// TODO
function storeEmail(mail) {
  return new Promise((resolve, reject) => {
    Email.updateAndGetOldAndUpdated(mail)
      .spread((emailOld, boxOld, emailUpdated, boxUpdated) => {
        // TODO new box numbers do not work properly
        console.log('inside storeEmail...');
        Socket.pushEmailUpdateToClient(emailOld, boxOld, emailUpdated, boxUpdated);
        resolve(emailUpdated);
      })
      .catch(err => {
        reject(err);
      });
  });
}

exports.storeEmail = storeEmail;

/**
 * @api {get} /email/search Search Emails
 * @apiDescription Search emails either for box or custom search
 * @apiName SearchEmail
 * @apiGroup Email
 * @apiParam {String} [boxId] Box unique ID.
 * @apiParam {String{'ASC','DESC'}} [sort='ASC'] Result sort order.
 * @apiParam {String} [search] Search string.
 * @apiParam {String} [lastEmailDate] Date of last email loaded.
 * @apiSuccessExample Success-Response:
 * //TODO
 *     {
 *       "firstname": "John",
 *       "lastname": "Doe"
 *     }
 */
exports.searchEmails = (req, res) => {

  const options = {
    boxId: req.query.boxId,
    sort: req.query.sort, // ASC or DESC
    search: req.query.search,
    lastEmailDate: new Date(req.query.lastEmailDate)
  };

  Email.search(req.user._id, options)
    .then(emails => {
      return Email.filterNonTrash(req.user, req.query.boxId, emails);
    })
    .then(emails => {
      res.status(200).send(emails);
    })
    .catch(err => {
      res.status(400).send(err);
    });
}

/** Creates autocomplete suggestions for email addresses */
exports.autocomplete = (req, res) => {
  Email.autocomplete(req.user._id)
    .then(suggestions => {
      res.status(200).send(suggestions);
    })
    .catch(err => {
      res.status(500).send(err);
    });
}

exports.appendEnron = (req, res) => {

  const emailConnector = req.user.createIMAPConnector();

  // find enron user e.g Allen
  User.findOne({username: 'allen-p'})
    .then((user) => {
      console.log('this is the user');
      console.log(user);

      // get all emails for this user;
      Email.find({user: user}).limit(3)
        .then((emails) => {

          // in which box to store these emails?

          // agregate boxes according to the folder names

          Box.findOne({name: EWSConnector.staticBoxNames.inbox, user: req.user})
            .then(box => {

              // filter emails without ewsItemId (exchange)
              const emailsToAppend = emails.filter(email => !email.ewsItemId);
              //console.log(emailsToAppend);

              Promise.each(emails, (email) => {

                req.body.boxId = box._id;
                req.body.subject = email.subject;
                req.body.msgData = email.text;
                req.body.to = email.to;

                return emailConnector.append(req.body, box.ewsId)
                  .then(result => {
                    // Pair ewsItemId to the Enron email, already in DB
                    console.log('resultado...');
                    console.log(JSON.stringify(result));

                    email.box = box._id;
                    email.boxes = [box._id];
                    email.ewsItemId = result.Id;
                    email.ewsChangeKey = result.ChangeKey;
                  })
                  .then(() => {
                    return storeEmail(email);
                  });
              })
                .then(() => {
                  res.status(200).send({msgData: 'ok'});
                })
                .catch((err) => {
                  console.log(err);
                  res.status(400).send(err);
                });

            });

        });

    });

}

<|endoftext|>


<commit_before>function fitSlider() {
	if (typeof slider != "undefined" ) { slider.configure({width : new_width}); slider.render();}
}
// Oh dear...
function general_removechart(metric,newurl,length) {

	if (length === 0) {
		window.location.replace(window.location.origin)
	}
	//Remove listing from cache of select2 listings (allows researching)
	if (filter_metrics_select) {
		var news2 = $.grep($("#filter_metrics_select").select2("data"), function(d) { return d.id != metric})
		$("#filter_metrics_select").select2("data",news2)
	}

	//Remove li metric listing
	$('*[data-metric="'+metric+'"]').parent().parent().remove()

	//Remove metric from any other generated links on page (oh boy)
	$.each($('a[href*="'+metric+'"]'), function(i,d) {
		d.href = cleanURL(d.href,"metric="+metric)
	})

	//Finally, update location url
	window.history.pushState({style:"removechart"},document.title,newurl)

}

// On back button popstate, reload the page. Uses history alterations, but actually invokes them
$(window).bind('popstate', function(event){
	if (!(event.originalEvent.state === null)) {
		if (event.originalEvent.state.style === "removechart") {
			window.location = location.href
		}
	}
})

function cleanURL(url,rm_string) {
	url = url.replace(rm_string,"")
	url = url.replace("&&","&")
	url = url.replace("?&","?")
	return url
}

function stopButtonClick() {
        stopUpdates();
	enablePlay();
}
function stopAll() {
        stopUpdates();
	stopButtonClick();
	//unrenderWaiting();
}
function enableStop() {
	$("#autoplay_stop_link").removeClass("disabled")
	$("#autoplay_play_link").addClass("disabled")
}
function enablePlay() {
	$("#autoplay_stop_link").addClass("disabled")
	$("#autoplay_play_link").removeClass("disabled")
}

function metric_sort() {
        $("#graphed_metrics").sortable({
                stop: function(event, ui) {
                        var metrics = [], params = [];
                        $(".sortable").each(function(i,el){
                                metrics.push("metric="+$(el).find("span.metric")[0].dataset.metric);
                        });
			$.each(location.search.split("&"), function(i, d) {
				if(d.indexOf("metric") == -1) { params.push(d); }
			});
                        new_url = location.origin + location.pathname +"?"+ params.join("&").replace("?","") +"&"+metrics.join("&");
                        window.location.href= new_url;
                }
        });
}

function metricURL(feed,start,stop,step) { return feed+"&start="+start+"&stop="+stop+"&step="+step }
<commit_msg>Show a little play icon in the title when graphs are playing<commit_after>function fitSlider() {
	if (typeof slider != "undefined" ) { slider.configure({width : new_width}); slider.render();}
}
// Oh dear...
function general_removechart(metric,newurl,length) {

	if (length === 0) {
		window.location.replace(window.location.origin)
	}
	//Remove listing from cache of select2 listings (allows researching)
	if (filter_metrics_select) {
		var news2 = $.grep($("#filter_metrics_select").select2("data"), function(d) { return d.id != metric})
		$("#filter_metrics_select").select2("data",news2)
	}

	//Remove li metric listing
	$('*[data-metric="'+metric+'"]').parent().parent().remove()

	//Remove metric from any other generated links on page (oh boy)
	$.each($('a[href*="'+metric+'"]'), function(i,d) {
		d.href = cleanURL(d.href,"metric="+metric)
	})

	//Finally, update location url
	window.history.pushState({style:"removechart"},document.title,newurl)

}

// On back button popstate, reload the page. Uses history alterations, but actually invokes them
$(window).bind('popstate', function(event){
	if (!(event.originalEvent.state === null)) {
		if (event.originalEvent.state.style === "removechart") {
			window.location = location.href
		}
	}
})

function cleanURL(url,rm_string) {
	url = url.replace(rm_string,"")
	url = url.replace("&&","&")
	url = url.replace("?&","?")
	return url
}

function stopButtonClick() {
        stopUpdates();
	enablePlay();
}
function stopAll() {
        stopUpdates();
	stopButtonClick();
	//unrenderWaiting();
}
function enableStop() {
	$("#autoplay_stop_link").removeClass("disabled")
	$("#autoplay_play_link").addClass("disabled")
	document.title = "\u25B8 Machiavelli"
}
function enablePlay() {
	$("#autoplay_stop_link").addClass("disabled")
	$("#autoplay_play_link").removeClass("disabled")
	document.title = "Machiavelli"
}

function metric_sort() {
        $("#graphed_metrics").sortable({
                stop: function(event, ui) {
                        var metrics = [], params = [];
                        $(".sortable").each(function(i,el){
                                metrics.push("metric="+$(el).find("span.metric")[0].dataset.metric);
                        });
			$.each(location.search.split("&"), function(i, d) {
				if(d.indexOf("metric") == -1) { params.push(d); }
			});
                        new_url = location.origin + location.pathname +"?"+ params.join("&").replace("?","") +"&"+metrics.join("&");
                        window.location.href= new_url;
                }
        });
}

function metricURL(feed,start,stop,step) { return feed+"&start="+start+"&stop="+stop+"&step="+step }
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name openshiftConsole.controller:NewFromTemplateController
 * @description
 * # NewFromTemplateController
 * Controller of the openshiftConsole
 */
angular.module('openshiftConsole')
  .controller('NewFromTemplateController', function ($scope, $http, $routeParams, DataService, $q, $location, TaskList, $parse) {

    function errorPage(message) {
      var redirect = URI('error').query({
        "error_description": message
      }).toString();
      $location.url(redirect);
    }

    var dcContainers = $parse('template.controllerTemplate.podTemplate.desiredState.manifest.containers');
    var stiBuilderImage = $parse('parameters.strategy.stiStrategy.image');
    var outputImage = $parse('parameters.output.to.name || parameters.output.DockerImageReference');

    function deploymentConfigImages(dc) {
      var images = [];
      var containers = dcContainers(dc);
      if (containers) {
        containers.forEach(function(container) {
          images.push(container.image);
        });
      }
      return images;
    }

    function imageItems(data) {
      var images = [];
      var dcImages = [];
      var outputImages = {};
      data.items.forEach(function(item) {
        if (item.kind === "BuildConfig") {
          var builder = stiBuilderImage(item);
          if(builder) {
            images.push({ name: builder });
          }
          var output = outputImage(item);
          if (output) {
            outputImages[output] = true;
          }
        }
        if (item.kind === "DeploymentConfig") {
          dcImages = dcImages.concat(deploymentConfigImages(item));
        }
      });
      dcImages.forEach(function(image) {
        if (!outputImages[image]) {
          images.push({ name: image });
        }
      });
      return images;
    }

    function getHelpLinks(template) {
      var helpLinkName = /^helplink\.(.*)\.title$/;
      var helpLinkURL = /^helplink\.(.*)\.url$/;
      var helpLinks = {};
      for (var attr in template.annotations) {
        var match = attr.match(helpLinkName);
        var link;
        if (match) {
          link = helpLinks[match[1]] || {};
          link.title = template.annotations[attr];
          helpLinks[match[1]] = link;
        }
        else {
          match = attr.match(helpLinkURL);
          if (match) {
            link = helpLinks[match[1]] || {};
            link.url = template.annotations[attr];
            helpLinks[match[1]] = link;
          }
        }
      }
      return helpLinks;
    }

    $scope.projectDisplayName = function() {
      return (this.project && this.project.displayName) || this.projectName;
    };

    $scope.templateDisplayName = function() {
      return (this.template.annotations && this.template.annotations.displayName) || this.template.metadata.name;
    };

    $scope.createFromTemplate = function() {
      DataService.create("templateConfigs", $scope.template, $scope).then(
        function(config) { // success
          var titles = {
            started: "Creating " + $scope.templateDisplayName() + " in project " + $scope.projectDisplayName(),
            success: "Created " + $scope.templateDisplayName() + " in project " + $scope.projectDisplayName(),
            failure: "Failed to create " + $scope.templateDisplayName() + " in project " + $scope.projectDisplayName()
          };

          var helpLinks = getHelpLinks($scope.template);
          TaskList.add(titles, helpLinks, function() {
            var d = $q.defer();
            DataService.createList(config.items, $scope).then(
              function(result) {
                var alerts = [];
                var hasErrors = false;
                if (result.failure.length > 0) {
                  result.failure.forEach(
                    function(failure) {
                      var objectName = "";
                      if (failure.data && failure.data.details) {
                        objectName = failure.data.details.kind + " " + failure.data.details.id;
                      } else {
                        objectName = "object";
                      }
                      alerts.push({
                        type: "error",
                        message: "Cannot create " + objectName + ". ",
                        details: failure.data.message
                      });
                      hasErrors = true;
                    }
                  );
                } else {
                  alerts.push({ type: "success", message: "All items in template " + $scope.templateDisplayName() +
                    " were created successfully."});
                }
                d.resolve({alerts: alerts, hasErrors: hasErrors});
              }
            );
            return d.promise;
          });
          Navigate.toProjectOverview($scope.projectName);
        },
        function(result) { // failure
          $scope.alerts = [
            {
              type: "error",
              message: "An error occurred processing the template.",
              details: "Status: " + result.status + ". " + result.data,
            }
          ];
        }
      );
    };

    $scope.toggleOptionsExpanded = function() {
      $scope.optionsExpanded = !$scope.optionsExpanded;
    };

    var name = $routeParams.name;
    var namespace = $routeParams.namespace;

    if (!name) {
      Navigate.toErrorPage("Cannot create from template: a template name was not specified.");
      return;
    }

    $scope.emptyMessage = "Loading...";
    $scope.alerts = [];
    $scope.projectName = $routeParams.project;
    $scope.projectPromise = $.Deferred();
    DataService.get("projects", $scope.projectName, $scope).then(function(project) {
      $scope.project = project;
      $scope.projectPromise.resolve(project);
    });

    DataService.get("templates", name, $scope, {namespace: namespace}).then(
      function(template) {
        $scope.template = template;
        $scope.templateImages = imageItems(template);
        $scope.hasParameters = $scope.template.parameters && $scope.template.parameters.length > 0;
        $scope.optionsExpanded = false;
        $scope.templateUrl = template.metadata.selfLink;
        template.labels = template.labels || {};
      },
      function() {
        Navigate.toErrorPage("Cannot create from template: the specified template could not be retrieved.");
      }
    );
  });
<commit_msg>Create from template fails with JS error<commit_after>'use strict';

/**
 * @ngdoc function
 * @name openshiftConsole.controller:NewFromTemplateController
 * @description
 * # NewFromTemplateController
 * Controller of the openshiftConsole
 */
angular.module('openshiftConsole')
  .controller('NewFromTemplateController', function ($scope, $http, $routeParams, DataService, $q, $location, TaskList, $parse, Navigate) {

    function errorPage(message) {
      var redirect = URI('error').query({
        "error_description": message
      }).toString();
      $location.url(redirect);
    }

    var dcContainers = $parse('template.controllerTemplate.podTemplate.desiredState.manifest.containers');
    var stiBuilderImage = $parse('parameters.strategy.stiStrategy.image');
    var outputImage = $parse('parameters.output.to.name || parameters.output.DockerImageReference');

    function deploymentConfigImages(dc) {
      var images = [];
      var containers = dcContainers(dc);
      if (containers) {
        containers.forEach(function(container) {
          images.push(container.image);
        });
      }
      return images;
    }

    function imageItems(data) {
      var images = [];
      var dcImages = [];
      var outputImages = {};
      data.items.forEach(function(item) {
        if (item.kind === "BuildConfig") {
          var builder = stiBuilderImage(item);
          if(builder) {
            images.push({ name: builder });
          }
          var output = outputImage(item);
          if (output) {
            outputImages[output] = true;
          }
        }
        if (item.kind === "DeploymentConfig") {
          dcImages = dcImages.concat(deploymentConfigImages(item));
        }
      });
      dcImages.forEach(function(image) {
        if (!outputImages[image]) {
          images.push({ name: image });
        }
      });
      return images;
    }

    function getHelpLinks(template) {
      var helpLinkName = /^helplink\.(.*)\.title$/;
      var helpLinkURL = /^helplink\.(.*)\.url$/;
      var helpLinks = {};
      for (var attr in template.annotations) {
        var match = attr.match(helpLinkName);
        var link;
        if (match) {
          link = helpLinks[match[1]] || {};
          link.title = template.annotations[attr];
          helpLinks[match[1]] = link;
        }
        else {
          match = attr.match(helpLinkURL);
          if (match) {
            link = helpLinks[match[1]] || {};
            link.url = template.annotations[attr];
            helpLinks[match[1]] = link;
          }
        }
      }
      return helpLinks;
    }

    $scope.projectDisplayName = function() {
      return (this.project && this.project.displayName) || this.projectName;
    };

    $scope.templateDisplayName = function() {
      return (this.template.annotations && this.template.annotations.displayName) || this.template.metadata.name;
    };

    $scope.createFromTemplate = function() {
      DataService.create("templateConfigs", $scope.template, $scope).then(
        function(config) { // success
          var titles = {
            started: "Creating " + $scope.templateDisplayName() + " in project " + $scope.projectDisplayName(),
            success: "Created " + $scope.templateDisplayName() + " in project " + $scope.projectDisplayName(),
            failure: "Failed to create " + $scope.templateDisplayName() + " in project " + $scope.projectDisplayName()
          };

          var helpLinks = getHelpLinks($scope.template);
          TaskList.add(titles, helpLinks, function() {
            var d = $q.defer();
            DataService.createList(config.items, $scope).then(
              function(result) {
                var alerts = [];
                var hasErrors = false;
                if (result.failure.length > 0) {
                  result.failure.forEach(
                    function(failure) {
                      var objectName = "";
                      if (failure.data && failure.data.details) {
                        objectName = failure.data.details.kind + " " + failure.data.details.id;
                      } else {
                        objectName = "object";
                      }
                      alerts.push({
                        type: "error",
                        message: "Cannot create " + objectName + ". ",
                        details: failure.data.message
                      });
                      hasErrors = true;
                    }
                  );
                } else {
                  alerts.push({ type: "success", message: "All items in template " + $scope.templateDisplayName() +
                    " were created successfully."});
                }
                d.resolve({alerts: alerts, hasErrors: hasErrors});
              }
            );
            return d.promise;
          });
          Navigate.toProjectOverview($scope.projectName);
        },
        function(result) { // failure
          $scope.alerts = [
            {
              type: "error",
              message: "An error occurred processing the template.",
              details: "Status: " + result.status + ". " + result.data,
            }
          ];
        }
      );
    };

    $scope.toggleOptionsExpanded = function() {
      $scope.optionsExpanded = !$scope.optionsExpanded;
    };

    var name = $routeParams.name;
    var namespace = $routeParams.namespace;

    if (!name) {
      Navigate.toErrorPage("Cannot create from template: a template name was not specified.");
      return;
    }

    $scope.emptyMessage = "Loading...";
    $scope.alerts = [];
    $scope.projectName = $routeParams.project;
    $scope.projectPromise = $.Deferred();
    DataService.get("projects", $scope.projectName, $scope).then(function(project) {
      $scope.project = project;
      $scope.projectPromise.resolve(project);
    });

    DataService.get("templates", name, $scope, {namespace: namespace}).then(
      function(template) {
        $scope.template = template;
        $scope.templateImages = imageItems(template);
        $scope.hasParameters = $scope.template.parameters && $scope.template.parameters.length > 0;
        $scope.optionsExpanded = false;
        $scope.templateUrl = template.metadata.selfLink;
        template.labels = template.labels || {};
      },
      function() {
        Navigate.toErrorPage("Cannot create from template: the specified template could not be retrieved.");
      }
    );
  });
<|endoftext|>


<commit_before>import React, { Components } from 'react';

const CommentCount = (props) => {
  let textToDisplay;

  if (props.numOfComments === 0) {
    textToDisplay = `[ No Comments ]`;
  } else if (props.numOfComments === 1) {
    textToDisplay = `[ ${props.numOfComments} Comment ]`;
  } else {
    textToDisplay = `[ ${props.numOfComments} Comments ]`;
  }

  return (

      {textToDisplay}

  );
};

export default CommentCount;
<commit_msg>removes unused class<commit_after>import React from 'react';

const CommentCount = (props) => {
  let textToDisplay;

  if (props.numOfComments === 0) {
    textToDisplay = `[ No Comments ]`;
  } else if (props.numOfComments === 1) {
    textToDisplay = `[ ${props.numOfComments} Comment ]`;
  } else {
    textToDisplay = `[ ${props.numOfComments} Comments ]`;
  }

  return (

      {textToDisplay}

  );
};

export default CommentCount;
<|endoftext|>


<commit_before>// @flow

import React, { Component } from 'react';
import { Link, NavLink, withRouter } from 'react-router-dom';
import { Modal } from 'react-overlays';
import Dropdown from '../Dropdown';
import Icon from '../Icon';
import Search from '../Search';
import { ProfilePicture } from '../Image';
import FancyNodesCanvas from './FancyNodesCanvas';
import NotificationsDropdown from '../HeaderNotifications';
import Button from '../Button';
import styles from './Header.css';
import {
  LoginForm,
  RegisterForm,
  ForgotPasswordForm,
} from 'app/components/LoginForm';
import { Flex } from 'app/components/Layout';
import cx from 'classnames';
import { applySelectedTheme, getTheme } from 'app/utils/themeUtils';
import { Image } from 'app/components/Image';
import type { UserEntity } from 'app/reducers/users';
import logoLightMode from 'app/assets/logo-dark.png';
import logoDarkMode from 'app/assets/logo.png';
import LoadingIndicator from 'app/components/LoadingIndicator';

type Props = {
  searchOpen: boolean,
  toggleSearch: () => any,
  currentUser: UserEntity,
  loggedIn: boolean,
  login: () => Promise<*>,
  logout: () => void,
  notificationsData: Object,
  fetchNotifications: () => void,
  notifications: Array<Object>,
  markAllNotifications: () => Promise<void>,
  fetchNotificationData: () => Promise<void>,
  upcomingMeeting: string,
  loading: boolean,
};

type State = {
  accountOpen: boolean,
  shake: boolean,
  mode: 'login' | 'register' | 'forgotPassword',
};

type AccountDropdownItemsProps = {
  logout: () => void,
  onClose: () => void,
  username: string,
};

function AccountDropdownItems({
  logout,
  onClose,
  username,
}: AccountDropdownItemsProps) {
  return (
    <Dropdown.List>
      <Dropdown.ListItem>
        <NavLink
          to="/users/me"
          onClick={onClose}
          style={{ color: 'var(--lego-color-gray)' }}
        >
          {username}
          <Icon name="contact" size={24} />
        </NavLink>
      </Dropdown.ListItem>
      <Dropdown.Divider />
      <Dropdown.ListItem>
        <Link to="/users/me/settings/profile" onClick={onClose}>
          Innstillinger
          <Icon name="cog" size={24} />
        </Link>
      </Dropdown.ListItem>
      <Dropdown.ListItem>
        <Link to="/meetings/" onClick={onClose}>
          Møteinnkallinger
          <Icon name="calendar" size={24} />
        </Link>
      </Dropdown.ListItem>
      <Dropdown.Divider />
      <Dropdown.ListItem>
        <Button flat onClick={() => (logout(), onClose())}>
          Logg ut
          <Icon name="log-out" size={24} />
        </Button>
      </Dropdown.ListItem>
    </Dropdown.List>
  );
}

class Header extends Component<Props, State> {
  state = {
    accountOpen: false,
    shake: false,
    mode: 'login',
  };

  toggleRegisterUser = (e: Event) => {
    this.setState({ mode: 'register' });
    e.stopPropagation();
  };

  toggleForgotPassword = (e: Event) => {
    this.setState({ mode: 'forgotPassword' });
    e.stopPropagation();
  };

  toggleBack = (e: Event) => {
    this.setState({ mode: 'login' });
    e.stopPropagation();
  };

  render() {
    const { loggedIn, currentUser, loading } = this.props;
    const isLogin = this.state.mode === 'login';
    let title, form;

    if (loggedIn && currentUser && currentUser.selectedTheme != getTheme()) {
      applySelectedTheme(currentUser.selectedTheme || 'light');
    }

    switch (this.state.mode) {
      case 'login':
        title = 'Logg inn';
        form = <LoginForm />;
        break;
      case 'register':
        title = 'Register';
        form = <RegisterForm />;
        break;
      case 'forgotPassword':
        title = 'Glemt passord';
        form = <ForgotPasswordForm />;
        break;
    }

    const MeetingButton = withRouter(({ history }) => (
      <button
        type="button"
        onClick={() => {
          history.push(`/meetings/${this.props.upcomingMeeting}`);
        }}
      >
        <Icon name="calendar" className={styles.meetingIcon} />
      </button>
    ));

    return (

        <FancyNodesCanvas height={300} />

          <Link to="/">
            <LoadingIndicator loading={loading}>

                <Image
                  src={logoLightMode}
                  className={styles.logoLightMode}
                  alt=""
                />

            </LoadingIndicator>
            <Image src={logoDarkMode} className={styles.logoDarkMode} alt="" />
          </Link>

              <NavLink to="/events" activeClassName={styles.activeItem}>
                Arrangementer
              </NavLink>
              {!loggedIn ? (
                <NavLink
                  to="/pages/bedrifter/for-bedrifter"
                  activeClassName={styles.activeItem}
                >
                  For bedrifter
                </NavLink>
              ) : (
                <NavLink to="/joblistings" activeClassName={styles.activeItem}>
                  Karriere
                </NavLink>
              )}
              <NavLink
                to="/pages/info-om-abakus"
                activeClassName={styles.activeItem}
              >
                Om Abakus
              </NavLink>

              {loggedIn && (
                <NotificationsDropdown
                  notificationsData={this.props.notificationsData}
                  fetchNotifications={this.props.fetchNotifications}
                  notifications={this.props.notifications}
                  markAllNotifications={this.props.markAllNotifications}
                  fetchNotificationData={this.props.fetchNotificationData}
                />
              )}

              {loggedIn && this.props.upcomingMeeting && <MeetingButton />}

              {loggedIn && (
                <Dropdown
                  show={this.state.accountOpen}
                  toggle={() =>
                    this.setState((state) => ({
                      accountOpen: !state.accountOpen,
                    }))
                  }
                  triggerComponent={
                    <ProfilePicture
                      size={30}
                      alt="user"
                      user={this.props.currentUser}
                      style={{ verticalAlign: 'middle' }}
                    />
                  }
                >
                  <AccountDropdownItems
                    onClose={() => {}}
                    username={this.props.currentUser.username}
                    logout={this.props.logout}
                  />
                </Dropdown>
              )}

              {!loggedIn && (
                <Dropdown
                  show={this.state.accountOpen}
                  toggle={() =>
                    this.setState((state) => ({
                      accountOpen: !state.accountOpen,
                      shake: false,
                    }))
                  }
                  contentClassName={cx(
                    this.state.shake ? 'animated shake' : '',
                    styles.dropdown
                  )}
                  triggerComponent={<Icon name="contact" size={30} />}
                >

                    <Flex
                      component="h2"
                      justifyContent="space-between"
                      allignItems="center"
                      className="u-mb"
                      style={{ whitespace: 'nowrap' }}
                    >
                      {title}
                      {isLogin && (

                          <button
                            onClick={this.toggleForgotPassword}
                            className={styles.toggleButton}
                          >
                            Glemt passord
                          </button>
                          •
                          <button
                            onClick={this.toggleRegisterUser}
                            className={styles.toggleButton}
                          >
                            Jeg er ny
                          </button>

                      )}

                      {!isLogin && (
                        <button
                          onClick={this.toggleBack}
                          className={styles.toggleButton}
                        >
                          Tilbake
                        </button>
                      )}
                    </Flex>
                    {form}

                </Dropdown>
              )}

              <button onClick={this.props.toggleSearch}>
                <Icon name="menu" size={30} className={styles.searchIcon} />
              </button>

          <Modal
            show={this.props.searchOpen}
            onHide={this.props.toggleSearch}
            backdropClassName={styles.backdrop}
            backdrop
            autoFocus={false}
          >
            <Search
              loggedIn={loggedIn}
              isOpen={this.props.searchOpen}
              onCloseSearch={this.props.toggleSearch}
            />
          </Modal>

    );
  }
}
export default Header;
<commit_msg>fix darkmode logo in header<commit_after>// @flow

import React, { Component } from 'react';
import { Link, NavLink, withRouter } from 'react-router-dom';
import { Modal } from 'react-overlays';
import Dropdown from '../Dropdown';
import Icon from '../Icon';
import Search from '../Search';
import { ProfilePicture } from '../Image';
import FancyNodesCanvas from './FancyNodesCanvas';
import NotificationsDropdown from '../HeaderNotifications';
import Button from '../Button';
import styles from './Header.css';
import {
  LoginForm,
  RegisterForm,
  ForgotPasswordForm,
} from 'app/components/LoginForm';
import { Flex } from 'app/components/Layout';
import cx from 'classnames';
import { applySelectedTheme, getTheme } from 'app/utils/themeUtils';
import { Image } from 'app/components/Image';
import type { UserEntity } from 'app/reducers/users';
import logoLightMode from 'app/assets/logo-dark.png';
import logoDarkMode from 'app/assets/logo.png';
import LoadingIndicator from 'app/components/LoadingIndicator';

type Props = {
  searchOpen: boolean,
  toggleSearch: () => any,
  currentUser: UserEntity,
  loggedIn: boolean,
  login: () => Promise<*>,
  logout: () => void,
  notificationsData: Object,
  fetchNotifications: () => void,
  notifications: Array<Object>,
  markAllNotifications: () => Promise<void>,
  fetchNotificationData: () => Promise<void>,
  upcomingMeeting: string,
  loading: boolean,
};

type State = {
  accountOpen: boolean,
  shake: boolean,
  mode: 'login' | 'register' | 'forgotPassword',
};

type AccountDropdownItemsProps = {
  logout: () => void,
  onClose: () => void,
  username: string,
};

function AccountDropdownItems({
  logout,
  onClose,
  username,
}: AccountDropdownItemsProps) {
  return (
    <Dropdown.List>
      <Dropdown.ListItem>
        <NavLink
          to="/users/me"
          onClick={onClose}
          style={{ color: 'var(--lego-color-gray)' }}
        >
          {username}
          <Icon name="contact" size={24} />
        </NavLink>
      </Dropdown.ListItem>
      <Dropdown.Divider />
      <Dropdown.ListItem>
        <Link to="/users/me/settings/profile" onClick={onClose}>
          Innstillinger
          <Icon name="cog" size={24} />
        </Link>
      </Dropdown.ListItem>
      <Dropdown.ListItem>
        <Link to="/meetings/" onClick={onClose}>
          Møteinnkallinger
          <Icon name="calendar" size={24} />
        </Link>
      </Dropdown.ListItem>
      <Dropdown.Divider />
      <Dropdown.ListItem>
        <Button flat onClick={() => (logout(), onClose())}>
          Logg ut
          <Icon name="log-out" size={24} />
        </Button>
      </Dropdown.ListItem>
    </Dropdown.List>
  );
}

class Header extends Component<Props, State> {
  state = {
    accountOpen: false,
    shake: false,
    mode: 'login',
  };

  toggleRegisterUser = (e: Event) => {
    this.setState({ mode: 'register' });
    e.stopPropagation();
  };

  toggleForgotPassword = (e: Event) => {
    this.setState({ mode: 'forgotPassword' });
    e.stopPropagation();
  };

  toggleBack = (e: Event) => {
    this.setState({ mode: 'login' });
    e.stopPropagation();
  };

  render() {
    const { loggedIn, currentUser, loading } = this.props;
    const isLogin = this.state.mode === 'login';
    let title, form;

    if (loggedIn && currentUser && currentUser.selectedTheme != getTheme()) {
      applySelectedTheme(currentUser.selectedTheme || 'light');
    }

    switch (this.state.mode) {
      case 'login':
        title = 'Logg inn';
        form = <LoginForm />;
        break;
      case 'register':
        title = 'Register';
        form = <RegisterForm />;
        break;
      case 'forgotPassword':
        title = 'Glemt passord';
        form = <ForgotPasswordForm />;
        break;
    }

    const MeetingButton = withRouter(({ history }) => (
      <button
        type="button"
        onClick={() => {
          history.push(`/meetings/${this.props.upcomingMeeting}`);
        }}
      >
        <Icon name="calendar" className={styles.meetingIcon} />
      </button>
    ));

    return (

        <FancyNodesCanvas height={300} />

          <Link to="/">
            <LoadingIndicator loading={loading}>

                <Image
                  src={logoLightMode}
                  className={styles.logoLightMode}
                  alt=""
                />
                <Image
                  src={logoDarkMode}
                  className={styles.logoDarkMode}
                  alt=""
                />

            </LoadingIndicator>
          </Link>

              <NavLink to="/events" activeClassName={styles.activeItem}>
                Arrangementer
              </NavLink>
              {!loggedIn ? (
                <NavLink
                  to="/pages/bedrifter/for-bedrifter"
                  activeClassName={styles.activeItem}
                >
                  For bedrifter
                </NavLink>
              ) : (
                <NavLink to="/joblistings" activeClassName={styles.activeItem}>
                  Karriere
                </NavLink>
              )}
              <NavLink
                to="/pages/info-om-abakus"
                activeClassName={styles.activeItem}
              >
                Om Abakus
              </NavLink>

              {loggedIn && (
                <NotificationsDropdown
                  notificationsData={this.props.notificationsData}
                  fetchNotifications={this.props.fetchNotifications}
                  notifications={this.props.notifications}
                  markAllNotifications={this.props.markAllNotifications}
                  fetchNotificationData={this.props.fetchNotificationData}
                />
              )}

              {loggedIn && this.props.upcomingMeeting && <MeetingButton />}

              {loggedIn && (
                <Dropdown
                  show={this.state.accountOpen}
                  toggle={() =>
                    this.setState((state) => ({
                      accountOpen: !state.accountOpen,
                    }))
                  }
                  triggerComponent={
                    <ProfilePicture
                      size={30}
                      alt="user"
                      user={this.props.currentUser}
                      style={{ verticalAlign: 'middle' }}
                    />
                  }
                >
                  <AccountDropdownItems
                    onClose={() => {}}
                    username={this.props.currentUser.username}
                    logout={this.props.logout}
                  />
                </Dropdown>
              )}

              {!loggedIn && (
                <Dropdown
                  show={this.state.accountOpen}
                  toggle={() =>
                    this.setState((state) => ({
                      accountOpen: !state.accountOpen,
                      shake: false,
                    }))
                  }
                  contentClassName={cx(
                    this.state.shake ? 'animated shake' : '',
                    styles.dropdown
                  )}
                  triggerComponent={<Icon name="contact" size={30} />}
                >

                    <Flex
                      component="h2"
                      justifyContent="space-between"
                      allignItems="center"
                      className="u-mb"
                      style={{ whitespace: 'nowrap' }}
                    >
                      {title}
                      {isLogin && (

                          <button
                            onClick={this.toggleForgotPassword}
                            className={styles.toggleButton}
                          >
                            Glemt passord
                          </button>
                          •
                          <button
                            onClick={this.toggleRegisterUser}
                            className={styles.toggleButton}
                          >
                            Jeg er ny
                          </button>

                      )}

                      {!isLogin && (
                        <button
                          onClick={this.toggleBack}
                          className={styles.toggleButton}
                        >
                          Tilbake
                        </button>
                      )}
                    </Flex>
                    {form}

                </Dropdown>
              )}

              <button onClick={this.props.toggleSearch}>
                <Icon name="menu" size={30} className={styles.searchIcon} />
              </button>

          <Modal
            show={this.props.searchOpen}
            onHide={this.props.toggleSearch}
            backdropClassName={styles.backdrop}
            backdrop
            autoFocus={false}
          >
            <Search
              loggedIn={loggedIn}
              isOpen={this.props.searchOpen}
              onCloseSearch={this.props.toggleSearch}
            />
          </Modal>

    );
  }
}
export default Header;
<|endoftext|>


<commit_before>// Pointrel20151212 store module to store immutable data in memory

var Promise = require('promise');
var crypto = require('crypto');
var uuid = require('node-uuid');

var maxShardLength = 4096000;

function makeAlwaysSuccessfulPromise(result) {
    var promise = new Promise(function (resolve, reject) {
        // reject("Unfinished");
        resolve(result);
    });

    return promise;
}

function makeShardName() {
	var uuid4 = uuid.v4();
    return "shard-" + uuid4 + ".twirlip";
}

function StoreMemory(defaultMetadata) {
    this.shards = {};
    this.sha256ToShardAndPosition = {};
    this.defaultMetadata = defaultMetadata || {};
    this.currentShardName = null;
    this.allocateNewShard();
}

StoreMemory.prototype.allocateNewShard = function() {
    this.currentShardName = makeShardName();
    console.log("Making new shard", this.currentShardName);
    this.shards[this.currentShardName] = "";
};

StoreMemory.prototype.writeToCurrentShard = function(dataString) {
	if (this.shards[this.currentShardName].length > maxShardLength) {
		this.allocateNewShard();
	}
	var start = this.shards[this.currentShardName].length;
	this.shards[this.currentShardName] += dataString + "\n";
	return {shardName: this.currentShardName, start: start, length: dataString.length};
};

function isString(value) {
    return typeof value === 'string' || value instanceof String;
}

StoreMemory.prototype.wrap = function(what, metadata) {
    if (!metadata) metadata = {};

    var wrapper = {
        who: metadata.who || this.defaultMetadata.who,
        what: what,
        where: metadata.where || this.defaultMetadata.where,
        when: metadata.when || this.defaultMetadata.when || new Date().toISOString(),
        why: metadata.why || this.defaultMetadata.why,
        how: metadata.how || this.defaultMetadata.how
    };

    return wrapper;
};

StoreMemory.prototype.store = function(data) {
    var dataAsString = JSON.stringify(data);
    if (dataAsString.length > maxShardLength) throw new Error("data to be stored is too long: " + dataAsString.length);
    var sha256 = crypto.createHash('sha256').update(dataAsString, 'utf8').digest('hex');
    // console.log("calculated sha256 of data to store", sha256);

    var location = this.writeToCurrentShard(dataAsString);
    this.sha256ToShardAndPosition[sha256] = location;
    return makeAlwaysSuccessfulPromise(sha256);
};

StoreMemory.prototype.fetch = function(sha256) {
	var location = this.sha256ToShardAndPosition[sha256];
	if (!location) return null;
	// console.log("location", location);
	// console.log("shard", this.shards[location.shardName]);
    var resultString = this.shards[location.shardName].substring(location.start, location.start + location.length);
    // console.log("retrieved resultString", "|" + resultString + "|");
    var result = JSON.parse(resultString);
    // console.log("retrieved result", result);
    return makeAlwaysSuccessfulPromise(result);
};

module.exports = StoreMemory;<commit_msg>Don't store duplicate objects in StoreMemory.js<commit_after>// Pointrel20151212 store module to store immutable data in memory

var Promise = require('promise');
var crypto = require('crypto');
var uuid = require('node-uuid');

var maxShardLength = 4096000;

var debugLogging = false;

function makeAlwaysSuccessfulPromise(result) {
    var promise = new Promise(function (resolve, reject) {
        // reject("Unfinished");
        resolve(result);
    });

    return promise;
}

function makeShardName() {
	var uuid4 = uuid.v4();
    return "shard-" + uuid4 + ".twirlip";
}

function StoreMemory(defaultMetadata) {
    this.shards = {};
    this.sha256ToShardAndPosition = {};
    this.defaultMetadata = defaultMetadata || {};
    this.currentShardName = null;
    this.allocateNewShard();
}

StoreMemory.prototype.allocateNewShard = function() {
    this.currentShardName = makeShardName();
    if (debugLogging) console.log("Making new shard", this.currentShardName);
    this.shards[this.currentShardName] = "";
};

StoreMemory.prototype.writeToCurrentShard = function(dataString) {
	if (this.shards[this.currentShardName].length > maxShardLength) {
		this.allocateNewShard();
	}
	var start = this.shards[this.currentShardName].length;
	this.shards[this.currentShardName] += dataString + "\n";
	return {shardName: this.currentShardName, start: start, length: dataString.length};
};

function isString(value) {
    return typeof value === 'string' || value instanceof String;
}

StoreMemory.prototype.wrap = function(what, metadata) {
    if (!metadata) metadata = {};

    var wrapper = {
        who: metadata.who || this.defaultMetadata.who,
        what: what,
        where: metadata.where || this.defaultMetadata.where,
        when: metadata.when || this.defaultMetadata.when || new Date().toISOString(),
        why: metadata.why || this.defaultMetadata.why,
        how: metadata.how || this.defaultMetadata.how
    };

    return wrapper;
};

StoreMemory.prototype.store = function(data) {
    var dataAsString = JSON.stringify(data);
    if (dataAsString.length > maxShardLength) throw new Error("data to be stored is too long: " + dataAsString.length);
    var sha256 = crypto.createHash('sha256').update(dataAsString, 'utf8').digest('hex');

	var location = this.sha256ToShardAndPosition[sha256];
	if (!location) {
	    location = this.writeToCurrentShard(dataAsString);
	    if (debugLogging) console.log("store: sha256 and location of data to store", sha256, location, dataAsString.substring(0, 40) + "...");
	    this.sha256ToShardAndPosition[sha256] = location;
	} else {
		if (debugLogging) console.log("store: previously stored ", sha256, location, dataAsString.substring(0, 40) + "...");
	}

    return makeAlwaysSuccessfulPromise(sha256);
};

StoreMemory.prototype.fetch = function(sha256) {
	var location = this.sha256ToShardAndPosition[sha256];
	if (!location) return null;
	// console.log("location", location);
	// console.log("shard", this.shards[location.shardName]);
    var resultString = this.shards[location.shardName].substring(location.start, location.start + location.length);
    // console.log("retrieved resultString", "|" + resultString + "|");
    var result = JSON.parse(resultString);
    // console.log("retrieved result", result);
    return makeAlwaysSuccessfulPromise(result);
};

module.exports = StoreMemory;<|endoftext|>


<commit_before>// jscs:disable
(function(){
  angular.module('ncsaas')
    .service('baseServiceClass', ['$q', 'currentStateService', '$resource', 'ENV', baseServiceClass]);
  function baseServiceClass($q, currentStateService, $resource, ENV) {
    // Base service class for services with pagination
    // pageSize, page, pages - default variables, you can change this in your init method or call this._super() in init
    var BaseServiceClass = Class.extend({
      pageSize:null,
      page:null,
      pages:null,
      currentStateService:null,
      endpoint:null,
      customerName:null,

      init:function(){
        this.pageSize = 10;
        this.page = 1;
        this.pages = null;
        this.currentStateService = currentStateService;
        this.stopResource = this.operation.bind(null, 'stop');
        this.startResource = this.operation.bind(null, 'start');
        this.restartResource = this.operation.bind(null, 'restart');
      },
      getList:function(filter) {
        var vm = this;
        var deferred = $q.defer();
        filter = filter || {};
        var queryList = function() {
          filter.page = vm.page;
          filter.page_size = vm.pageSize;
          vm.getFactory(true).query(filter,function(response, responseHeaders){
            var header = responseHeaders(),
              objQuantity = !header['x-result-count'] ? null : header['x-result-count'];
            if (objQuantity) {
              vm.pages = Math.ceil(objQuantity/vm.pageSize);
            }
            deferred.resolve(response);
          }, function(err) {
            deferred.reject(err);
          });
        };

        if (vm.currentStateService == null) {
          queryList();
        } else {
          vm.currentStateService.getCustomer().then(function (response) {
            /*jshint camelcase: false */
            filter.customer_name = (this.customerName) ? this.customerName() : response.name;
            queryList();
          }, function (err) {
            deferred.reject(err);
          });
        }

        return deferred.promise;
      },
      $create:function() {
        var Instance = this.getFactory(false);
        return new Instance();
      },
      $delete:function(uuid) {
        var deferred = $q.defer();
        this.getFactory(false).Delete({},{uuid: uuid}).$promise.then(function(response) {
          deferred.resolve(response);
        }, function(err) {
          deferred.reject(err);
        });
        return deferred.promise;
      },
      operation:function(operation, uuid) {
        var deferred = $q.defer();
        this.getFactory(false).Operation({uuid: uuid, operation: operation}).$promise.then(function(response){
          deferred.resolve(response);
        }, function(err) {
          deferred.reject(err);
        });
        return deferred.promise;
      },
      getFactory:function(params) {
        return $resource(ENV.apiEndpoint + 'api' + this.getEndpoint(params) + ':UUID/', {UUID:'@uuid',
            page_size:'@page_size', page:'@page'},
          {
            Operation: {
              method:'POST',
              url:ENV.apiEndpoint + 'api' + this.getEndpoint(params) + ':UUID/:operation/',
              params: {UUID:'@uuid', operation:'@operation'}
            },
            Delete: {
              method:'DELETE'
            }
          }
        );
      },
      $get:function(uuid) {
        return this.getFactory(false).get({uuid: uuid}).$promise;
      },
      getEndpoint:function(params) {
        return this.endpoint;
      }
    });

    return BaseServiceClass;
  }
})();
<commit_msg>Change 'params' agrument to 'isList' in getEndpoint (SAAS-150)<commit_after>// jscs:disable
(function(){
  angular.module('ncsaas')
    .service('baseServiceClass', ['$q', 'currentStateService', '$resource', 'ENV', baseServiceClass]);
  function baseServiceClass($q, currentStateService, $resource, ENV) {
    // Base service class for services with pagination
    // pageSize, page, pages - default variables, you can change this in your init method or call this._super() in init
    var BaseServiceClass = Class.extend({
      pageSize:null,
      page:null,
      pages:null,
      currentStateService:null,
      endpoint:null,
      customerName:null,

      init:function(){
        this.pageSize = 10;
        this.page = 1;
        this.pages = null;
        this.currentStateService = currentStateService;
        this.stopResource = this.operation.bind(null, 'stop');
        this.startResource = this.operation.bind(null, 'start');
        this.restartResource = this.operation.bind(null, 'restart');
      },
      getList:function(filter) {
        var vm = this;
        var deferred = $q.defer();
        filter = filter || {};
        var queryList = function() {
          filter.page = vm.page;
          filter.page_size = vm.pageSize;
          vm.getFactory(true).query(filter,function(response, responseHeaders){
            var header = responseHeaders(),
              objQuantity = !header['x-result-count'] ? null : header['x-result-count'];
            if (objQuantity) {
              vm.pages = Math.ceil(objQuantity/vm.pageSize);
            }
            deferred.resolve(response);
          }, function(err) {
            deferred.reject(err);
          });
        };

        if (vm.currentStateService == null) {
          queryList();
        } else {
          vm.currentStateService.getCustomer().then(function (response) {
            /*jshint camelcase: false */
            filter.customer_name = (this.customerName) ? this.customerName() : response.name;
            queryList();
          }, function (err) {
            deferred.reject(err);
          });
        }

        return deferred.promise;
      },
      $create:function() {
        var Instance = this.getFactory(false);
        return new Instance();
      },
      $delete:function(uuid) {
        var deferred = $q.defer();
        this.getFactory(false).Delete({},{uuid: uuid}).$promise.then(function(response) {
          deferred.resolve(response);
        }, function(err) {
          deferred.reject(err);
        });
        return deferred.promise;
      },
      operation:function(operation, uuid) {
        var deferred = $q.defer();
        this.getFactory(false).Operation({uuid: uuid, operation: operation}).$promise.then(function(response){
          deferred.resolve(response);
        }, function(err) {
          deferred.reject(err);
        });
        return deferred.promise;
      },
      getFactory:function(params) {
        return $resource(ENV.apiEndpoint + 'api' + this.getEndpoint(params) + ':UUID/', {UUID:'@uuid',
            page_size:'@page_size', page:'@page'},
          {
            Operation: {
              method:'POST',
              url:ENV.apiEndpoint + 'api' + this.getEndpoint(params) + ':UUID/:operation/',
              params: {UUID:'@uuid', operation:'@operation'}
            },
            Delete: {
              method:'DELETE'
            }
          }
        );
      },
      $get:function(uuid) {
        return this.getFactory(false).get({uuid: uuid}).$promise;
      },
      getEndpoint:function(isList) {
        return this.endpoint;
      }
    });

    return BaseServiceClass;
  }
})();
<|endoftext|>


<commit_before>// Pointrel20151212 store module to store immutable data in memory

var Promise = require('promise');
var crypto = require('crypto');
var uuid = require('node-uuid');

var maxShardLength = 4096000;

var debugLogging = false;

function makeAlwaysSuccessfulPromise(result) {
    var promise = new Promise(function (resolve, reject) {
        // reject("Unfinished");
        resolve(result);
    });

    return promise;
}

function makeShardName() {
	var uuid4 = uuid.v4();
    return "shard-" + uuid4 + ".twirlip";
}

function StoreMemory(defaultMetadata) {
    this.shards = {};
    this.sha256ToShardAndPosition = {};
    this.defaultMetadata = defaultMetadata || {};
    this.currentShardName = null;
    this.allocateNewShard();
}

StoreMemory.prototype.allocateNewShard = function() {
    this.currentShardName = makeShardName();
    if (debugLogging) console.log("Making new shard", this.currentShardName);
    this.shards[this.currentShardName] = "";
};

StoreMemory.prototype.writeToCurrentShard = function(dataString) {
	if (this.shards[this.currentShardName].length > maxShardLength) {
		this.allocateNewShard();
	}
	var start = this.shards[this.currentShardName].length;
	this.shards[this.currentShardName] += dataString + "\n";
	return {shardName: this.currentShardName, start: start, length: dataString.length};
};

function isString(value) {
    return typeof value === 'string' || value instanceof String;
}

StoreMemory.prototype.wrap = function(what, metadata) {
    if (!metadata) metadata = {};

    var wrapper = {
        who: metadata.who || this.defaultMetadata.who,
        what: what,
        where: metadata.where || this.defaultMetadata.where,
        when: metadata.when || this.defaultMetadata.when || new Date().toISOString(),
        why: metadata.why || this.defaultMetadata.why,
        how: metadata.how || this.defaultMetadata.how
    };

    return wrapper;
};

StoreMemory.prototype.store = function(data) {
    var dataAsString = JSON.stringify(data);
    if (dataAsString.length > maxShardLength) throw new Error("data to be stored is too long: " + dataAsString.length);
    var sha256 = crypto.createHash('sha256').update(dataAsString, 'utf8').digest('hex');

	var location = this.sha256ToShardAndPosition[sha256];
	if (!location) {
	    location = this.writeToCurrentShard(dataAsString);
	    if (debugLogging) console.log("store: sha256 and location of data to store", sha256, location, dataAsString.substring(0, 40) + "...");
	    this.sha256ToShardAndPosition[sha256] = location;
	} else {
		if (debugLogging) console.log("store: previously stored ", sha256, location, dataAsString.substring(0, 40) + "...");
	}

    return makeAlwaysSuccessfulPromise(sha256);
};

StoreMemory.prototype.fetch = function(sha256) {
	var location = this.sha256ToShardAndPosition[sha256];
	if (!location) return null;
	// console.log("location", location);
	// console.log("shard", this.shards[location.shardName]);
    var resultString = this.shards[location.shardName].substring(location.start, location.start + location.length);
    // console.log("retrieved resultString", "|" + resultString + "|");
    var result = JSON.parse(resultString);
    // console.log("retrieved result", result);
    return makeAlwaysSuccessfulPromise(result);
};

module.exports = StoreMemory;<commit_msg>Improvements to StoreMemory<commit_after>// Pointrel20151212 store module to store immutable data in memory

var Promise = require('promise');
var crypto = require('crypto');
var uuid = require('node-uuid');

var maxShardLength = 4096000;

var debugLogging = false;

function makeAlwaysSuccessfulPromise(result) {
    var promise = new Promise(function (resolve, reject) {
        // reject("Unfinished");
        resolve(result);
    });

    return promise;
}

function makeShardName() {
	var uuid4 = uuid.v4();
    return "shard-" + uuid4 + ".twirlip";
}

function StoreMemory(defaultMetadata) {
    this.shards = {};
    this.sha256ToShardAndPosition = {};
    this.defaultMetadata = defaultMetadata || {};
    this.currentShardName = null;
    this.allocateNewShard();
}

StoreMemory.prototype.allocateNewShard = function() {
    this.currentShardName = makeShardName();
    if (debugLogging) console.log("StoreMemory: Making new shard", this.currentShardName);
    this.shards[this.currentShardName] = "";
};

StoreMemory.prototype.writeToCurrentShard = function(dataString) {
	if (this.shards[this.currentShardName].length > maxShardLength) {
		this.allocateNewShard();
	}
	var start = this.shards[this.currentShardName].length + 1;
	this.shards[this.currentShardName] += "\n" + dataString + "\n";
	return {shardName: this.currentShardName, start: start, length: dataString.length};
};

StoreMemory.prototype.wrap = function(what, metadata) {
    if (!metadata) metadata = {};

    var wrapper = {
        who: metadata.who || this.defaultMetadata.who,
        what: what,
        where: metadata.where || this.defaultMetadata.where,
        when: metadata.when || this.defaultMetadata.when || new Date().toISOString(),
        why: metadata.why || this.defaultMetadata.why,
        how: metadata.how || this.defaultMetadata.how
    };

    return wrapper;
};

StoreMemory.prototype.store = function(data) {
    var dataAsString = JSON.stringify(data);
    if (dataAsString.length > maxShardLength) throw new Error("data to be stored is too long: " + dataAsString.length);
    var sha256 = crypto.createHash('sha256').update(dataAsString, 'utf8').digest('hex');

	var location = this.sha256ToShardAndPosition[sha256];
	if (!location) {
	    location = this.writeToCurrentShard(dataAsString);
	    if (debugLogging) console.log("store: sha256 and location of data to store", sha256, location, dataAsString.substring(0, 40) + "...");
	    this.sha256ToShardAndPosition[sha256] = location;
	} else {
		if (debugLogging) console.log("store: previously stored ", sha256, location, dataAsString.substring(0, 40) + "...");
	}

    return makeAlwaysSuccessfulPromise(sha256);
};

StoreMemory.prototype.fetch = function(sha256) {
	var location = this.sha256ToShardAndPosition[sha256];
	if (!location) return null;
	// console.log("location", location);
	// console.log("shard", this.shards[location.shardName]);
    var resultString = this.shards[location.shardName].substring(location.start, location.start + location.length);
    // console.log("retrieved resultString", "|" + resultString + "|");
    var result = JSON.parse(resultString);
    // console.log("retrieved result", result);
    return makeAlwaysSuccessfulPromise(result);
};

module.exports = StoreMemory;<|endoftext|>