<commit_before>/*
* Name : DslDomain.js
* Module : Back-end::Lib::Model::DSLModel
* Location : /lib/model/dslmodel/
*
* History :
*
* Version         Date           Programmer
* =================================================
* 0.0.1          2016-05-30     Davide Polonio
* -------------------------------------------------
* Corretto typo. Trovato errore in `new Engine()`
* =================================================
* 0.0.1          2016-05-11     Andrea Mantovani
* -------------------------------------------------
* Rimosso metodo init
* Rinominato metodo DslLoadFile in DslLoad
* =================================================
* 0.0.1          2014-03-01     Federico Poli
* -------------------------------------------------
* Codifica modulo
* =================================================
*/

"use strict";

var DslConcreteStrategy = require("./DslConcreteStrategy");
var MaapError = require("../utils/MaapError.js");

var _prefix = "_id";

var DslDomain = function() {
    this.modelRegistry = {};
    this.strategy = new DslConcreteStrategy();
    this.id = 0;
};

DslDomain.prototype.loadDSL = function(data, callback) {
    var self = this;
    self.strategy.loadDSL(data, function(models) {
		var ids = []

		models.forEach(function(model) {
			ids.push(self.register(model));
		});

		callback(undefined, ids);

    }, function(maaperror) {
		callback(maaperror, undefined);
    });
};

DslDomain.prototype.register = function(model) {
    var idc = `${_prefix}${this.id++}`;
    this.modelRegistry[idc] = model;

    return {
		token: idc,
		type: model.constructor.name
	};
};

DslDomain.prototype.getByToken = function(token) {
	return this.modelRegistry[token];
};

DslDomain.prototype.getAll = function() {
	return this.modelRegistry;
};

var compareCollectionWeight = function(a, b) {
	var aw = a.getWeight();
	var bw = b.getWeight();
	if (aw < bw) {
		return -1;
	}
	if (aw > bw) {
		return 1;
	}
	return 0;
};

DslDomain.prototype.getCollectionModels = function() {
	var models = [];

	for (var id in this.modelRegistry) {
		if (this.modelRegistry.hasOwnProperty(id)) {
			models.push(this.modelRegistry[id]);
		}
	}
	models.sort(compareCollectionWeight);

	return models;
};

module.exports = DslDomain;
<commit_msg>Move method in CollectionEngine<commit_after>/*
* Name : DslDomain.js
* Module : Back-end::Lib::Model::DSLModel
* Location : /lib/model/dslmodel/
*
* History :
*
* Version         Date           Programmer
* =================================================
* 0.0.1          2016-05-30     Davide Polonio
* -------------------------------------------------
* Corretto typo. Trovato errore in `new Engine()`
* =================================================
* 0.0.1          2016-05-11     Andrea Mantovani
* -------------------------------------------------
* Rimosso metodo init
* Rinominato metodo DslLoadFile in DslLoad
* =================================================
* 0.0.1          2014-03-01     Federico Poli
* -------------------------------------------------
* Codifica modulo
* =================================================
*/

"use strict";

var DslConcreteStrategy = require("./DslConcreteStrategy");
var MaapError = require("../utils/MaapError.js");

var _prefix = "_id";

var DslDomain = function() {
    this.modelRegistry = {};
    this.strategy = new DslConcreteStrategy();
    this.id = 0;
};

DslDomain.prototype.loadDSL = function(data, callback) {
    var self = this;
    self.strategy.loadDSL(data, function(models) {
		var ids = []

		models.forEach(function(model) {
			ids.push(self.register(model));
		});

		callback(undefined, ids);

    }, function(maaperror) {
		callback(maaperror, undefined);
    });
};

DslDomain.prototype.register = function(model) {
    var idc = `${_prefix}${this.id++}`;
    this.modelRegistry[idc] = model;

    return {
		token: idc,
		type: model.constructor.name
	};
};

DslDomain.prototype.getByToken = function(token) {
	return this.modelRegistry[token];
};

DslDomain.prototype.getAll = function() {
	return this.modelRegistry;
};

module.exports = DslDomain;
<|endoftext|>


<commit_before>var _curry2 = require('./internal/_curry2');

/**
 * Takes two arguments, `fst` and `snd`, and returns `[fst, snd]`.
 *
 * @func
 * @memberOf R
 * @since v0.18.0
 * @category List
 * @sig a -> b -> (a,b)
 * @param {*} fst
 * @param {*} snd
 * @return {Array}
 * @see R.createMapEntry, R.of
 * @example
 *
 *      R.pair('foo', 'bar'); //=> ['foo', 'bar']
 */
module.exports = _curry2(function pair(fst, snd) { return [fst, snd]; });
<commit_msg>Remove reference to createMapEntry in docs<commit_after>var _curry2 = require('./internal/_curry2');

/**
 * Takes two arguments, `fst` and `snd`, and returns `[fst, snd]`.
 *
 * @func
 * @memberOf R
 * @since v0.18.0
 * @category List
 * @sig a -> b -> (a,b)
 * @param {*} fst
 * @param {*} snd
 * @return {Array}
 * @see R.objOf, R.of
 * @example
 *
 *      R.pair('foo', 'bar'); //=> ['foo', 'bar']
 */
module.exports = _curry2(function pair(fst, snd) { return [fst, snd]; });
<|endoftext|>


<commit_before>// ==UserScript==
// @name           Trellonest
// @description    This extension enables nested boards in Trello
// @include        https://trello.com/*
// @version        1.0
// ==/UserScript==

(function ($) {
  var trelloAPI = "https://trello.com/1/";

  function getLoginToken() {
    var token = document.cookie.match(/token=(.*?)(;|$)/);
    return (token && unescape(token[1])) || null;
  }

  function getBoard(cb) {
    var boardMatch = window.location.pathname.match(/^\/b\/(.*?)(\/|$)/);
    if (boardMatch) {
      var board = boardMatch && boardMatch[1];
      if (board) {
        $.get(trelloAPI + "boards/" + board + "?fields=id")
          .done(function (resp) {
            boardCache = resp.id;
            cb(null, resp.id);
          })
          .fail(function (xhr, status, err) {
            cb(err);
          });
      } else {
        cb(null, null);
      }
    } else {
      var cardMatch = window.location.pathname.match(/^\/c\/(.*?)(\/|$)/);
      if (cardMatch) {
        var card = cardMatch && cardMatch[1];

        $.get(trelloAPI + "cards/" + card + "?fields=idBoard")
          .done(function (resp) {
            boardCache = resp.idBoard;
            cb(null, resp.idBoard);
          })
          .fail(function (xhr, status, err) {
            cb(err);
          });
      } else {
        cb(new Error("Unsupported trello page"));
      }
    }
  }

  function getActiveCard() {
    var cardMatch = window.location.pathname.match(/^\/c\/(.*?)(\/|$)/);
    if (!cardMatch) return null;
    var card = cardMatch && cardMatch[1];
    return card || null;
  }

  var currentSocket;
  function establishSocket() {
    var token = getLoginToken();

    getBoard(function (err, boardId) {
      if (currentSocket) {
        currentSocket.close();
        currentSocket = null;
      }

      var reqId = 0;
      var socket = new WebSocket("wss://trello.com/1/Session/socket?token=" + token);
      currentSocket = socket;
      socket.onopen = function () {
        socket.send(JSON.stringify({ type: "ping", reqid: reqId++ }));
        socket.send(JSON.stringify({ type: "subscribe", modelType: "Board", idModel: boardId, tags: ["clientActions", "updates"], invitationTokens: [], reqid: reqId++ }));
      };

      socket.onmessage = function (msg) {
        if (!msg.data) return;

        var data = JSON.parse(msg.data);
        if (!data.notify || data.notify.typeName !== "Card" || data.notify.event !== "updateModels") return;

        var deltas = {};
        for (var i = 0; i < data.notify.deltas.length; ++i) {
          if (data.notify.deltas[i].desc !== undefined) {
            deltas[data.notify.deltas[i].id] = data.notify.deltas[i].desc;
          }
        }

        var keys = Object.keys(boardCards);
        for (var i = 0; i < keys.length; ++i) {
          if (deltas[boardCards[keys[i]].id] !== undefined) {
            boardCards[keys[i]].desc = deltas[boardCards[keys[i]].id];
          }
        }
      };
    });
  }

  function linkCardToBoard(cardId, targetBoard, cb) {
    var oldDesc = boardCards[cardId].desc;
    var newDesc = oldDesc ? oldDesc.replace(/\[\/\/\]:\s*#board\s*\((.*?)\)/, "[//]:#board(" + targetBoard + ")") : "[//]:#board(" + targetBoard + ")";

    if (oldDesc === newDesc) {
      newDesc += "\r\n\r\n[//]:#board(" + targetBoard + ")";
    }

    $.ajax({
      type: "PUT",
      url: trelloAPI + "cards/" + cardId,
      data: {
        desc: newDesc,
        token: getLoginToken(),
        invitationTokens: []
      }
    }).done(function () {
      if (!cb) return;
      cb(null);
    }).fail(function (xhr, _, err) {
      if (!cb) return;
      cb(err);
    });
  }

  function addLinkButton(buttonContainer) {
    var linkBtn = $('  Link board ');
    buttonContainer.append(linkBtn);

    linkBtn.on("click", function () {
      var card = getActiveCard();
      if (!card) return alert("Could not parse card id");

      var target = prompt("Please provide the target board id");
      if (target === null) return;

      linkCardToBoard(card, target);
    });
  }

  function addCreateButton(buttonContainer) {
    var createBtn = $('  Create board ');
    buttonContainer.append(createBtn);

    createBtn.on("click", function () {
      var cardId = getActiveCard();
      if (!cardId) return alert("Could not parse card id");

      var card = boardCards[cardId];
      $.post(trelloAPI + "boards?fields=url", { name: card.name, desc: card.desc, token: getLoginToken() }, function (e) {
        var card = getActiveCard();
        linkCardToBoard(card, e.url.match(/\/b\/(.*?)(\/|$)/)[1], function (err) {
          if (err) alert("Failed to link card to the new board, please retry linking it later!");

          window.open(e.url);
        });
      });
    });
  }

  function addButtons() {
    var objects = $(".card-detail-window .window-module.other-actions div:last-child");
    if (!objects.length) return setTimeout(addButtons, 1000);

    if ($(".js-link-board-card", objects).length === 0) {
      addLinkButton(objects);
    }
    if ($(".js-create-board-card", objects).length === 0) {
      addCreateButton(objects);
    }
  }

  var refreshingCards = false;
  var boardCards = null;
  function refreshCards() {
    if (refreshingCards) return;

    refreshingCards = true;
    getBoard(function (err, id) {
      if (err) {
        refreshingCards = false;
        return;
      }

      $.get(trelloAPI + "boards/" + id + "/cards?fields=id,name,desc,shortLink", function (cards) {
        boardCards = {};
        for (var i = 0; i < cards.length; ++i) {
          boardCards[cards[i].shortLink] = cards[i];
        }
      }).always(function () {
        refreshingCards = false;
      });
    });
  }

  function getBoardFromCard(card) {
    if (!boardCards) {
      refreshCards();
      establishSocket();
      return null;
    }

    var href = $(".list-card-title", card).attr("href");
    if (!href) return null;

    var cardId = href.match(/^\/c\/(.*?)(\/|$)/)[1];
    var cardData = boardCards[cardId];
    if (!cardData) {
      refreshCards();
      establishSocket();
      return null;
    }

    var match = cardData.desc && cardData.desc.match(/\[\/\/\]:\s*#board\s*\((.*?)\)/);
    return (match && match[1]) || null;
  }

  refreshCards();
  establishSocket();
  addButtons();

  var ignoreEvent = false;
  document.addEventListener("click", function (e) {
    if (ignoreEvent) return;

    var $target = $(e.target);
    var card = $target.parents(".list-card");
    if (card.length === 0) return;

    addButtons();

    var board = getBoardFromCard(card);
    if (!board) return;

    if ($target.is('.icon-edit') || $target.parents(".icon-edit").length) {

      ignoreEvent = true;
      $target.parents(".list-card").trigger('click');
      ignoreEvent = false;
    } else {
      window.location.href = "/b/" + board;
    }

    e.preventDefault();
    e.stopImmediatePropagation();
  }, true); // have to set useCapture because trello stops bubbling

  $(document).on("mouseenter", "#board .list-card", function () {
    var card = this;

    var board = getBoardFromCard(card);
    var penIcon = $(".icon-edit", this);

    if (board && !penIcon.next().is(".icon-card")) {
      var cardIcon = penIcon.clone()
        .removeClass("icon-edit")
        .addClass("icon-card")
        .css("top", "25px");

      penIcon.after(cardIcon);
    } else if (!board && penIcon.next().is(".icon-card")) {
      penIcon.next().remove();
    }
  });
})(jQuery);
<commit_msg>Fix redirect to the target board<commit_after>// ==UserScript==
// @name           Trellonest
// @description    This extension enables nested boards in Trello
// @include        https://trello.com/*
// @version        1.0
// ==/UserScript==

(function ($) {
  var trelloAPI = "https://trello.com/1/";

  function getLoginToken() {
    var token = document.cookie.match(/token=(.*?)(;|$)/);
    return (token && unescape(token[1])) || null;
  }

  function getBoard(cb) {
    var boardMatch = window.location.pathname.match(/^\/b\/(.*?)(\/|$)/);
    if (boardMatch) {
      var board = boardMatch && boardMatch[1];
      if (board) {
        $.get(trelloAPI + "boards/" + board + "?fields=id")
          .done(function (resp) {
            boardCache = resp.id;
            cb(null, resp.id);
          })
          .fail(function (xhr, status, err) {
            cb(err);
          });
      } else {
        cb(null, null);
      }
    } else {
      var cardMatch = window.location.pathname.match(/^\/c\/(.*?)(\/|$)/);
      if (cardMatch) {
        var card = cardMatch && cardMatch[1];

        $.get(trelloAPI + "cards/" + card + "?fields=idBoard")
          .done(function (resp) {
            boardCache = resp.idBoard;
            cb(null, resp.idBoard);
          })
          .fail(function (xhr, status, err) {
            cb(err);
          });
      } else {
        cb(new Error("Unsupported trello page"));
      }
    }
  }

  function getActiveCard() {
    var cardMatch = window.location.pathname.match(/^\/c\/(.*?)(\/|$)/);
    if (!cardMatch) return null;
    var card = cardMatch && cardMatch[1];
    return card || null;
  }

  var currentSocket;
  function establishSocket() {
    var token = getLoginToken();

    getBoard(function (err, boardId) {
      if (currentSocket) {
        currentSocket.close();
        currentSocket = null;
      }

      var reqId = 0;
      var socket = new WebSocket("wss://trello.com/1/Session/socket?token=" + token);
      currentSocket = socket;
      socket.onopen = function () {
        socket.send(JSON.stringify({ type: "ping", reqid: reqId++ }));
        socket.send(JSON.stringify({ type: "subscribe", modelType: "Board", idModel: boardId, tags: ["clientActions", "updates"], invitationTokens: [], reqid: reqId++ }));
      };

      socket.onmessage = function (msg) {
        if (!msg.data) return;

        var data = JSON.parse(msg.data);
        if (!data.notify || data.notify.typeName !== "Card" || data.notify.event !== "updateModels") return;

        var deltas = {};
        for (var i = 0; i < data.notify.deltas.length; ++i) {
          if (data.notify.deltas[i].desc !== undefined) {
            deltas[data.notify.deltas[i].id] = data.notify.deltas[i].desc;
          }
        }

        var keys = Object.keys(boardCards);
        for (var i = 0; i < keys.length; ++i) {
          if (deltas[boardCards[keys[i]].id] !== undefined) {
            boardCards[keys[i]].desc = deltas[boardCards[keys[i]].id];
          }
        }
      };
    });
  }

  function linkCardToBoard(cardId, targetBoard, cb) {
    var oldDesc = boardCards[cardId].desc;
    var newDesc = oldDesc ? oldDesc.replace(/\[\/\/\]:\s*#board\s*\((.*?)\)/, "[//]:#board(" + targetBoard + ")") : "[//]:#board(" + targetBoard + ")";

    if (oldDesc === newDesc) {
      newDesc += "\r\n\r\n[//]:#board(" + targetBoard + ")";
    }

    $.ajax({
      type: "PUT",
      url: trelloAPI + "cards/" + cardId,
      data: {
        desc: newDesc,
        token: getLoginToken(),
        invitationTokens: []
      }
    }).done(function () {
      if (!cb) return;
      cb(null);
    }).fail(function (xhr, _, err) {
      if (!cb) return;
      cb(err);
    });
  }

  function addLinkButton(buttonContainer) {
    var linkBtn = $('  Link board ');
    buttonContainer.append(linkBtn);

    linkBtn.on("click", function () {
      var card = getActiveCard();
      if (!card) return alert("Could not parse card id");

      var target = prompt("Please provide the target board id");
      if (target === null) return;

      linkCardToBoard(card, target);
    });
  }

  function addCreateButton(buttonContainer) {
    var createBtn = $('  Create board ');
    buttonContainer.append(createBtn);

    createBtn.on("click", function () {
      var cardId = getActiveCard();
      if (!cardId) return alert("Could not parse card id");

      var card = boardCards[cardId];
      $.post(trelloAPI + "boards?fields=url", { name: card.name, desc: card.desc, token: getLoginToken() }, function (e) {
        var card = getActiveCard();
        linkCardToBoard(card, e.url.match(/\/b\/(.*?)(\/|$)/)[1], function (err) {
          if (err) alert("Failed to link card to the new board, please retry linking it later!");

          window.open(e.url);
        });
      });
    });
  }

  function addButtons() {
    var objects = $(".card-detail-window .window-module.other-actions div:last-child");
    if (!objects.length) return setTimeout(addButtons, 1000);

    if ($(".js-link-board-card", objects).length === 0) {
      addLinkButton(objects);
    }
    if ($(".js-create-board-card", objects).length === 0) {
      addCreateButton(objects);
    }
  }

  var refreshingCards = false;
  var boardCards = null;
  function refreshCards() {
    if (refreshingCards) return;

    refreshingCards = true;
    getBoard(function (err, id) {
      if (err) {
        refreshingCards = false;
        return;
      }

      $.get(trelloAPI + "boards/" + id + "/cards?fields=id,name,desc,shortLink", function (cards) {
        boardCards = {};
        for (var i = 0; i < cards.length; ++i) {
          boardCards[cards[i].shortLink] = cards[i];
        }
      }).always(function () {
        refreshingCards = false;
      });
    });
  }

  function getBoardFromCard(card) {
    if (!boardCards) {
      refreshCards();
      establishSocket();
      return null;
    }

    var href = $(".list-card-title", card).attr("href");
    if (!href) return null;

    var cardId = href.match(/^\/c\/(.*?)(\/|$)/)[1];
    var cardData = boardCards[cardId];
    if (!cardData) {
      refreshCards();
      establishSocket();
      return null;
    }

    var match = cardData.desc && cardData.desc.match(/\[\/\/\]:\s*#board\s*\((.*?)\)/);
    return (match && match[1]) || null;
  }

  refreshCards();
  establishSocket();
  addButtons();

  var ignoreEvent = false;
  document.addEventListener("click", function (e) {
    if (ignoreEvent) return;

    var $target = $(e.target);
    var card = $target.parents(".list-card");
    if (card.length === 0) return;

    addButtons();

    var board = getBoardFromCard(card);
    if (!board) return;

    if ($target.is('.icon-edit') || $target.parents(".icon-edit").length) {

      ignoreEvent = true;
      $target.parents(".list-card").trigger('click');
      ignoreEvent = false;
    } else {
      $.get(trelloAPI + "boards/" + board + "?fields=url")
        .done(function (resp) {
          window.location.href = resp.url;
        })
        .fail(function (xhr, status, err) {
          alert("Can't find target board. The link might be broken or you might not have access to it.");
        });
    }

    e.preventDefault();
    e.stopImmediatePropagation();
  }, true); // have to set useCapture because trello stops bubbling

  $(document).on("mouseenter", "#board .list-card", function () {
    var card = this;

    var board = getBoardFromCard(card);
    var penIcon = $(".icon-edit", this);

    if (board && !penIcon.next().is(".icon-card")) {
      var cardIcon = penIcon.clone()
        .removeClass("icon-edit")
        .addClass("icon-card")
        .css("top", "25px");

      penIcon.after(cardIcon);
    } else if (!board && penIcon.next().is(".icon-card")) {
      penIcon.next().remove();
    }
  });
})(jQuery);
<|endoftext|>


<commit_before>const db = require('./db');

const getAllBooks = () => {
  return db.query(`SELECT * FROM books`)
    .catch(error => console.error(error));
};

const getAllBookImagesId = () => {
  return db.query(`SELECT id, img_url FROM books`)
    .catch(error => console.error(error));
};

const getOneBook = bookID => {
  return db.query(`SELECT title, price, img_url, in_stock, isbn, publisher, first_name, last_name,
  string_agg(genres.name, ', ') AS genres FROM books
  JOIN authors_books ON books.id = authors_books.book_id
  JOIN authors ON authors.id = authors_books.author_id
  JOIN genres_books ON books.id = genres_books.book_id
  JOIN genres ON genres.id = genres_books.genre_id
  WHERE books.id = $1
  GROUP BY title, price, img_url, in_stock, isbn, publisher, first_name, last_name`,
  [bookID])
  .then(book => book[0])
  .catch(error => console.error(error));
};

const searchForBooks = (searchQuery, offSet) => {
  return db.query(`SELECT books.id, title, price, img_url, first_name, last_name FROM books
    JOIN authors_books ON books.id = authors_books.book_id
    JOIN authors ON authors.id = authors_books.author_id
    JOIN genres_books ON books.id = genres_books.book_id
    JOIN genres ON genres.id = genres_books.genre_id
    WHERE LOWER(title) LIKE $1
    OR LOWER(first_name) LIKE $1
    OR LOWER(last_name) LIKE $1
    OR LOWER(name) LIKE $1
    GROUP BY books.id, title, price, img_url, first_name, last_name
    OFFSET $2 LIMIT 10`, [searchQuery, offSet])
    .catch(error => console.error(error));
};

const updateBookGenres = (newGenreName, bookId, oldGenreName) => {
  return db.tx(transaction => {
    return transaction.oneOrNone('SELECT id FROM genres WHERE LOWER(name) = LOWER($1)', [newGenreName])
      .then(genreId => {
        if (!genreId) {
          return transaction.query(`
              INSERT INTO genres (name) VALUES ($1) RETURNING id
               `, [newGenreName])
               .then(ids => {
                return transaction.query(`
                 UPDATE genres_books SET genre_id = $1
                 WHERE genres_books.book_id = $2
                 AND genres_books.genre_id = (SELECT id FROM genres WHERE name = $3);
                 `, [ids[0].id, bookId, oldGenreName]);
              })
               .catch(console.error);
        } else {
          return transaction.query(`
            UPDATE genres_books SET genre_id = (SELECT id FROM genres WHERE LOWER(name) = LOWER($1))
	          WHERE genres_books.book_id = $2
	          AND genres_books.genre_id = (SELECT id FROM genres WHERE name = $3);
            `, [newGenreName, bookId, oldGenreName]);
        }
      })
      .catch(error => {
        console.error({ message: 'UpdateBookGenres Inner Transaction failed',
                        arguments: arguments, });
        throw error;
      });
  })
  .catch(error => {
    console.error({ message: 'UpdateBookGenres Outer Transaction failed',
                    arguments: arguments, });
    throw error;
  });
}

const updateBookAuthors = (newAuthorFirst, newAuthorLast, bookId, oldAuthorFirst, oldAuthorLast) => {
  return db.tx(transaction => {
    return transaction.oneOrNone(`SELECT id FROM authors
      WHERE LOWER(first_name) = LOWER($1)
      AND LOWER(last_name) = LOWER($2)
      `, [newAuthorFirst, newAuthorLast])
      .then(authorId => {
        if (!authorId) {
          return transaction.query(`
              INSERT INTO authors (first_name, last_name) VALUES ($1, $2) RETURNING id
               `, [newAuthorFirst, newAuthorLast])
               .then(ids => {
                return transaction.query(`
                 UPDATE authors_books SET author_id = $1
                 WHERE authors_books.book_id = $2
                 AND authors_books.author_id = (SELECT id FROM genres WHERE first_name = $3
                 AND last_name = $4);
                 `, [ids[0].id, bookId, oldAuthorFirst, oldAuthorLast]);
              })
               .catch(console.error);
        } else {
          return transaction.query(`
            UPDATE authors_books SET author_id = (SELECT id FROM authors
            WHERE LOWER(first_name) = LOWER($1)
            AND LOWER(last_name) = LOWER($2))
            WHERE authors_books.book_id = $3
            AND authors_books.author_id = (SELECT id FROM genres WHERE first_name = $4
            AND last_name = $5);
            `, [newAuthorFirst, newAuthorLast, bookId, oldAuthorFirst, oldAuthorLast]);
        }
      })
      .catch(error => {
        console.error({ message: 'UpdateBookGenres Inner Transaction failed',
                        arguments: arguments, });
        throw error;
      });
  })
  .catch(error => {
    console.error({ message: 'UpdateBookGenres Outer Transaction failed',
                    arguments: arguments, });
    throw error;
  });
};

const updateBooks = (bookId, bookTitle, bookImg, bookPrice, inStock, isbn, publisher) => {
  return db.query(`
    UPDATE books SET title = $2, img_url = $3, price = $4,
    in_stock = $5, isbn = $6, publisher = $7
    WHERE id = $1
    `, [bookId, bookTitle, bookImg, bookPrice, inStock, isbn, publisher])
    .catch(error => console.error(error));
};

module.exports = {
  getAllBooks,
  getOneBook,
  getAllBookImagesId,
  searchForBooks,
  updateBookGenres,
  updateBookAuthors,
  updateBooks,
};
<commit_msg>Fixed typo in updateBookAuthor, pointing to the correct table now<commit_after>const db = require('./db');

const getAllBooks = () => {
  return db.query(`SELECT * FROM books`)
    .catch(error => console.error(error));
};

const getAllBookImagesId = () => {
  return db.query(`SELECT id, img_url FROM books`)
    .catch(error => console.error(error));
};

const getOneBook = bookID => {
  return db.query(`SELECT title, price, img_url, in_stock, isbn, publisher, first_name, last_name,
  string_agg(genres.name, ', ') AS genres FROM books
  JOIN authors_books ON books.id = authors_books.book_id
  JOIN authors ON authors.id = authors_books.author_id
  JOIN genres_books ON books.id = genres_books.book_id
  JOIN genres ON genres.id = genres_books.genre_id
  WHERE books.id = $1
  GROUP BY title, price, img_url, in_stock, isbn, publisher, first_name, last_name`,
  [bookID])
  .then(book => book[0])
  .catch(error => console.error(error));
};

const searchForBooks = (searchQuery, offSet) => {
  return db.query(`SELECT books.id, title, price, img_url, first_name, last_name FROM books
    JOIN authors_books ON books.id = authors_books.book_id
    JOIN authors ON authors.id = authors_books.author_id
    JOIN genres_books ON books.id = genres_books.book_id
    JOIN genres ON genres.id = genres_books.genre_id
    WHERE LOWER(title) LIKE $1
    OR LOWER(first_name) LIKE $1
    OR LOWER(last_name) LIKE $1
    OR LOWER(name) LIKE $1
    GROUP BY books.id, title, price, img_url, first_name, last_name
    OFFSET $2 LIMIT 10`, [searchQuery, offSet])
    .catch(error => console.error(error));
};

const updateBookGenre = (newGenreName, bookId, oldGenreName) => {
  return db.tx(transaction => {
    return transaction.oneOrNone('SELECT id FROM genres WHERE LOWER(name) = LOWER($1)', [newGenreName])
      .then(genreId => {
        if (!genreId) {
          return transaction.query(`
              INSERT INTO genres (name) VALUES ($1) RETURNING id
               `, [newGenreName])
               .then(ids => {
                return transaction.query(`
                 UPDATE genres_books SET genre_id = $1
                 WHERE genres_books.book_id = $2
                 AND genres_books.genre_id = (SELECT id FROM genres WHERE name = $3);
                 `, [ids[0].id, bookId, oldGenreName]);
              })
               .catch(console.error);
        } else {
          return transaction.query(`
            UPDATE genres_books SET genre_id = (SELECT id FROM genres WHERE LOWER(name) = LOWER($1))
	          WHERE genres_books.book_id = $2
	          AND genres_books.genre_id = (SELECT id FROM genres WHERE name = $3);
            `, [newGenreName, bookId, oldGenreName]);
        }
      })
      .catch(error => {
        console.error({ message: 'UpdateBookGenres Inner Transaction failed',
                        arguments: arguments, });
        throw error;
      });
  })
  .catch(error => {
    console.error({ message: 'UpdateBookGenres Outer Transaction failed',
                    arguments: arguments, });
    throw error;
  });
}

const updateBookAuthor = (newAuthorFirst, newAuthorLast, bookId, oldAuthorFirst, oldAuthorLast) => {
  return db.tx(transaction => {
    return transaction.oneOrNone(`SELECT id FROM authors
      WHERE LOWER(first_name) = LOWER($1)
      AND LOWER(last_name) = LOWER($2)
      `, [newAuthorFirst, newAuthorLast])
      .then(authorId => {
        if (!authorId) {
          return transaction.query(`
              INSERT INTO authors (first_name, last_name) VALUES ($1, $2) RETURNING id
               `, [newAuthorFirst, newAuthorLast])
               .then(ids => {
                return transaction.query(`
                 UPDATE authors_books SET author_id = $1
                 WHERE authors_books.book_id = $2
                 AND authors_books.author_id = (SELECT id FROM authors WHERE first_name = $3
                 AND last_name = $4);
                 `, [ids[0].id, bookId, oldAuthorFirst, oldAuthorLast]);
              })
               .catch(console.error);
        } else {
          return transaction.query(`
            UPDATE authors_books SET author_id = (SELECT id FROM authors
            WHERE LOWER(first_name) = LOWER($1)
            AND LOWER(last_name) = LOWER($2))
            WHERE authors_books.book_id = $3
            AND authors_books.author_id = (SELECT id FROM authors WHERE first_name = $4
            AND last_name = $5);
            `, [newAuthorFirst, newAuthorLast, bookId, oldAuthorFirst, oldAuthorLast]);
        }
      })
      .catch(error => {
        console.error({ message: 'UpdateBookGenres Inner Transaction failed',
                        arguments: arguments, });
        throw error;
      });
  })
  .catch(error => {
    console.error({ message: 'UpdateBookGenres Outer Transaction failed',
                    arguments: arguments, });
    throw error;
  });
};

const updateBooks = (bookId, bookTitle, bookImg, bookPrice, inStock, isbn, publisher) => {
  return db.query(`
    UPDATE books SET title = $2, img_url = $3, price = $4,
    in_stock = $5, isbn = $6, publisher = $7
    WHERE id = $1
    `, [bookId, bookTitle, bookImg, bookPrice, inStock, isbn, publisher])
    .catch(error => console.error(error));
};

module.exports = {
  getAllBooks,
  getOneBook,
  getAllBookImagesId,
  searchForBooks,
  updateBookGenres,
  updateBookAuthor,
  updateBook,
};
<|endoftext|>


<commit_before>import * as utils from "base/utils";
import DataConnected from "models/dataconnected";

/*!
 * VIZABI Entities Model
 */

const EntitiesModel = DataConnected.extend({

  /**
   * Default values for this model
   */
  getClassDefaults() {
    const defaults = {
      show: {},
      showFallback: {},
      showItemsMaxCount: null,
      filter: {},
      dim: null,
      skipFilter: false
    };
    return utils.deepExtend(this._super(), defaults);
  },

  objectLeafs: ["show", "showFallback", "filter", "autoconfig"],
  dataConnectedChildren: ["show", "dim", "grouping"],

  /**
   * Initializes the entities model.
   * @param {Object} values The initial values of this model
   * @param parent A reference to the parent model
   * @param {Object} bind Initial events to bind
   */
  init(name, values, parent, bind) {

    this._type = "entities";

    this._super(name, values, parent, bind);
  },

  preloadData() {
    this.dataSource = this.getClosestModel(this.data || "data");
    return this._super();
  },

  afterPreload() {
    this.autoconfigureModel();
  },

  setLinkWith(model) {
  },

  autoconfigureModel() {
    if (!this.dim && this.autoconfig) {
      const concept = this.dataSource.getConcept(this.autoconfig);

      if (concept) this.dim = concept.concept;
      utils.printAutoconfigResult(this);
    }
  },

  setInterModelListeners() {
    this.getClosestModel("locale").on("dataConnectedChange", this.handleDataConnectedChange.bind(this));
  },

  validate() {
    this._super();
    if (!this.showFallback[this.dim] && !this.showItemsMaxCount) return;

    const dimShowFilter = this.show[this.dim] || (this.show.$and && this.show.$and.filter(f => f[this.dim])[0]);
    if (!dimShowFilter) {
      if (this.showFallback[this.dim]) {
        this.show = { [this.dim]: utils.deepClone(this.showFallback[this.dim]) };
      }
    } else if (dimShowFilter.$in && this.showItemsMaxCount && dimShowFilter.$in.length > this.showItemsMaxCount) {
      dimShowFilter.$in.splice(0, dimShowFilter.$in.length - this.showItemsMaxCount);
      this.show = utils.deepClone(this.show);
    }
  },

  handleDataConnectedChange(evt) {
    //defer is necessary because other events might be queued.
    //load right after such events
    utils.defer(() => {
      this.startLoading()
        .catch(utils.warn);
    });
  },

  _isLoading() {
    return (!this._loadedOnce || this._loadCall);
  },

  loadData() {
    this.setReady(false);
    this._loadCall = true;

    const _this = this;

    if (!this.dim) {
      this._entitySets = {};
      this._entitySetsData = {};
      this._entitySetsValues = {};
      return Promise.resolve();
    }

    const dim = this.dim;
    this._entitySets = { [dim]: this._root.dataManager.getAvailableDataForKey(dim, null)
      .filter(d => d.value !== dim && ["entity_set", "entity_domain"].includes(this._root.dataManager.getConceptProperty(d.value, "concept_type")))
      .map(d => d.value) };

    if (!this._entitySets[dim].length) {
      this._entitySetsValues = { [dim]: [] };
      this._entitySetsData = { [dim]: {} };
      return Promise.resolve();
    }

    const queryAddition = { "language": this.getClosestModel("locale").id };
    const loadPromises = [this._root.dataManager.getDimensionValues(dim, this._entitySets[dim], queryAddition)]
      .concat(this._entitySets[dim].map(entitySetName => this._root.dataManager.getDimensionValues(entitySetName, ["name"], queryAddition)));

    return Promise.all(loadPromises).then(data => {
      _this._entitySetsValues = { [dim]: data[0] };
      _this._entitySetsData = { [dim]: {} };
      _this._entitySets[dim].forEach((key, index) => {
        _this._entitySetsData[dim][key] = data[index + 1];
      });
    });
  },

  getEntitySets(type = "") {
    return this["_entitySets" + utils.capitalize(type)][this.dim];
  },
  /**
   * Gets the dimensions in this entities
   * @returns {String} String with dimension
   */
  getDimension() {
    return this.dim;
  },

  setDimension(dim) {
    if (this.dim === dim) return;
    const props = {};
    props.show = {};
    props.dim = dim;
    this.set(props);
  },
  /**
   * Gets the filter in this entities
   * @returns {Array} Array of unique values
   */
  getFilter({ entityTypeRequest } = {}) {
    const filter = utils.deepClone(this.filter[this.dim] || {});
    if (entityTypeRequest || this.skipFilter) return filter;

    const show = utils.deepClone(this.show);
    if (show[this.dim] && utils.isEmpty(show[this.dim])) {
      delete show[this.dim];
    }

    const $and = [];
    if (!utils.isEmpty(filter)) $and.push(filter);
    if (!utils.isEmpty(show)) $and.push(show);
    if ($and.length > 1) {
      return { $and };
    }

    return $and[0] || {};
  },

  /**
   * Shows or unshows an entity from the set
   */
  showEntity(d) {
    //clear selected countries when showing something new
    const newShow = utils.deepClone(this.show);
    const dimension = this.getDimension();
    let _d;

    if (!utils.isArray(d)) {
      _d = [d];
    } else {
      _d = d;
    }

    const showFilter = newShow[dimension] || (newShow.$and || []).filter(f => f[dimension])[0] || { $in: [] };

    utils.forEach(_d, d => {
      const value = d[dimension];
      if (this.isShown(d)) {
        showFilter["$in"] = showFilter["$in"].filter(d => d !== value);
      } else {
        showFilter["$in"] = showFilter["$in"].concat(value);
      }
    });

    if (showFilter["$in"].length === 0) {
      if (newShow.$and) {
        newShow.$and = newShow.$and.filter(f => !f[dimension]);
      } else {
        delete newShow[dimension];
      }
    } else {
      if (newShow.$and) {
        newShow.$and.push({ [dimension]: showFilter });
      } else {
        newShow[dimension] = showFilter;
      }
    }

    this.show = newShow;
  },

  /**
   * Selects an entity from the set
   * @returns {Boolean} whether the item is shown or not
   */
  isShown(d) {
    const dimension = this.getDimension();

    const { $in = [] } = this.show[dimension] || (this.show.$and || []).filter(f => f[dimension])[0] || {};

    return $in.includes(d[dimension]);
  },

  isInShowFilter(d, category) {
    const dim = this.getDimension();
    const key = d[dim];
    const filter = (this.show.$and || [this.show]).filter(f => f[category])[0] || {};

    return utils.getProp(filter, [category, "$in"], []).includes(d[category]);
  },

  /**
   * Clears showing of items
   */
  clearShow() {
    const dimension = this.getDimension();
    const show = utils.deepClone(this.show);
    delete show[dimension];
    this.show = show;
  },

  getFilteredEntities() {
    const dimension = this.getDimension();
    const { $in = [] } = this.show[dimension] || {};

    return $in.map(m => ({ [dimension]: m }));
  },

  isEntities() {
    return true;
  }

});

export default EntitiesModel;
<commit_msg>join entity values from every datasource and filter them for unique values<commit_after>import * as utils from "base/utils";
import DataConnected from "models/dataconnected";

/*!
 * VIZABI Entities Model
 */

const EntitiesModel = DataConnected.extend({

  /**
   * Default values for this model
   */
  getClassDefaults() {
    const defaults = {
      show: {},
      showFallback: {},
      showItemsMaxCount: null,
      filter: {},
      dim: null,
      skipFilter: false
    };
    return utils.deepExtend(this._super(), defaults);
  },

  objectLeafs: ["show", "showFallback", "filter", "autoconfig"],
  dataConnectedChildren: ["show", "dim", "grouping"],

  /**
   * Initializes the entities model.
   * @param {Object} values The initial values of this model
   * @param parent A reference to the parent model
   * @param {Object} bind Initial events to bind
   */
  init(name, values, parent, bind) {

    this._type = "entities";

    this._super(name, values, parent, bind);
  },

  preloadData() {
    this.dataSource = this.getClosestModel(this.data || "data");
    return this._super();
  },

  afterPreload() {
    this.autoconfigureModel();
  },

  setLinkWith(model) {
  },

  autoconfigureModel() {
    if (!this.dim && this.autoconfig) {
      const concept = this.dataSource.getConcept(this.autoconfig);

      if (concept) this.dim = concept.concept;
      utils.printAutoconfigResult(this);
    }
  },

  setInterModelListeners() {
    this.getClosestModel("locale").on("dataConnectedChange", this.handleDataConnectedChange.bind(this));
  },

  validate() {
    this._super();
    if (!this.showFallback[this.dim] && !this.showItemsMaxCount) return;

    const dimShowFilter = this.show[this.dim] || (this.show.$and && this.show.$and.filter(f => f[this.dim])[0]);
    if (!dimShowFilter) {
      if (this.showFallback[this.dim]) {
        this.show = { [this.dim]: utils.deepClone(this.showFallback[this.dim]) };
      }
    } else if (dimShowFilter.$in && this.showItemsMaxCount && dimShowFilter.$in.length > this.showItemsMaxCount) {
      dimShowFilter.$in.splice(0, dimShowFilter.$in.length - this.showItemsMaxCount);
      this.show = utils.deepClone(this.show);
    }
  },

  handleDataConnectedChange(evt) {
    //defer is necessary because other events might be queued.
    //load right after such events
    utils.defer(() => {
      this.startLoading()
        .catch(utils.warn);
    });
  },

  _isLoading() {
    return (!this._loadedOnce || this._loadCall);
  },

  loadData() {
    this.setReady(false);
    this._loadCall = true;

    const _this = this;

    if (!this.dim) {
      this._entitySets = {};
      this._entitySetsData = {};
      this._entitySetsValues = {};
      return Promise.resolve();
    }

    const dim = this.dim;
    this._entitySets = { [dim]: utils.unique(this._root.dataManager.getAvailableDataForKey(dim, null)
      .filter(d => d.value !== dim && ["entity_set", "entity_domain"].includes(this._root.dataManager.getConceptProperty(d.value, "concept_type")))
      .map(d => d.value)) };

    if (!this._entitySets[dim].length) {
      this._entitySetsValues = { [dim]: [] };
      this._entitySetsData = { [dim]: {} };
      return Promise.resolve();
    }

    const queryAddition = { "language": this.getClosestModel("locale").id };
    const loadPromises = [this._root.dataManager.getDimensionValues(dim, this._entitySets[dim], queryAddition)]
      .concat(this._entitySets[dim].map(entitySetName => this._root.dataManager.getDimensionValues(entitySetName, ["name"], queryAddition)));

    return Promise.all(loadPromises).then(data => {
      _this._entitySetsValues = { [dim]: data[0].length > 1 ? utils.unique([].concat(data[0]), d => d[dim]) : data[0] };
      _this._entitySetsData = { [dim]: {} };
      _this._entitySets[dim].forEach((key, index) => {
        _this._entitySetsData[dim][key] = data[index + 1].length > 1 ? utils.unique([].concat(data[index + 1]), d => d[key]) : data[index + 1];
      });
    });
  },

  getEntitySets(type = "") {
    return this["_entitySets" + utils.capitalize(type)][this.dim];
  },
  /**
   * Gets the dimensions in this entities
   * @returns {String} String with dimension
   */
  getDimension() {
    return this.dim;
  },

  setDimension(dim) {
    if (this.dim === dim) return;
    const props = {};
    props.show = {};
    props.dim = dim;
    this.set(props);
  },
  /**
   * Gets the filter in this entities
   * @returns {Array} Array of unique values
   */
  getFilter({ entityTypeRequest } = {}) {
    const filter = utils.deepClone(this.filter[this.dim] || {});
    if (entityTypeRequest || this.skipFilter) return filter;

    const show = utils.deepClone(this.show);
    if (show[this.dim] && utils.isEmpty(show[this.dim])) {
      delete show[this.dim];
    }

    const $and = [];
    if (!utils.isEmpty(filter)) $and.push(filter);
    if (!utils.isEmpty(show)) $and.push(show);
    if ($and.length > 1) {
      return { $and };
    }

    return $and[0] || {};
  },

  /**
   * Shows or unshows an entity from the set
   */
  showEntity(d) {
    //clear selected countries when showing something new
    const newShow = utils.deepClone(this.show);
    const dimension = this.getDimension();
    let _d;

    if (!utils.isArray(d)) {
      _d = [d];
    } else {
      _d = d;
    }

    const showFilter = newShow[dimension] || (newShow.$and || []).filter(f => f[dimension])[0] || { $in: [] };

    utils.forEach(_d, d => {
      const value = d[dimension];
      if (this.isShown(d)) {
        showFilter["$in"] = showFilter["$in"].filter(d => d !== value);
      } else {
        showFilter["$in"] = showFilter["$in"].concat(value);
      }
    });

    if (showFilter["$in"].length === 0) {
      if (newShow.$and) {
        newShow.$and = newShow.$and.filter(f => !f[dimension]);
      } else {
        delete newShow[dimension];
      }
    } else {
      if (newShow.$and) {
        newShow.$and.push({ [dimension]: showFilter });
      } else {
        newShow[dimension] = showFilter;
      }
    }

    this.show = newShow;
  },

  /**
   * Selects an entity from the set
   * @returns {Boolean} whether the item is shown or not
   */
  isShown(d) {
    const dimension = this.getDimension();

    const { $in = [] } = this.show[dimension] || (this.show.$and || []).filter(f => f[dimension])[0] || {};

    return $in.includes(d[dimension]);
  },

  isInShowFilter(d, category) {
    const dim = this.getDimension();
    const key = d[dim];
    const filter = (this.show.$and || [this.show]).filter(f => f[category])[0] || {};

    return utils.getProp(filter, [category, "$in"], []).includes(d[category]);
  },

  /**
   * Clears showing of items
   */
  clearShow() {
    const dimension = this.getDimension();
    const show = utils.deepClone(this.show);
    delete show[dimension];
    this.show = show;
  },

  getFilteredEntities() {
    const dimension = this.getDimension();
    const { $in = [] } = this.show[dimension] || {};

    return $in.map(m => ({ [dimension]: m }));
  },

  isEntities() {
    return true;
  }

});

export default EntitiesModel;
<|endoftext|>


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

var promise = require("./promise.js");
var Packaging = require('./packaging.js');
var extractDependencies = require('./extractDependencies.js');
var moduleFunction = require('./moduleFunction.js');
var execCallModule = require('./execCallModule.js');
var Resolver = require('./resolver.js');
var execScripts = require('../node-modules/execScripts.js');
var isArray = require('./type.js').isArray;
var dirname = require('./path.js').dirname;

var bind = function (fn, scope) {
    return function () {
        return fn.apply(scope, arguments);
    };
};

var bind1 = function (fn, scope, paramBind) {
    return function (param) {
        return fn.call(scope, paramBind, param);
    };
};

function Module(context, filename) {
    if (filename) {
        this.dirname = dirname(filename);
    } else {
        filename = '.';
        this.dirname = filename;
    }
    this.filename = filename;
    this.id = filename;
    this.require = bind1(context.require, context, this);
    this.require.resolve = bind1(context.resolve, context, this);
    this.require.cache = context.cache;
    this.parent = null;
    this.children = [];
}

var moduleProto = Module.prototype = {};
moduleProto.preloading = false;
moduleProto.preloaded = false;
moduleProto.loadingDefinition = false;
moduleProto.definition = null;
moduleProto.executing = false;
moduleProto.loaded = false;

module.exports = Module;

var createAsyncRequire = function (context) {
    return function (module) {
        module.exports = {
            create: function (module) {
                return function (id) {
                    return context.asyncRequire(module, id);
                };
            }
        };
    };
};

var start = function (context) {
    var config = context.config;
    var actions = promise.done;

    if (!config.hasOwnProperty('scriptsType')) {
        config.scriptsType = config.varName;
    }
    var scriptsType = config.scriptsType;
    if (scriptsType) {
        actions = actions.then(function () {
            return execScripts(context, scriptsType);
        });
    }

    var main = config.main;
    actions = actions.then(main ?
    function () {
        return execCallModule(context, main);
    } : promise.empty /* if there is no main module, an empty parameter should be passed to onstart */ );

    actions = actions.then(config.onstart);

    return actions.always(function () {
        context = null;
        config = null;
        actions = null;
    });
};

var Context = function (config) {
    this.cache = {};
    var define = bind(this.define, this);
    this.define = define; // allow using define without the scope
    define("asyncRequire.js", [], createAsyncRequire(this));

    config = config || {};
    this.config = config;
    this.resolver = new Resolver(config.resolver);
    this.packaging = new Packaging(config.packaging, this.define);

    var rootModule = new Module(this);
    rootModule.preloaded = true;
    rootModule.loaded = true;
    rootModule.define = define;
    rootModule.asyncRequire = rootModule.require('asyncRequire').create(rootModule);
    this.rootModule = rootModule;

    var globalVarName = config.varName;
    if (globalVarName) {
        global[globalVarName] = rootModule;
    }
    start(this).end();
};

var contextProto = Context.prototype = {};

// Preloading a module means making it ready to be executed (loading its definition and preloading its
// dependencies)
contextProto.preloadModule = function (module, parent) {
    if (module.preloaded) {
        return promise.done;
    }
    if (module.preloading) {
        // If we get here, it may be because of a circular dependency
        // check it here:
        while (parent) {
            if (parent === module) {
                return promise.done;
            }
            parent = parent.parent;
        }
        return module.preloading;
    }
    var self = this;
    if (parent && parent.id != '.') {
        module.parent = parent;
        module.require.main = parent.require.main;
        parent.children.push(module);
    } else {
        module.require.main = module;
    }
    return module.preloading = self.loadDefinition(module).then(function () {
        return self.preloadModules(module, module.definition.dependencies);
    }).then(function () {
        module.preloaded = true;
        module.preloading = false;
    }).always(function () {
        // clean up
        module = null;
        self = null;
    });
};

contextProto.loadDefinition = function (module) {
    if (module.definition) {
        return promise.done;
    }
    var res = module.loadingDefinition;
    if (!res) {
        // store the promise so that it can be resolved when the define method is called:
        module.loadingDefinition = res = promise();
        this.packaging.loadModule(module.filename).then(function () {
            if (res) {
                // if reaching this, and if res is still pending, then it means the module was not found where expected
                res.reject(new Error("Module " + module.filename + " was not found in expected package."));
            }
        }, res.reject);
        res.done(function () {
            res = null;
            module.loadingDefinition = false;
        });
    }
    return res;
};

contextProto.preloadModules = function (module, modules) {
    var promises = [];
    for (var i = 0, l = modules.length; i < l; i++) {
        promises.push(this.preloadModule(this.getModule(this.resolve(module, modules[i])), module));
    }
    return promise.when(promises);
};

contextProto.executePreloadedModule = function (module) {
    if (module.loaded || module.executing) { /* this.executing is true only in the case of a circular dependency */
        return module.exports;
    }
    if (!module.preloaded) {
        throw new Error('A module must be preloaded before executing it.');
    }
    var exports = {};
    module.exports = exports;
    module.executing = true;
    try {
        module.definition.body.call(exports, module, global);
        module.loaded = true;
        return module.exports;
    } finally {
        module.executing = false;
    }
};

contextProto.require = function (module, id) {
    var filename = this.resolve(module, id);
    var newModule = this.cache[filename];
    if (newModule) {
        return this.executePreloadedModule(newModule);
    }
    throw new Error(['Module ', id, ' (', filename, ') is not loaded.'].join(''));
};

contextProto.resolve = function (module, id) {
    return this.resolver.resolve(module.filename, id);
};

contextProto.getModule = function (moduleFilename) {
    if (!moduleFilename) {
        // anonymous module
        return new Module(this);
    }
    var res = this.cache[moduleFilename];
    if (!res) {
        this.cache[moduleFilename] = res = new Module(this, moduleFilename);
    }
    return res;
};

contextProto.define = function (moduleFilename, dependencies, body) {
    this.defineModule(this.getModule(moduleFilename), dependencies, body);
};

contextProto.defineModule = function (module, dependencies, body) {
    if (!module.definition) {
        // do not override an existing definition
        var definition = {
            dependencies: dependencies,
            body: body
        };
        module.definition = definition;
        if (!dependencies.length) {
            module.preloaded = true;
        }
        var loadingDefinition = module.loadingDefinition;
        if (loadingDefinition) {
            if (loadingDefinition.isPending()) {
                loadingDefinition.resolve();
            } else {
                // there was probably an error previously when loading this module
                module.loadingDefinition = false;
            }
        }
    }
    return module;
};

contextProto.executeModule = function (module) {
    var self = this;
    return self.preloadModule(module).then(function () {
        return self.executePreloadedModule(module);
    }).always(function () {
        self = null;
        module = null;
    });
};

contextProto.execute = function (code, moduleFilename) {
    var module = this.getModule(moduleFilename);
    this.defineModule(module, extractDependencies(code), moduleFunction(code));
    return this.executeModule(module);
};

contextProto.asyncRequire = function (module, id) {
    if (isArray(id)) {
        return this.preloadModules(module, id);
    } else {
        return this.require(module, id);
    }
};

contextProto.Context = Context;

module.exports = Context;<commit_msg>Exposing the execute method on the noder object.<commit_after>/*
 * Copyright 2012 Amadeus s.a.s.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var promise = require("./promise.js");
var Packaging = require('./packaging.js');
var extractDependencies = require('./extractDependencies.js');
var moduleFunction = require('./moduleFunction.js');
var execCallModule = require('./execCallModule.js');
var Resolver = require('./resolver.js');
var execScripts = require('../node-modules/execScripts.js');
var isArray = require('./type.js').isArray;
var dirname = require('./path.js').dirname;

var bind = function (fn, scope) {
    return function () {
        return fn.apply(scope, arguments);
    };
};

var bind1 = function (fn, scope, paramBind) {
    return function (param) {
        return fn.call(scope, paramBind, param);
    };
};

function Module(context, filename) {
    if (filename) {
        this.dirname = dirname(filename);
    } else {
        filename = '.';
        this.dirname = filename;
    }
    this.filename = filename;
    this.id = filename;
    this.require = bind1(context.require, context, this);
    this.require.resolve = bind1(context.resolve, context, this);
    this.require.cache = context.cache;
    this.parent = null;
    this.children = [];
}

var moduleProto = Module.prototype = {};
moduleProto.preloading = false;
moduleProto.preloaded = false;
moduleProto.loadingDefinition = false;
moduleProto.definition = null;
moduleProto.executing = false;
moduleProto.loaded = false;

module.exports = Module;

var createAsyncRequire = function (context) {
    return function (module) {
        module.exports = {
            create: function (module) {
                return function (id) {
                    return context.asyncRequire(module, id);
                };
            }
        };
    };
};

var start = function (context) {
    var config = context.config;
    var actions = promise.done;

    if (!config.hasOwnProperty('scriptsType')) {
        config.scriptsType = config.varName;
    }
    var scriptsType = config.scriptsType;
    if (scriptsType) {
        actions = actions.then(function () {
            return execScripts(context, scriptsType);
        });
    }

    var main = config.main;
    actions = actions.then(main ?
    function () {
        return execCallModule(context, main);
    } : promise.empty /* if there is no main module, an empty parameter should be passed to onstart */ );

    actions = actions.then(config.onstart);

    return actions.always(function () {
        context = null;
        config = null;
        actions = null;
    });
};

var Context = function (config) {
    this.cache = {};
    var define = bind(this.define, this);
    this.define = define; // allow using define without the scope
    define("asyncRequire.js", [], createAsyncRequire(this));

    config = config || {};
    this.config = config;
    this.resolver = new Resolver(config.resolver);
    this.packaging = new Packaging(config.packaging, this.define);

    var rootModule = new Module(this);
    rootModule.preloaded = true;
    rootModule.loaded = true;
    rootModule.define = define;
    rootModule.asyncRequire = rootModule.require('asyncRequire').create(rootModule);
    rootModule.execute = bind(this.execute, this);
    this.rootModule = rootModule;

    var globalVarName = config.varName;
    if (globalVarName) {
        global[globalVarName] = rootModule;
    }
    start(this).end();
};

var contextProto = Context.prototype = {};

// Preloading a module means making it ready to be executed (loading its definition and preloading its
// dependencies)
contextProto.preloadModule = function (module, parent) {
    if (module.preloaded) {
        return promise.done;
    }
    if (module.preloading) {
        // If we get here, it may be because of a circular dependency
        // check it here:
        while (parent) {
            if (parent === module) {
                return promise.done;
            }
            parent = parent.parent;
        }
        return module.preloading;
    }
    var self = this;
    if (parent && parent.id != '.') {
        module.parent = parent;
        module.require.main = parent.require.main;
        parent.children.push(module);
    } else {
        module.require.main = module;
    }
    return module.preloading = self.loadDefinition(module).then(function () {
        return self.preloadModules(module, module.definition.dependencies);
    }).then(function () {
        module.preloaded = true;
        module.preloading = false;
    }).always(function () {
        // clean up
        module = null;
        self = null;
    });
};

contextProto.loadDefinition = function (module) {
    if (module.definition) {
        return promise.done;
    }
    var res = module.loadingDefinition;
    if (!res) {
        // store the promise so that it can be resolved when the define method is called:
        module.loadingDefinition = res = promise();
        this.packaging.loadModule(module.filename).then(function () {
            if (res) {
                // if reaching this, and if res is still pending, then it means the module was not found where expected
                res.reject(new Error("Module " + module.filename + " was not found in expected package."));
            }
        }, res.reject);
        res.done(function () {
            res = null;
            module.loadingDefinition = false;
        });
    }
    return res;
};

contextProto.preloadModules = function (module, modules) {
    var promises = [];
    for (var i = 0, l = modules.length; i < l; i++) {
        promises.push(this.preloadModule(this.getModule(this.resolve(module, modules[i])), module));
    }
    return promise.when(promises);
};

contextProto.executePreloadedModule = function (module) {
    if (module.loaded || module.executing) { /* this.executing is true only in the case of a circular dependency */
        return module.exports;
    }
    if (!module.preloaded) {
        throw new Error('A module must be preloaded before executing it.');
    }
    var exports = {};
    module.exports = exports;
    module.executing = true;
    try {
        module.definition.body.call(exports, module, global);
        module.loaded = true;
        return module.exports;
    } finally {
        module.executing = false;
    }
};

contextProto.require = function (module, id) {
    var filename = this.resolve(module, id);
    var newModule = this.cache[filename];
    if (newModule) {
        return this.executePreloadedModule(newModule);
    }
    throw new Error(['Module ', id, ' (', filename, ') is not loaded.'].join(''));
};

contextProto.resolve = function (module, id) {
    return this.resolver.resolve(module.filename, id);
};

contextProto.getModule = function (moduleFilename) {
    if (!moduleFilename) {
        // anonymous module
        return new Module(this);
    }
    var res = this.cache[moduleFilename];
    if (!res) {
        this.cache[moduleFilename] = res = new Module(this, moduleFilename);
    }
    return res;
};

contextProto.define = function (moduleFilename, dependencies, body) {
    this.defineModule(this.getModule(moduleFilename), dependencies, body);
};

contextProto.defineModule = function (module, dependencies, body) {
    if (!module.definition) {
        // do not override an existing definition
        var definition = {
            dependencies: dependencies,
            body: body
        };
        module.definition = definition;
        if (!dependencies.length) {
            module.preloaded = true;
        }
        var loadingDefinition = module.loadingDefinition;
        if (loadingDefinition) {
            if (loadingDefinition.isPending()) {
                loadingDefinition.resolve();
            } else {
                // there was probably an error previously when loading this module
                module.loadingDefinition = false;
            }
        }
    }
    return module;
};

contextProto.executeModule = function (module) {
    var self = this;
    return self.preloadModule(module).then(function () {
        return self.executePreloadedModule(module);
    }).always(function () {
        self = null;
        module = null;
    });
};

contextProto.execute = function (code, moduleFilename) {
    var module = this.getModule(moduleFilename);
    this.defineModule(module, extractDependencies(code), moduleFunction(code));
    return this.executeModule(module);
};

contextProto.asyncRequire = function (module, id) {
    if (isArray(id)) {
        return this.preloadModules(module, id);
    } else {
        return this.require(module, id);
    }
};

contextProto.Context = Context;

module.exports = Context;<|endoftext|>


<commit_before>import axios from 'axios';

export default function initCanvas() {
  const canvas = document.querySelector('#drawing');
  const clearButton = document.querySelector('.drawing__clear');
  const saveButton = document.querySelector('.drawing__save');
  const errorMessage = document.querySelector('.drawing__error');
  const displayContainer = document.querySelector('.drawing__display');
  const ctx = canvas.getContext('2d');
  const mouse = { x: 0, y: 0 };

  // Canvas settings
  ctx.canvas.width = 300;
  ctx.canvas.height = 225;
  ctx.lineWidth = 2;
  ctx.lineJoin = 'round';
  ctx.lineCap = 'round';
  ctx.strokeStyle = '#000000';

  /**
   * Paint a line on the canvas, drawing in progress
   */
  function paint() {
    ctx.lineTo(mouse.x, mouse.y);
    ctx.stroke();
  }

  /**
   * Clear the canvas
   */
  function clear() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  }

  /**
   * Function to continually set the cursor position,
   * taking into account different pixel densities
   *
   * @param {any} event The touch or mousemove event
   */
  function setPosition(event) {
    const rect = canvas.getBoundingClientRect(); // abs. size of element
    const scaleX = canvas.width / rect.width; // relationship bitmap vs. element for X
    const scaleY = canvas.height / rect.height; // relationship bitmap vs. element for Y
    const clientX = event.clientX ? event.clientX : event.touches[0].clientX;
    const clientY = event.clientY ? event.clientY : event.touches[0].clientY;

    mouse.x = (clientX - rect.left) * scaleX;
    mouse.y = (clientY - rect.top) * scaleY;
  }

  /**
   * Start a new path on the canvas
   *
   * @param {any} event Touchstart or mousemove event
   */
  function startPath(event) {
    canvas.classList.remove('blank', 'error', 'merci');
    setPosition(event);
    ctx.beginPath();
    ctx.moveTo(mouse.x, mouse.y);
    paint();
  }

  canvas.addEventListener('mousemove', setPosition, false);
  canvas.addEventListener('touchmove', setPosition, false);

  canvas.addEventListener('mousedown', (event) => {
    startPath(event);

    canvas.addEventListener('mousemove', paint, false);
  }, false);

  canvas.addEventListener('touchstart', (event) => {
    event.preventDefault();
    startPath(event);

    canvas.addEventListener('touchmove', paint, false);
  });

  canvas.addEventListener('touchend', () => {
    canvas.removeEventListener('touchmove', paint, false);
  }, false);

  document.documentElement.addEventListener('mouseup', () => {
    canvas.removeEventListener('mousemove', paint, false);
  }, false);

  canvas.addEventListener('mouseenter', (event) => {
    if (event.which !== 1) return;
    startPath(event);
    canvas.addEventListener('mousemove', paint, false);
  });

  canvas.addEventListener('mouseleave', () => {
    canvas.removeEventListener('mousemove', paint, false);
  }, false);

  clearButton.addEventListener('click', clear);

  saveButton.addEventListener('click', () => {
    const postMeta = document.querySelector('meta[property="id"]');
    const postId = postMeta ? postMeta.getAttribute('content') : null;
    const sendButton = document.querySelector('.drawing__save');
    const imageData = canvas.toDataURL();
    const newImg = document.createElement('img');

    // Clear canvas and say thanks
    clear();
    newImg.src = imageData;
    if (displayContainer) displayContainer.appendChild(newImg);
    errorMessage.classList.remove('show');
    canvas.classList.add('merci');
    sendButton.setAttribute('disabled', 'disabled');

    // Put the drawing
    axios.put('/api/drawing', `source=${imageData}&postid=${postId}`)
      .then(() => {
        canvas.classList.remove('merci');
        sendButton.removeAttribute('disabled');
      })
      .catch((error) => {
        errorMessage.innerHTML = error.message;
        errorMessage.classList.add('show');
        canvas.classList.add('error');
        sendButton.removeAttribute('disabled');
      });
  });
}
<commit_msg>Better left mouse pressed detection<commit_after>import axios from 'axios';

export default function initCanvas() {
  const canvas = document.querySelector('#drawing');
  const clearButton = document.querySelector('.drawing__clear');
  const saveButton = document.querySelector('.drawing__save');
  const errorMessage = document.querySelector('.drawing__error');
  const displayContainer = document.querySelector('.drawing__display');
  const ctx = canvas.getContext('2d');
  const mouse = { x: 0, y: 0 };

  // Canvas settings
  ctx.canvas.width = 300;
  ctx.canvas.height = 225;
  ctx.lineWidth = 2;
  ctx.lineJoin = 'round';
  ctx.lineCap = 'round';
  ctx.strokeStyle = '#000000';

  /**
   * Paint a line on the canvas, drawing in progress
   */
  function paint() {
    ctx.lineTo(mouse.x, mouse.y);
    ctx.stroke();
  }

  /**
   * Clear the canvas
   */
  function clear() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  }

  /**
   * Function to continually set the cursor position,
   * taking into account different pixel densities
   *
   * @param {any} event The touch or mousemove event
   */
  function setPosition(event) {
    const rect = canvas.getBoundingClientRect(); // abs. size of element
    const scaleX = canvas.width / rect.width; // relationship bitmap vs. element for X
    const scaleY = canvas.height / rect.height; // relationship bitmap vs. element for Y
    const clientX = event.clientX ? event.clientX : event.touches[0].clientX;
    const clientY = event.clientY ? event.clientY : event.touches[0].clientY;

    mouse.x = (clientX - rect.left) * scaleX;
    mouse.y = (clientY - rect.top) * scaleY;
  }

  /**
   * Start a new path on the canvas
   *
   * @param {any} event Touchstart or mousemove event
   */
  function startPath(event) {
    canvas.classList.remove('blank', 'error', 'merci');
    setPosition(event);
    ctx.beginPath();
    ctx.moveTo(mouse.x, mouse.y);
    paint();
  }

  canvas.addEventListener('mousemove', setPosition, false);
  canvas.addEventListener('touchmove', setPosition, false);

  canvas.addEventListener('mousedown', (event) => {
    startPath(event);

    canvas.addEventListener('mousemove', paint, false);
  }, false);

  canvas.addEventListener('touchstart', (event) => {
    event.preventDefault();
    startPath(event);

    canvas.addEventListener('touchmove', paint, false);
  });

  canvas.addEventListener('touchend', () => {
    canvas.removeEventListener('touchmove', paint, false);
  }, false);

  document.documentElement.addEventListener('mouseup', () => {
    canvas.removeEventListener('mousemove', paint, false);
  }, false);

  canvas.addEventListener('mouseenter', (event) => {
    const leftMousePressed = 'buttons' in event ? event.buttons === 1 : event.which === 1;
    if (!leftMousePressed) return;
    startPath(event);
    canvas.addEventListener('mousemove', paint, false);
  });

  canvas.addEventListener('mouseleave', () => {
    canvas.removeEventListener('mousemove', paint, false);
  }, false);

  clearButton.addEventListener('click', clear);

  saveButton.addEventListener('click', () => {
    const postMeta = document.querySelector('meta[property="id"]');
    const postId = postMeta ? postMeta.getAttribute('content') : null;
    const sendButton = document.querySelector('.drawing__save');
    const imageData = canvas.toDataURL();
    const newImg = document.createElement('img');

    // Clear canvas and say thanks
    clear();
    newImg.src = imageData;
    if (displayContainer) displayContainer.appendChild(newImg);
    errorMessage.classList.remove('show');
    canvas.classList.add('merci');
    sendButton.setAttribute('disabled', 'disabled');

    // Put the drawing
    axios.put('/api/drawing', `source=${imageData}&postid=${postId}`)
      .then(() => {
        canvas.classList.remove('merci');
        sendButton.removeAttribute('disabled');
      })
      .catch((error) => {
        errorMessage.innerHTML = error.message;
        errorMessage.classList.add('show');
        canvas.classList.add('error');
        sendButton.removeAttribute('disabled');
      });
  });
}
<|endoftext|>


<commit_before>module.exports = (bot, logger, helper) => {
  const Whatanime = require('whatanimega-helper')

  const Format = class {
    constructor (time) {
      this.time = time
      return true
    }
    get hour () {
      return this.pad(Math.floor(this.time / (60 * 60)))
    }
    get min () {
      return this.pad(Math.floor(this.time % (60 * 60) / 60))
    }
    get sec () {
      return this.pad(Math.floor(this.time % 60))
    }
    pad (s) {
      return (s < 10 ? '0' : '') + s
    }
  }

  const failure = async (chatid, msg) => {
    let temp
    try {
      // eslint-disable-next-line
      let send
      [send, temp] = await Promise.all([
        bot.sendChatAction(chatid, 'typing'),
        helper.getlang(msg, logger)
      ])
      await bot.sendMessage(chatid, '📺❗ ' + temp.text(msg.chat.type, 'command.whatanime.info'), {
        reply_to_message_id: msg.message_id,
        parse_mode: 'HTML',
        reply_markup: {
          force_reply: true, selective: true
        }
      })
      logger.info('chatid: ' + chatid + ', username: ' + helper.getuser(msg.from) + ', lang: ' + msg.from.language_code + ', command: whatanime, type: valid,')
    } catch (e) {
      logger.error('chatid: ' + chatid + ', username: ' + helper.getuser(msg.from) + ', lang: ' + msg.from.language_code + ', command: whatanime, type: error')
      logger.debug(e.stack)
    }
  }

  const success = async (chatid, msg, photo) => {
    let temp
    try {
      logger.info('chatid: ' + chatid + ', username: ' + helper.getuser(msg.from) + ', lang: ' + msg.from.language_code + ', command: whatanime, type: command received')
      // eslint-disable-next-line
      let send
      [send, temp] = await Promise.all([
        bot.sendChatAction(chatid, 'typing'),
        helper.getlang(msg, logger)
      ])

      const query = new Whatanime(global.config.apikey.whatanime)

      const url = await bot.getFileLink(photo)
      const response = await query.search(url)
      const result = response.docs[0]
      let resultMessage = ''
      if (result.anime.toLowerCase() !== result.title_english.toLowerCase()) {
        resultMessage = temp.textb(msg.chat.type, 'command.whatanime.name') + ': ' + result.title + '\n' +
          temp.textb(msg.chat.type, 'command.whatanime.english') + ': ' + result.title_english + '\n'
      } else {
        resultMessage = temp.textb(msg.chat.type, 'command.whatanime.name') + ': ' + result.anime + '\n'
      }
      const time = new Format(result.at)
      resultMessage = resultMessage +
        temp.textb(msg.chat.type, 'command.whatanime.episode') + ' ' + result.episode + '\n' +
        temp.textb(msg.chat.type, 'command.whatanime.time') + ': ' +
        (time.hour === '00' ? '' : time.hour + ' : ') + time.min + ' : ' + time.sec + '\n' +
        temp.textb(msg.chat.type, 'command.whatanime.match') + ': ' + (result.similarity * 100).toFixed(2) + '%'
      if (result.similarity > 70) {
        await bot.sendMessage(chatid, resultMessage + '\n' + temp.text(msg.chat.type, 'command.whatanime.incorrect'), {
          parse_mode: 'HTML',
          disable_web_page_preview: true,
          reply_to_message_id: msg.message_id
        })
      } else {
        const animeVideo = await query.previewVideo(result.season, result.anime, result.filename, result.at, result.tokenthumb)
        await Promise.all([
          bot.sendMessage(chatid, resultMessage, {
            parse_mode: 'HTML',
            disable_web_page_preview: true,
            reply_to_message_id: msg.message_id
          }),
          bot.sendVideo(chatid, animeVideo, {
            reply_to_message_id: msg.message_id
          })
        ])
      }
      logger.info('chatid: ' + chatid + ', username: ' + helper.getuser(msg.from) + ', lang: ' + msg.from.language_code + ', command: whatanime, type: valid')
    } catch (e) {
      logger.error('chatid: ' + chatid + ', username: ' + helper.getuser(msg.from) + ', lang: ' + msg.from.language_code + ', command: whatanime, type: error')
      logger.debug(e.stack)
    }
  }

  bot.on('message', async (msg) => {
    try {
      if (Math.round((new Date()).getTime() / 1000) - msg.date >= 180) return
      if (msg.photo) {
        if (/^(?:무슨애니|whatanime|\/무슨애니|\/whatanime|무슨애니\?|anime)$/.test(msg.text)) {
          await success(msg.chat.id, msg, msg.photo[msg.photo.length - 1].file_id)
        } else if (msg.reply_to_message.from.username !== global.botinfo.username &&
          msg.reply_to_message.text.match(/📺❗/)) {
          await success(msg.chat.id, msg, msg.photo[msg.photo.length - 1].file_id)
        }
      } else {
        if (/^(?:무슨애니|whatanime|\/무슨애니|\/whatanime|무슨애니\?|anime)$/.test(msg.text) &&
          msg.reply_to_message && msg.reply_to_message.photo) {
          await success(msg.chat.id, msg, msg.reply_to_message.photo[msg.reply_to_message.photo.length - 1].file_id)
        } else if (/^\/(?:무슨애니|\/whatanime)$/.test(msg.text) &&
          !msg.reply_to_message) {
          await failure(msg.chat.id, msg)
        }
      }
    } catch (e) {
      logger.error('chatid: ' + msg.chat.id + ', username: ' + helper.getuser(msg.from) + ', lang: ' + msg.from.language_code + ', command: whatanime, type: error')
      logger.debug(e.stack)
    }
  })
}
<commit_msg>오류 수정<commit_after>module.exports = (bot, logger, helper) => {
  const Whatanime = require('whatanimega-helper')

  const Format = class {
    constructor (time) {
      this.time = time
      return true
    }
    get hour () {
      return this.pad(Math.floor(this.time / (60 * 60)))
    }
    get min () {
      return this.pad(Math.floor(this.time % (60 * 60) / 60))
    }
    get sec () {
      return this.pad(Math.floor(this.time % 60))
    }
    pad (s) {
      return (s < 10 ? '0' : '') + s
    }
  }

  const failure = async (chatid, msg) => {
    let temp
    try {
      // eslint-disable-next-line
      let send
      [send, temp] = await Promise.all([
        bot.sendChatAction(chatid, 'typing'),
        helper.getlang(msg, logger)
      ])
      await bot.sendMessage(chatid, '📺❗ ' + temp.text(msg.chat.type, 'command.whatanime.info'), {
        reply_to_message_id: msg.message_id,
        parse_mode: 'HTML',
        reply_markup: {
          force_reply: true, selective: true
        }
      })
      logger.info('chatid: ' + chatid + ', username: ' + helper.getuser(msg.from) + ', lang: ' + msg.from.language_code + ', command: whatanime, type: valid,')
    } catch (e) {
      logger.error('chatid: ' + chatid + ', username: ' + helper.getuser(msg.from) + ', lang: ' + msg.from.language_code + ', command: whatanime, type: error')
      logger.debug(e.stack)
    }
  }

  const success = async (chatid, msg, photo) => {
    let temp
    try {
      logger.info('chatid: ' + chatid + ', username: ' + helper.getuser(msg.from) + ', lang: ' + msg.from.language_code + ', command: whatanime, type: command received')
      // eslint-disable-next-line
      let send
      [send, temp] = await Promise.all([
        bot.sendChatAction(chatid, 'typing'),
        helper.getlang(msg, logger)
      ])

      const query = new Whatanime(global.config.apikey.whatanime)

      const url = await bot.getFileLink(photo)
      const response = await query.search(url)
      const result = response.docs[0]
      let resultMessage = ''
      if (result.anime.toLowerCase() !== result.title_english.toLowerCase()) {
        resultMessage = temp.textb(msg.chat.type, 'command.whatanime.name') + ': ' + result.title + '\n' +
          temp.textb(msg.chat.type, 'command.whatanime.english') + ': ' + result.title_english + '\n'
      } else {
        resultMessage = temp.textb(msg.chat.type, 'command.whatanime.name') + ': ' + result.anime + '\n'
      }
      const time = new Format(result.at)
      resultMessage = resultMessage +
        temp.textb(msg.chat.type, 'command.whatanime.episode') + ' ' + result.episode + '\n' +
        temp.textb(msg.chat.type, 'command.whatanime.time') + ': ' +
        (time.hour === '00' ? '' : time.hour + ' : ') + time.min + ' : ' + time.sec + '\n' +
        temp.textb(msg.chat.type, 'command.whatanime.match') + ': ' + (result.similarity * 100).toFixed(2) + '%'
      if (result.similarity * 100 > 70) {
        await bot.sendMessage(chatid, resultMessage + '\n' + temp.text(msg.chat.type, 'command.whatanime.incorrect'), {
          parse_mode: 'HTML',
          disable_web_page_preview: true,
          reply_to_message_id: msg.message_id
        })
      } else {
        const animeVideo = await query.previewVideo(result.season, result.anime, result.filename, result.at, result.tokenthumb)
        await Promise.all([
          bot.sendMessage(chatid, resultMessage, {
            parse_mode: 'HTML',
            disable_web_page_preview: true,
            reply_to_message_id: msg.message_id
          }),
          bot.sendVideo(chatid, animeVideo, {
            reply_to_message_id: msg.message_id
          })
        ])
      }
      logger.info('chatid: ' + chatid + ', username: ' + helper.getuser(msg.from) + ', lang: ' + msg.from.language_code + ', command: whatanime, type: valid')
    } catch (e) {
      logger.error('chatid: ' + chatid + ', username: ' + helper.getuser(msg.from) + ', lang: ' + msg.from.language_code + ', command: whatanime, type: error')
      logger.debug(e.stack)
    }
  }

  bot.on('message', async (msg) => {
    try {
      if (Math.round((new Date()).getTime() / 1000) - msg.date >= 180) return
      if (msg.photo) {
        if (/^(?:무슨애니|whatanime|\/무슨애니|\/whatanime|무슨애니\?|anime)$/.test(msg.caption)) {
          await success(msg.chat.id, msg, msg.photo[msg.photo.length - 1].file_id)
          return
        } else if (msg.reply_to_message.from.username === global.botinfo.username &&
          msg.reply_to_message.text.match(/📺❗/)) {
          await success(msg.chat.id, msg, msg.photo[msg.photo.length - 1].file_id)
          return
        }
      } else {
        if (/^(?:무슨애니|whatanime|\/무슨애니|\/whatanime|무슨애니\?|anime)$/.test(msg.text) &&
          msg.reply_to_message && msg.reply_to_message.photo) {
          await success(msg.chat.id, msg, msg.reply_to_message.photo[msg.reply_to_message.photo.length - 1].file_id)
          return
        } else if (/^\/(?:무슨애니|\/whatanime)$/.test(msg.text)) {
          await failure(msg.chat.id, msg)
          return
        }
      }
    } catch (e) {
      logger.error('chatid: ' + msg.chat.id + ', username: ' + helper.getuser(msg.from) + ', lang: ' + msg.from.language_code + ', command: whatanime, type: error')
      logger.debug(e.stack)
    }
  })
}
<|endoftext|>