<commit_before>import AI from '../ai';
import Game from '../models/Game';
import Logger from '../logger';
import Rx from 'rxjs';
import db from '../database';
import {startLoading, endLoading, setSubscription, showMessage} from './app';
import {pushPage, popPage, replacePage} from './navigation';
import {PAGES} from '../models/Page';

export const GAME_ACTIONS = {
  RESUME_GAME: 'RESUME_GAME',
  START_GAME: 'START_GAME',
  UPDATE_GAME: 'UPDATE_GAME',
  SUSPEND_GAME: 'SUSPEND_GAME',
  GAME_ENDED: 'GAME_ENDED',
  LAUNCH_GAME_AGAINST_AI: 'LAUNCH_GAME_AGAINST_AI',
  CLICK_ON_TOWER: 'CLICK_ON_TOWER',
  CLICK_ON_FIELD: 'CLICK_ON_FIELD',
};

export const MOVE_RESULTS = {
  OK: 'OK',
  NOT_YOUR_TURN: 'NOT_YOUR_TURN',
  INVALID: 'INVALID',
  NO_TOWER_SELECTED: 'NO_TOWER_SELECTED',
};

/**
 * @type {AI}
 */
let computerPlayer = null;

/**
 * Launches a new game against the computer.
 *
 * @export
 * @param {string} player ID of the player.
 * @return {void}
 */
export function startGameAgainstAI(player) {
  const aiCharacteristics = {
    blockedPenalty: 20 + (5 - Math.random() * 10),
    couldFinishBonus: 10 + (2 - Math.random() * 4),
    aggressiveness: 0.5 + (0.1 - Math.random() * 0.2),
  };

  computerPlayer = new AI(aiCharacteristics);

  return {
    type: GAME_ACTIONS.LAUNCH_GAME_AGAINST_AI,
    player,
    blockedPenalty: aiCharacteristics.blockedPenalty,
    couldFinishBonus: aiCharacteristics.couldFinishBonus,
    aggressiveness: aiCharacteristics.aggressiveness,
  };
}

export const gameSuspended = () => ({
  type: GAME_ACTIONS.SUSPEND_GAME,
});

/**
 * Suspends the currently running game.
 *
 * @export
 * @param {string} gameKey
 * @return {void}
 */
export function suspendGame(gameKey) {
  return (dispatch) => {
    Logger.debug(`suspending game: ${gameKey}`);
    db.child(`games/${gameKey}`).off();
    dispatch(gameSuspended());
  };
}

/**
 * Starts to listen for updates of a specific game.
 * Every update will trigger an update game action.
 *
 * @export
 * @param {string} gameKey The game which to watch for changes.
 * @return {function(function(object):void):void}
 */
export function startListeningForGameUpdates(gameKey) {
  return (dispatch) => {
    db.child(`games/${gameKey}`).on('value', (snapshot) => {
      const gameState = snapshot.val();

      if (gameState !== null) {
        dispatch(updateGame(gameState));
      }
    });
  };
}

/**
 * Loads a game from a given key.
 *
 * @export
 * @param {string} gameKey Name of the game.
 * @return {function(function(object):void):void}
 */
export function loadGameFromKey(gameKey) {
  return (dispatch, getState) => {
    const gameObserver = Rx.Observable.fromPromise(
      db.child(`games/${gameKey}`).once('value')
    );

    dispatch(startLoading(`Resuming game ...`));
    const subscription = gameObserver.subscribe(
      (gameSnapshot) => {
        const currentState = getState();

        if (gameSnapshot.exists()) {
          const game = gameSnapshot.val();
          const player = Game.getPlayer(game, currentState.app.player.id);
          const opponent = Game.getOpponent(game, currentState.app.player.id);
          const gamePage = PAGES.GAME.withTitle(
            `${player.name} vs ${opponent.name}`
          );

          dispatch(resumeGame(gameKey));
          dispatch(updateGame(game));
          dispatch(startListeningForGameUpdates(gameKey));

          const gameState = getState().game;
          if (gameState.valid) {
            dispatch(pushPage(gamePage));
          } else {
            dispatch(showMessage('Game is not in a valid state!'));
          }
        }
      },
      (error) => dispatch(showMessage(error)),
      () => dispatch(endLoading())
    );
    setSubscription(subscription);
  };
}

export const resumeGame = (game) => ({
  type: GAME_ACTIONS.RESUME_GAME,
  game,
});

export const gameStarted = (game) => ({
  type: GAME_ACTIONS.START_GAME,
  game,
});

/**
 * Starts a new game between the two given players.
 *
 * @export
 * @param {string} playerID Database ID of the player.
 * @param {string} opponentID Database ID of the player's opponent.
 * @param {any} players Map of player IDs to their corresponding player objects.
 * @return {function(function(object):void):void}
 */
export function startGame(playerID, opponentID, players) {
  return (dispatch) => {
    dispatch(startLoading(`starting game against ${players[opponentID].name}`));

    const playersCopy = {};
    for (const id in players) {
      if (players.hasOwnProperty(id)) {
        Object.assign(playersCopy, {
          [id]: {
            name: players[id].name,
          },
        });
      }
    }

    const newGame = {
      players: playersCopy,
      currentPlayer: playerID,
      moves: [],
    };
    const gameName = Game.getKey(newGame);
    const playerRef = db.child(`players/${playerID}`);
    const opponentRef = db.child(`players/${opponentID}`);
    const gameRef = db.child(`games/${gameName}`);

    return Promise.all([
      opponentRef.once('value'),
      playerRef.once('value'),
      gameRef.once('value'),
    ])
      .then((results) => {
        const opponent = results[0];
        const player = results[1];
        const game = results[2];
        const updatePlayerGames = (gamesObj) => {
          gamesObj = gamesObj || {};
          gamesObj[gameName] = {
            players: {
              [player.key]: {
                name: player.val().name,
              },
              [opponent.key]: {
                name: opponent.val().name,
              },
            },
            currentPlayer: newGame.currentPlayer,
          };
          return gamesObj;
        };

        if (!opponent.exists()) {
          throw new Error('Opponent does not exist in database!');
        }
        if (!player.exists()) {
          throw new Error('Player does not exist in database!');
        }
        if (game.exists()) {
          throw new Error(
            `You are already playing against ${opponent.val().name}!`
          );
        }

        return gameRef
          .set(newGame)
          .then(() =>
            Promise.all([
              db
                .child(`players/${playerID}/games`)
                .transaction(updatePlayerGames),
              db
                .child(`players/${opponentID}/games`)
                .transaction(updatePlayerGames),
            ])
          )
          .then(() => {
            const gamePage = PAGES.GAME.withTitle(
              `${players[playerID].name} vs ${players[opponentID].name}`
            );
            dispatch(gameStarted(newGame));
            dispatch(replacePage(gamePage));
            dispatch(startListeningForGameUpdates(gameName));
            dispatch(endLoading());
          });
      })
      .catch((err) => {
        dispatch(endLoading());
        dispatch(showMessage(err));
      });
  };
}

export const updateGame = (game) => ({
  type: GAME_ACTIONS.UPDATE_GAME,
  game,
});

/**
 * End the game with given key.
 *
 * @export
 * @param {any} gameKey Name of the game that should be ended.
 * @return {function(function(object):void):void}
 */
export function endGame(gameKey) {
  return (dispatch, getState) => {
    const currentState = getState();
    const player = currentState.app.player.id;

    if (currentState.game.isAIGame || currentState.game.isTutorial) {
      dispatch(popPage());
      return;
    }

    const gameRef = db.child(`games/${gameKey}`);
    const playerGameRef = db.child(`players/${player}/games/${gameKey}`);

    // do not receive updates on this game anymore
    gameRef.off();

    gameRef
      .once('value')
      .then((snapshot) => {
        const game = snapshot.val();
        const opponent = Object.keys(game.players).find((uid) => uid !== player);

        // remove game from player
        playerGameRef.remove();

        // if opponent still has game
        return db
          .child(`players/${opponent}/games/${gameKey}`)
          .once('value')
          .then((val) => {
            if (val.exists()) {
              if (game.currentPlayer === player) {
                gameRef.child('currentPlayer').set(opponent);
              }
            } else {
              if (game.currentPlayer === player) {
                gameRef.remove();
              }
            }
          });
      })
      .then(() => {
        dispatch(gameEnded(gameKey));
      })
      .catch((e) => {
        Logger.error('an error occured while ending the game:', e);
      })
      .then(() => dispatch(popPage()));
  };
}

export const gameEnded = (gameKey, player) => ({
  type: GAME_ACTIONS.GAME_ENDED,
  gameKey,
});

export const clickOnTower = (tower, playerID) => ({
  type: GAME_ACTIONS.CLICK_ON_TOWER,
  tower,
  playerID,
});

/**
 * Whenever a player clicks onto a field.
 *
 * @export
 * @param {any} field The field the player clicked onto.
 * @return {function(function(object):void):void}
 */
export function clickOnField(field) {
  return (dispatch, getState) => {
    const oldState = getState();
    const playerID = oldState.app.player.id;
    const opponentID = Game.getOpponentID(oldState.game, playerID);
    const currentGame = oldState.app.currentGame;

    dispatch(clickedOnField(field, playerID, currentGame));
    let newState = getState();

    if (oldState.game.currentPlayer !== newState.game.currentPlayer) {
      // only save game if it is not a tutorial
      if (!oldState.game.isTutorial && !oldState.game.isAIGame) {
        const game = {
          currentColor: newState.game.currentColor,
          currentPlayer: newState.game.currentPlayer,
          players: newState.game.players,
          moves: newState.game.moves,
        };

        db.child(`games/${currentGame}`).update(game).then(() => {
          return [playerID, opponentID].map((id) => {
            return db
              .child(`players/${id}/games/${currentGame}/currentPlayer`)
              .set(game.currentPlayer);
          });
        });
      }

      if (oldState.game.isAIGame) {
        setTimeout(() => {
          while (newState.game.currentPlayer === 'computer') {
            const chosenMove = computerPlayer.getNextMove(newState.game);

            if (chosenMove) {
              Logger.info('will choose:', chosenMove);
              dispatch(
                clickedOnField(
                  chosenMove.to,
                  newState.game.currentPlayer,
                  currentGame
                )
              );
              newState = getState();
            } else {
              Logger.info('Computer has won.');
              break;
            }
          }
        }, 0);
      }
    } else {
      if (newState.game.moveResult === MOVE_RESULTS.NOT_YOUR_TURN) {
        dispatch(showMessage(`It's not your turn.`));
      } else if (newState.game.moveResult === MOVE_RESULTS.INVALID) {
        dispatch(showMessage('Move is not valid.'));
      } else if (newState.game.moveResult === MOVE_RESULTS.NO_TOWER_SELECTED) {
        dispatch(showMessage('Select a tower first.'));
      }
    }
  };
}

export const clickedOnField = (field, playerID, currentGame) => ({
  type: GAME_ACTIONS.CLICK_ON_FIELD,
  field,
  playerID,
  currentGame,
});
<commit_msg>fix backend permissioning.<commit_after>import AI from '../ai';
import Game from '../models/Game';
import Logger from '../logger';
import Rx from 'rxjs';
import db from '../database';
import {startLoading, endLoading, setSubscription, showMessage} from './app';
import {pushPage, popPage, replacePage} from './navigation';
import {PAGES} from '../models/Page';

export const GAME_ACTIONS = {
  RESUME_GAME: 'RESUME_GAME',
  START_GAME: 'START_GAME',
  UPDATE_GAME: 'UPDATE_GAME',
  SUSPEND_GAME: 'SUSPEND_GAME',
  GAME_ENDED: 'GAME_ENDED',
  LAUNCH_GAME_AGAINST_AI: 'LAUNCH_GAME_AGAINST_AI',
  CLICK_ON_TOWER: 'CLICK_ON_TOWER',
  CLICK_ON_FIELD: 'CLICK_ON_FIELD',
};

export const MOVE_RESULTS = {
  OK: 'OK',
  NOT_YOUR_TURN: 'NOT_YOUR_TURN',
  INVALID: 'INVALID',
  NO_TOWER_SELECTED: 'NO_TOWER_SELECTED',
};

/**
 * @type {AI}
 */
let computerPlayer = null;

/**
 * Launches a new game against the computer.
 *
 * @export
 * @param {string} player ID of the player.
 * @return {void}
 */
export function startGameAgainstAI(player) {
  const aiCharacteristics = {
    blockedPenalty: 20 + (5 - Math.random() * 10),
    couldFinishBonus: 10 + (2 - Math.random() * 4),
    aggressiveness: 0.5 + (0.1 - Math.random() * 0.2),
  };

  computerPlayer = new AI(aiCharacteristics);

  return {
    type: GAME_ACTIONS.LAUNCH_GAME_AGAINST_AI,
    player,
    blockedPenalty: aiCharacteristics.blockedPenalty,
    couldFinishBonus: aiCharacteristics.couldFinishBonus,
    aggressiveness: aiCharacteristics.aggressiveness,
  };
}

export const gameSuspended = () => ({
  type: GAME_ACTIONS.SUSPEND_GAME,
});

/**
 * Suspends the currently running game.
 *
 * @export
 * @param {string} gameKey
 * @return {void}
 */
export function suspendGame(gameKey) {
  return (dispatch) => {
    Logger.debug(`suspending game: ${gameKey}`);
    db.child(`games/${gameKey}`).off();
    dispatch(gameSuspended());
  };
}

/**
 * Starts to listen for updates of a specific game.
 * Every update will trigger an update game action.
 *
 * @export
 * @param {string} gameKey The game which to watch for changes.
 * @return {function(function(object):void):void}
 */
export function startListeningForGameUpdates(gameKey) {
  return (dispatch) => {
    db.child(`games/${gameKey}`).on('value', (snapshot) => {
      const gameState = snapshot.val();

      if (gameState !== null) {
        dispatch(updateGame(gameState));
      }
    });
  };
}

/**
 * Loads a game from a given key.
 *
 * @export
 * @param {string} gameKey Name of the game.
 * @return {function(function(object):void):void}
 */
export function loadGameFromKey(gameKey) {
  return (dispatch, getState) => {
    const gameObserver = Rx.Observable.fromPromise(
      db.child(`games/${gameKey}`).once('value')
    );

    dispatch(startLoading(`Resuming game ...`));
    const subscription = gameObserver.subscribe(
      (gameSnapshot) => {
        const currentState = getState();

        if (gameSnapshot.exists()) {
          const game = gameSnapshot.val();
          const player = Game.getPlayer(game, currentState.app.player.id);
          const opponent = Game.getOpponent(game, currentState.app.player.id);
          const gamePage = PAGES.GAME.withTitle(
            `${player.name} vs ${opponent.name}`
          );

          dispatch(resumeGame(gameKey));
          dispatch(updateGame(game));
          dispatch(startListeningForGameUpdates(gameKey));

          const gameState = getState().game;
          if (gameState.valid) {
            dispatch(pushPage(gamePage));
          } else {
            dispatch(showMessage('Game is not in a valid state!'));
          }
        }
      },
      (error) => dispatch(showMessage(error)),
      () => dispatch(endLoading())
    );
    setSubscription(subscription);
  };
}

export const resumeGame = (game) => ({
  type: GAME_ACTIONS.RESUME_GAME,
  game,
});

export const gameStarted = (game) => ({
  type: GAME_ACTIONS.START_GAME,
  game,
});

/**
 * Starts a new game between the two given players.
 *
 * @export
 * @param {string} playerID Database ID of the player.
 * @param {string} opponentID Database ID of the player's opponent.
 * @param {any} players Map of player IDs to their corresponding player objects.
 * @return {function(function(object):void):void}
 */
export function startGame(playerID, opponentID, players) {
  return (dispatch) => {
    dispatch(startLoading(`starting game against ${players[opponentID].name}`));

    const playersCopy = {};
    for (const id in players) {
      if (players.hasOwnProperty(id)) {
        Object.assign(playersCopy, {
          [id]: {
            name: players[id].name,
          },
        });
      }
    }

    const newGame = {
      players: playersCopy,
      currentPlayer: playerID,
      moves: [],
    };
    const gameName = Game.getKey(newGame);
    const playerRef = db.child(`players/${playerID}`);
    const opponentRef = db.child(`players/${opponentID}`);
    const gameRef = db.child(`games/${gameName}`);

    return Promise.all([
      opponentRef.once('value'),
      playerRef.once('value'),
      gameRef.once('value'),
    ])
      .then((results) => {
        const opponent = results[0];
        const player = results[1];
        const game = results[2];
        const updatePlayerGames = (gamesObj) => {
          return {
            players: {
              [player.key]: {
                name: player.val().name,
              },
              [opponent.key]: {
                name: opponent.val().name,
              },
            },
            currentPlayer: newGame.currentPlayer,
          };
        };

        if (!opponent.exists()) {
          throw new Error('Opponent does not exist in database!');
        }
        if (!player.exists()) {
          throw new Error('Player does not exist in database!');
        }
        if (game.exists()) {
          throw new Error(
            `You are already playing against ${opponent.val().name}!`
          );
        }

        return gameRef
          .set(newGame)
          .then(() =>
            Promise.all([
              db
                .child(`players/${playerID}/games/${gameName}`)
                .transaction(updatePlayerGames),
              db
                .child(`players/${opponentID}/games/${gameName}`)
                .transaction(updatePlayerGames),
            ])
          )
          .then(() => {
            const gamePage = PAGES.GAME.withTitle(
              `${players[playerID].name} vs ${players[opponentID].name}`
            );
            dispatch(gameStarted(newGame));
            dispatch(replacePage(gamePage));
            dispatch(startListeningForGameUpdates(gameName));
            dispatch(endLoading());
          });
      })
      .catch((err) => {
        dispatch(endLoading());
        dispatch(showMessage(err));
      });
  };
}

export const updateGame = (game) => ({
  type: GAME_ACTIONS.UPDATE_GAME,
  game,
});

/**
 * End the game with given key.
 *
 * @export
 * @param {any} gameKey Name of the game that should be ended.
 * @return {function(function(object):void):void}
 */
export function endGame(gameKey) {
  return (dispatch, getState) => {
    const currentState = getState();
    const player = currentState.app.player.id;

    if (currentState.game.isAIGame || currentState.game.isTutorial) {
      dispatch(popPage());
      return;
    }

    const gameRef = db.child(`games/${gameKey}`);
    const playerGameRef = db.child(`players/${player}/games/${gameKey}`);

    // do not receive updates on this game anymore
    gameRef.off();

    gameRef
      .once('value')
      .then((snapshot) => {
        const game = snapshot.val();
        const opponent = Object.keys(game.players).find((uid) => uid !== player);

        // remove game from player
        playerGameRef.remove();

        // if opponent still has game
        return db
          .child(`players/${opponent}/games/${gameKey}`)
          .once('value')
          .then((val) => {
            if (val.exists()) {
              if (game.currentPlayer === player) {
                gameRef.child('currentPlayer').set(opponent);
              }
            } else {
              if (game.currentPlayer === player) {
                gameRef.remove();
              }
            }
          });
      })
      .then(() => {
        dispatch(gameEnded(gameKey));
      })
      .catch((e) => {
        Logger.error('an error occured while ending the game:', e);
      })
      .then(() => dispatch(popPage()));
  };
}

export const gameEnded = (gameKey, player) => ({
  type: GAME_ACTIONS.GAME_ENDED,
  gameKey,
});

export const clickOnTower = (tower, playerID) => ({
  type: GAME_ACTIONS.CLICK_ON_TOWER,
  tower,
  playerID,
});

/**
 * Whenever a player clicks onto a field.
 *
 * @export
 * @param {any} field The field the player clicked onto.
 * @return {function(function(object):void):void}
 */
export function clickOnField(field) {
  return (dispatch, getState) => {
    const oldState = getState();
    const playerID = oldState.app.player.id;
    const opponentID = Game.getOpponentID(oldState.game, playerID);
    const currentGame = oldState.app.currentGame;

    dispatch(clickedOnField(field, playerID, currentGame));
    let newState = getState();

    if (oldState.game.currentPlayer !== newState.game.currentPlayer) {
      // only save game if it is not a tutorial
      if (!oldState.game.isTutorial && !oldState.game.isAIGame) {
        const game = {
          currentColor: newState.game.currentColor,
          currentPlayer: newState.game.currentPlayer,
          players: newState.game.players,
          moves: newState.game.moves,
        };

        db.child(`games/${currentGame}`).update(game).then(() => {
          return [playerID, opponentID].map((id) => {
            return db
              .child(`players/${id}/games/${currentGame}/currentPlayer`)
              .set(game.currentPlayer);
          });
        });
      }

      if (oldState.game.isAIGame) {
        setTimeout(() => {
          while (newState.game.currentPlayer === 'computer') {
            const chosenMove = computerPlayer.getNextMove(newState.game);

            if (chosenMove) {
              Logger.info('will choose:', chosenMove);
              dispatch(
                clickedOnField(
                  chosenMove.to,
                  newState.game.currentPlayer,
                  currentGame
                )
              );
              newState = getState();
            } else {
              Logger.info('Computer has won.');
              break;
            }
          }
        }, 0);
      }
    } else {
      if (newState.game.moveResult === MOVE_RESULTS.NOT_YOUR_TURN) {
        dispatch(showMessage(`It's not your turn.`));
      } else if (newState.game.moveResult === MOVE_RESULTS.INVALID) {
        dispatch(showMessage('Move is not valid.'));
      } else if (newState.game.moveResult === MOVE_RESULTS.NO_TOWER_SELECTED) {
        dispatch(showMessage('Select a tower first.'));
      }
    }
  };
}

export const clickedOnField = (field, playerID, currentGame) => ({
  type: GAME_ACTIONS.CLICK_ON_FIELD,
  field,
  playerID,
  currentGame,
});
<|endoftext|>


<commit_before>/* Pure JS Cart v1.0 by Simeon Lyubenov <lyubenov@gmail.com> www.webdevlabs.com */

'use strict';

class Cart {

    constructor() {
        // set cart template vars
        this.currencySymbol = 'USD';
        this.removeItemTitle = 'remove from cart';
        // fetch cartStorage object from sessionStorage
        this.cartStorage = JSON.parse(sessionStorage.getItem('cart'));
        if (!this.cartStorage) { this.cartStorage = []; }
        this.renderCart();
        // attach show/hide cart button
        document.querySelector('#shoppingCart .cartBtn').addEventListener('click', function(event) {
            if (document.querySelector('#shoppingCart ul').style.display === 'block') {
                document.querySelector('#shoppingCart ul').style.display = 'none';
            } else {
                document.querySelector('#shoppingCart ul').style.display = 'block';
            }
        });
    }

    saveCart() {
        // save cartStorage object to local browser sessionStorage
        sessionStorage.setItem('cart', JSON.stringify(this.cartStorage));
    }

    addItem(id, price, title) {
        if (this.inCart(id)) {
            this.increaseQty(id);
        } else {
            var item = {
                "id": id,
                "price": price,
                "title": title,
                "qty": '1'
            };
            this.cartStorage.push(item);
        }
        this.saveCart();
        this.renderCart();
    }

    removeItem(id) {
        var i = this.cartStorage.length;
        while (i--) {
            if (arguments.length > 0 && this.cartStorage[i]['id'] === id) {
                if (this.cartStorage[i]['qty'] > 1) {
                    this.cartStorage[i]['qty']--;
                } else {
                    this.cartStorage.splice(i, 1);
                }
            }
        }
        this.saveCart();
        this.renderCart();
    }

    inCart(id) {
        var i = this.cartStorage.length;
        while (i--) {
            if (arguments.length > 0 && this.cartStorage[i]['id'] === id) {
                return true;
            }
        }
    }

    increaseQty(id) {
        var i = this.cartStorage.length;
        while (i--) {
            if (arguments.length > 0 && this.cartStorage[i]['id'] === id) {
                this.cartStorage[i]['qty']++;
            }
        }
    }

    renderCart() {
        var cartTotal = Number('0');
        var itemQtyBox = '';
        var removeItemTitle = this.removeItemTitle;
        document.querySelector('#shoppingCart ul').innerHTML = '';
        // Render Cart view items from cartStorage object
        this.cartStorage.forEach(function(item) {
            if (item.qty > 1) { itemQtyBox = item.qty + ' x '; } else { itemQtyBox = ''; }
            var li = document.createElement("li");
            li.setAttribute("title", removeItemTitle);
            li.setAttribute("data-price", item.price);
            li.setAttribute("data-itemid", item.id);
            li.appendChild(document.createTextNode(itemQtyBox + item.title));
            // attach on click remove item from cart
            li.addEventListener('click', function(event) {
                window.cart.removeItem(item.id);
            });
            document.querySelector('#shoppingCart ul').appendChild(li);
            // increase the cartTotal amount
            cartTotal = Number(cartTotal + (Number(item.price) * Number(item.qty)));
        });
        if (cartTotal > 0) {
            document.querySelector('#shoppingCart').style.display = 'block';
            document.querySelector('#cartTotal').innerHTML = cartTotal.toFixed(2) + this.currencySymbol;
        } else {
            // hide cart if no items
            document.querySelector('#shoppingCart').style.display = 'none';
        }
    }

}

// Create the Cart object when the page is loaded
document.onreadystatechange = function() {
    if (document.readyState == 'complete') {
        window.cart = new Cart();
    }
};

// Attach class .add2cart button functionality
document.body.addEventListener('click', function(e) {
    var t = e.target;
    if (t.classList.contains('add2cart')) {
        window.cart.addItem(
            t.getAttribute('data-itemid'),
            t.getAttribute('data-price'),
            t.getAttribute('data-title')
        );
    }
});
<commit_msg>added js templating<commit_after>/* Pure JS Cart v1.1 by Simeon Lyubenov <lyubenov@gmail.com> www.webdevlabs.com */

'use strict';

class Cart {

    constructor() {
        // set cart template vars
        this.currencySymbol = 'USD';
        this.removeItemTitle = 'remove from cart';
        // fetch cartStorage object from sessionStorage
        this.cartStorage = JSON.parse(sessionStorage.getItem('cart'));
        if (!this.cartStorage) { this.cartStorage = []; }
        this.renderCart();
        // attach show/hide cart button
        document.querySelector('#shoppingCart .cartBtn').addEventListener('click', function(event) {
            if (document.querySelector('#shoppingCart ul').style.display === 'block') {
                document.querySelector('#shoppingCart ul').style.display = 'none';
            } else {
                document.querySelector('#shoppingCart ul').style.display = 'block';
            }
        });
    }

    saveCart() {
        // save cartStorage object to local browser sessionStorage
        sessionStorage.setItem('cart', JSON.stringify(this.cartStorage));
    }

    addItem(id, price, title) {
        if (this.inCart(id)) {
            this.increaseQty(id);
        } else {
            var item = {
                "id": id,
                "price": price,
                "title": title,
                "qty": '1'
            };
            this.cartStorage.push(item);
        }
        this.saveCart();
        this.renderCart();
    }

    removeItem(id) {
        var i = this.cartStorage.length;
        while (i--) {
            if (arguments.length > 0 && this.cartStorage[i]['id'] === id) {
                if (this.cartStorage[i]['qty'] > 1) {
                    this.cartStorage[i]['qty']--;
                } else {
                    this.cartStorage.splice(i, 1);
                }
            }
        }
        this.saveCart();
        this.renderCart();
    }

    inCart(id) {
        var i = this.cartStorage.length;
        while (i--) {
            if (arguments.length > 0 && this.cartStorage[i]['id'] === id) {
                return true;
            }
        }
    }

    increaseQty(id) {
        var i = this.cartStorage.length;
        while (i--) {
            if (arguments.length > 0 && this.cartStorage[i]['id'] === id) {
                this.cartStorage[i]['qty']++;
            }
        }
    }

    renderCart() {
        var cartTotal = Number('0');
        var itemQtyBox = '';
        var removeItemTitle = this.removeItemTitle;
        var currencySymbol = this.currencySymbol;
        document.querySelector('#shoppingCart ul').innerHTML = '';
        // Render Cart view items from cartStorage object
        this.cartStorage.forEach(function(item) {
            if (item.qty > 1) { itemQtyBox = item.qty + ' x '; } else { itemQtyBox = ''; }
            let li = document.createElement("li");
            li.setAttribute("title", removeItemTitle);
            li.setAttribute("data-price", item.price);
            li.setAttribute("data-itemid", item.id);
            let TplCartItem = `${itemQtyBox} ${item.title} = ${Number(item.price * item.qty).toFixed(2)}${currencySymbol}`;
            li.appendChild(document.createTextNode(TplCartItem));
            // attach on click remove item from cart
            li.addEventListener('click', function(event) {
                window.cart.removeItem(item.id);
            });
            document.querySelector('#shoppingCart ul').appendChild(li);
            // increase the cartTotal amount
            cartTotal = Number(cartTotal + (Number(item.price) * Number(item.qty)));
        });
        if (cartTotal > 0) {
            document.querySelector('#shoppingCart').style.display = 'block';
            let TplCartTotal = `${cartTotal.toFixed(2)}${currencySymbol}`;
            document.querySelector('#cartTotal').innerHTML = TplCartTotal;
        } else {
            // hide cart if no items
            document.querySelector('#shoppingCart').style.display = 'none';
        }
    }

}

// Create the Cart object when the page is loaded
document.onreadystatechange = function() {
    if (document.readyState == 'complete') {
        try {
            window.cart = new Cart();
        } catch (err) {
            console.log('CartJS error: ' + err);
        }
    }
};

// Attach class .add2cart button functionality
document.body.addEventListener('click', function(e) {
    var t = e.target;
    if (t.classList.contains('add2cart')) {
        window.cart.addItem(
            t.getAttribute('data-itemid'),
            t.getAttribute('data-price'),
            t.getAttribute('data-title')
        );
    }
});
<|endoftext|>


<commit_before>var express = require('express'),
    superagent = require('superagent'),
    cheerio = require('cheerio'),
    eventproxy = require('eventproxy'),
    url = require('url');

var app = express();
var ep = new eventproxy();

app.get('/reptile', function(req, res, next) {
    var condeUrl = req.query.url;

    console.log(condeUrl);
    //爬取页面
    superagent.get(condeUrl)
    .end(function(err, sres) {
        if (err) {
            console.log(err.message);
        }

        var $ = cheerio.load(sres.text);
        var topicUrls = [];
        $('.topic_title').each(function() {
            var topicUrl = 'http://' + condeUrl + $(this).attr('href');
            topicUrls.push(topicUrl);
        });

        //监听40次回调
        ep.after('topic_html', topicUrls.length, function(topics) {
            console.log(topics);
        });

        topicUrls.forEach(function(topic) {
            superagent.get(topic)
            .end(function(err, data) {
                if (err) {
                    console.log(err.message);
                }
            });
        });
        res.send('ok');
    });
});

app.listen(3000, function() {
    console.log('reptile listen at port 3000!');
});<commit_msg>add retile<commit_after>var express = require('express'),
    superagent = require('superagent'),
    cheerio = require('cheerio'),
    eventproxy = require('eventproxy'),
    url = require('url');

var app = express();
var ep = new eventproxy();

app.get('/reptile', function(req, res, next) {
    var condeUrl = req.query.url;
    //爬取页面
    superagent.get(condeUrl)
    .end(function(err, sres) {
        if (err) {
            console.log('error is: ' + err.message);
        }

        var $ = cheerio.load(sres.text);
        var topicUrls = [];
        $('.topic_title').each(function() {
            var topicUrl = 'http://' + condeUrl + $(this).attr('href');
            topicUrls.push(topicUrl);
        });

        //监听40次回调
        ep.after('topic_html', topicUrls.length, function(topics) {
            var resArr = [];
            topics.forEach(function(topicObj) {
                var topicUrl = topicObj[0];
                var topicHtml = topicObj[1];
                var $ = cheerio.load(topicHtml);
                resArr.push({
                    'title': $('.topic_full_title').text().trim(),
                    'url': topicUrl,
                    'author1': $('.user_info').eq(0).find('.dark').text().trim(),
                    'comment1': $('.reply_content').eq(0).text().trim()
                });
            });

            res.send(resArr);
        });

        topicUrls.forEach(function(topicUrl) {
            superagent.get(topicUrl)
            .end(function(err, data) {
                if (err) {
                    console.log('error is: ' + err.message);
                    console.log('error url is: ' + topicUrl);
                }
                //发送一次emit
                ep.emit('topic_html', [topicUrl, data.text]);
            });
        });
    });
});

app.listen(3000, function() {
    console.log('reptile listen at port 3000!');
});<|endoftext|>


<commit_before>
exports.up = knex =>
  knex.schema.createTable('user', (table) => {
    table.increments('id');
    table.string('username').unique().notNullable();
    table.string('name');
    table.boolean('is_admin');
    table.timestamp('created_at').defaultTo(knex.fn.now());
    table.index('username');
  })
  .createTable('password', (table) => {
    table.increments('id');
    table.integer('user_id').references('user.id').notNullable().onDelete('CASCADE');
    table.string('password_hash').notNullable();
    table.timestamp('updated_at').defaultTo(knex.fn.now());
    table.boolean('valid').defaultsTo(true);
  })
  .createTable('email', (table) => {
    table.increments('id');
    table.integer('user_id').references('user.id').notNullable().onDelete('CASCADE');
    table.string('address').unique().notNullable();
    table.boolean('verified').defaultsTo(false);
  })
  .createTable('role', (table) => {
    table.increments('id');
    table.string('name').unique().notNullable();
  })
  .createTable('user_role', (table) => {
    table.integer('user_id').references('user.id').notNullable();
    table.integer('role_id').references('role.id').notNullable();
  });

exports.down = (knex, Promise) =>
  Promise.all([
    knex.schema.dropTable('user'),
    knex.schema.dropTable('password'),
    knex.schema.dropTable('email'),
    knex.schema.dropTable('role'),
    knex.schema.dropTable('user_role'),
  ]);
<commit_msg>Drop tables in correct order<commit_after>
exports.up = knex =>
  knex.schema.createTable('user', (table) => {
    table.increments('id');
    table.string('username').unique().notNullable();
    table.string('name');
    table.boolean('is_admin');
    table.timestamp('created_at').defaultTo(knex.fn.now());
    table.index('username');
  })
  .createTable('password', (table) => {
    table.increments('id');
    table.integer('user_id').references('user.id').notNullable().onDelete('CASCADE');
    table.string('password_hash').notNullable();
    table.timestamp('updated_at').defaultTo(knex.fn.now());
    table.boolean('valid').defaultsTo(true);
  })
  .createTable('email', (table) => {
    table.increments('id');
    table.integer('user_id').references('user.id').notNullable().onDelete('CASCADE');
    table.string('address').unique().notNullable();
    table.boolean('verified').defaultsTo(false);
  })
  .createTable('role', (table) => {
    table.increments('id');
    table.string('name').unique().notNullable();
  })
  .createTable('user_role', (table) => {
    table.integer('user_id').references('user.id').notNullable();
    table.integer('role_id').references('role.id').notNullable();
  });

exports.down = (knex, Promise) =>
  Promise.all([
    knex.schema.dropTable('password'),
    knex.schema.dropTable('email'),
    knex.schema.dropTable('user_role'),
    knex.schema.dropTable('role'),
    knex.schema.dropTable('user'),
  ]);
<|endoftext|>


<commit_before>// Load dependencies
var amanda = require('../../dist/latest.js');

/**
 * Test #1
 */
exports['Test #1'] = function(test) {

  var count = 0;

  var schema = {
    required: true,
    type: 'number',
    maximum: 10
  };

  [
    11,
    100,
    {},
    null,
    [],
    function() {},
    'Hello!'
  ].forEach(function(input) {
    amanda.validate(input, schema, function(error) {
      count += 1;
      test.ok(error);
    });
  });

  amanda.validate(10, schema, function(error) {
    count += 1;
    test.equal(error, undefined);
  });

  amanda.validate(2, schema, function(error) {
    count += 1;
    test.equal(error, undefined);
  });

  test.equal(count, 9);
  test.done();

};<commit_msg>Remove the obsolete ‘maximum’ test<commit_after><|endoftext|>


<commit_before>import localforage from 'localforage'

const namespace = 'settings'

export const fetchSettings = () => {
  return localforage.startsWith(namespace)
}

export const updateSettings = data => {
  return localforage.setItem(namespace, data)
}

/**
 * Returns all app data.
 * 1. Get all keys from IndexedDB as array
 * 2. Remove unwanted elements defined in blacklist
 * 3. Load items from IndexedDB and return as array with objects
 * 4. Turn array into single object
 */
export const getAllData = () => {
  const blackList = ['updated']
  return localforage.keys()
    .then(keys => keys.filter(k => !blackList.includes(k)))
    .then(keys => Promise.all(keys.map(key =>
      localforage.getItem(key).then(values => ({ key, values })))))
    .then(list => list.reduce((acc, current, index) => {
      acc[current.key] = current.values
      return acc
    }, {}))
}
<commit_msg>:bug: (data) Fix broken image exports in settings<commit_after>import localforage from 'localforage'
import blobUtil from 'blob-util'

const namespace = 'settings'

export const fetchSettings = () => {
  return localforage.startsWith(namespace)
}

export const updateSettings = data => {
  return localforage.setItem(namespace, data)
}

/**
 * Returns all app data.
 * 1. Get all keys from IndexedDB as array
 * 2. Remove unwanted elements defined in blacklist
 * 3. Load items from IndexedDB and return as array with objects
 * 4. Turn all blobs in plant data to base64 strings
 * 5. Turn array into single object
 */
export const getAllData = () => {
  const blackList = ['updated']

  return localforage.keys()
    .then(keys => keys.filter(k => !blackList.includes(k)))
    .then(keys => Promise.all(keys.map(key =>
      localforage.getItem(key).then(values => ({ key, values })))))
    .then(list => Promise.all(list.map(async item => {
      if (item.key.startsWith('plant-')) {
        item.values.blob = await blobUtil.blobToBase64String(item.values.blob)
      }
      return item
    })))
    .then(list => list.reduce((acc, current, index) => {
      acc[current.key] = current.values
      return acc
    }, {}))
}
<|endoftext|>


<commit_before>"use strict";

let React = require("react/addons");
let { Router, Route } = require("react-router");
let HashHistory = require("react-router/lib/HashHistory");

let AppComponent = require("./components/appComponent");
let Drugs = require("./components/drugs");
let DrugDetails = require("./components/drugDetails");
let LoginComponent = require("./components/loginComponent");
let auth = require("./security/auth");
let utils = require("./common/utils");

var isLoggedInGuard = utils.createGuardComponent.bind(this, () => auth.isLoggedIn());

window.onload = function () {
    // Facebook Authentication adds this value to the location hash
    if (window.location.hash.indexOf("_=_") > -1) {
        window.location.hash = "";
    }

    React.render((
        <Router history={new HashHistory()}>
            <Route path="/" component={isLoggedInGuard(AppComponent, { state: "login"})}>
                <Route path="drugs" component={Drugs}>
                    <Route path=":drugId" component={DrugDetails}/>
                </Route>
            </Route>
            <Route path="login" component={LoginComponent} />
        </Router>
    ), document.getElementById("app"));
};
<commit_msg>#97 - Setting the initial route when a user logs in to be /drugs<commit_after>"use strict";

let React = require("react/addons");
let { Router, Route, Redirect } = require("react-router");
let HashHistory = require("react-router/lib/HashHistory");

let AppComponent = require("./components/appComponent");
let Drugs = require("./components/drugs");
let DrugDetails = require("./components/drugDetails");
let LoginComponent = require("./components/loginComponent");
let auth = require("./security/auth");
let utils = require("./common/utils");

var isLoggedInGuard = utils.createGuardComponent.bind(this, () => auth.isLoggedIn());

window.onload = function () {
    // Facebook Authentication adds this value to the location hash
    if (window.location.hash.indexOf("_=_") > -1) {
        window.location.hash = "";
    }

    React.render((
        <Router history={new HashHistory()}>
            <Route component={isLoggedInGuard(AppComponent, { state: "login"})}>
                <Route path="drugs" component={Drugs}>
                    <Route path=":drugId" component={DrugDetails}/>
                </Route>
            </Route>
            <Route path="login" component={LoginComponent} />
            <Redirect from="/" to="/drugs" />
        </Router>
    ), document.getElementById("app"));
};
<|endoftext|>


<commit_before>'use strict'

var $ = require('jquery')

var utils = require('./utils')
var uiHelper = require('./ui-helper')

function Renderer (editor, web3, updateFiles, udapp, executionContext, formalVerificationEvent, compilerEvent) {
  this.editor = editor
  this.web3 = web3
  this.updateFiles = updateFiles
  this.udapp = udapp
  this.executionContext = executionContext
  var self = this
  formalVerificationEvent.register('compilationFinished', this, function (success, message, container, noAnnotations) {
    if (!success) {
      self.error(message, container, noAnnotations)
    }
  })
  compilerEvent.register('compilationFinished', this, function (success, data, source) {
    $('#output').empty()
    if (success) {
      self.contracts(data, source)
    }

    // NOTE: still need to display as there might be warnings
    if (data['error']) {
      self.error(data['error'])
    }
    if (data['errors']) {
      data['errors'].forEach(function (err) {
        self.error(err)
      })
    }
  })
}

Renderer.prototype.error = function (message, container, noAnnotations) {
  var self = this
  var type = utils.errortype(message)
  var $pre = $('
').text(message)
  var $error = $('

').prepend($pre)
  if (container === undefined) {
    container = $('#output')
  }
  container.append($error)
  var err = message.match(/^([^:]*):([0-9]*):(([0-9]*):)? /)
  if (err) {
    var errFile = err[1]
    var errLine = parseInt(err[2], 10) - 1
    var errCol = err[4] ? parseInt(err[4], 10) : 0
    if (!noAnnotations && (errFile === '' || errFile === utils.fileNameFromKey(self.editor.getCacheFile()))) {
      self.editor.addAnnotation({
        row: errLine,
        column: errCol,
        text: message,
        type: type
      })
    }
    $error.click(function (ev) {
      if (errFile !== '' && errFile !== utils.fileNameFromKey(self.editor.getCacheFile()) && self.editor.hasFile(errFile)) {
        // Switch to file
        self.editor.setCacheFile(utils.fileKey(errFile))
        self.updateFiles()
      // @TODO could show some error icon in files with errors
      }
      self.editor.handleErrorClick(errLine, errCol)
    })
    $error.find('.close').click(function (ev) {
      ev.preventDefault()
      $error.remove()
      return false
    })
  }
}

Renderer.prototype.contracts = function (data, source) {
  var udappContracts = []
  for (var contractName in data.contracts) {
    var contract = data.contracts[contractName]
    udappContracts.push({
      name: contractName,
      interface: contract['interface'],
      bytecode: contract.bytecode
    })
  }

  // rendering function used by udapp. they need data and source
  var combined = function (contractName, jsonInterface, bytecode) {
    return JSON.stringify([{ name: contractName, interface: jsonInterface, bytecode: bytecode }])
  }

  var renderOutputModifier = function (contractName, $contractOutput) {
    var contract = data.contracts[contractName]
    if (contract.bytecode) {
      $contractOutput.append(uiHelper.textRow('Bytecode', contract.bytecode))
    }

    $contractOutput.append(uiHelper.textRow('Interface', contract['interface']))

    if (contract.bytecode) {
      $contractOutput.append(uiHelper.textRow('Web3 deploy', uiHelper.gethDeploy(contractName.toLowerCase(), contract['interface'], contract.bytecode), 'deploy'))
      $contractOutput.append(uiHelper.textRow('uDApp', combined(contractName, contract['interface'], contract.bytecode), 'deploy'))
    }
    var ctrSource = getSource(contractName, source, data)
    return $contractOutput.append(uiHelper.getDetails(contract, ctrSource, contractName))
  }
  // //
  var self = this

  var getSource = function (contractName, source, data) {
    var currentFile = utils.fileNameFromKey(self.editor.getCacheFile())
    return source.sources[currentFile]
  }

  var getAddress = function (cb) {
    cb(null, $('#txorigin').val())
  }

  var getValue = function (cb) {
    try {
      var comp = $('#value').val().split(' ')
      cb(null, self.executionContext.web3().toWei(comp[0], comp.slice(1).join(' ')))
    } catch (e) {
      cb(e)
    }
  }

  var getGasLimit = function (cb) {
    cb(null, $('#gasLimit').val())
  }

  this.udapp.reset(udappContracts, getAddress, getValue, getGasLimit, renderOutputModifier)

  var $contractOutput = this.udapp.render()

  var $txOrigin = $('#txorigin')

  this.udapp.getAccounts(function (err, accounts) {
    if (err) {
      self.error(err.message)
    }
    if (accounts && accounts[0]) {
      $txOrigin.empty()
      for (var a in accounts) { $txOrigin.append($('<option />').val(accounts[a]).text(accounts[a])) }
      $txOrigin.val(accounts[0])
    } else {
      $txOrigin.val('unknown')
    }
  })

  $contractOutput.find('.title').click(function (ev) { $(this).closest('.contract').toggleClass('hide') })
  $('#output').append($contractOutput)
  $('.col2 input,textarea').click(function () { this.select() })
}

module.exports = Renderer
<commit_msg>Remove UDApp from the contract display<commit_after>'use strict'

var $ = require('jquery')

var utils = require('./utils')
var uiHelper = require('./ui-helper')

function Renderer (editor, web3, updateFiles, udapp, executionContext, formalVerificationEvent, compilerEvent) {
  this.editor = editor
  this.web3 = web3
  this.updateFiles = updateFiles
  this.udapp = udapp
  this.executionContext = executionContext
  var self = this
  formalVerificationEvent.register('compilationFinished', this, function (success, message, container, noAnnotations) {
    if (!success) {
      self.error(message, container, noAnnotations)
    }
  })
  compilerEvent.register('compilationFinished', this, function (success, data, source) {
    $('#output').empty()
    if (success) {
      self.contracts(data, source)
    }

    // NOTE: still need to display as there might be warnings
    if (data['error']) {
      self.error(data['error'])
    }
    if (data['errors']) {
      data['errors'].forEach(function (err) {
        self.error(err)
      })
    }
  })
}

Renderer.prototype.error = function (message, container, noAnnotations) {
  var self = this
  var type = utils.errortype(message)
  var $pre = $('
').text(message)
  var $error = $('

').prepend($pre)
  if (container === undefined) {
    container = $('#output')
  }
  container.append($error)
  var err = message.match(/^([^:]*):([0-9]*):(([0-9]*):)? /)
  if (err) {
    var errFile = err[1]
    var errLine = parseInt(err[2], 10) - 1
    var errCol = err[4] ? parseInt(err[4], 10) : 0
    if (!noAnnotations && (errFile === '' || errFile === utils.fileNameFromKey(self.editor.getCacheFile()))) {
      self.editor.addAnnotation({
        row: errLine,
        column: errCol,
        text: message,
        type: type
      })
    }
    $error.click(function (ev) {
      if (errFile !== '' && errFile !== utils.fileNameFromKey(self.editor.getCacheFile()) && self.editor.hasFile(errFile)) {
        // Switch to file
        self.editor.setCacheFile(utils.fileKey(errFile))
        self.updateFiles()
      // @TODO could show some error icon in files with errors
      }
      self.editor.handleErrorClick(errLine, errCol)
    })
    $error.find('.close').click(function (ev) {
      ev.preventDefault()
      $error.remove()
      return false
    })
  }
}

Renderer.prototype.contracts = function (data, source) {
  var udappContracts = []
  for (var contractName in data.contracts) {
    var contract = data.contracts[contractName]
    udappContracts.push({
      name: contractName,
      interface: contract['interface'],
      bytecode: contract.bytecode
    })
  }

  var renderOutputModifier = function (contractName, $contractOutput) {
    var contract = data.contracts[contractName]
    if (contract.bytecode) {
      $contractOutput.append(uiHelper.textRow('Bytecode', contract.bytecode))
    }

    $contractOutput.append(uiHelper.textRow('Interface', contract['interface']))

    if (contract.bytecode) {
      $contractOutput.append(uiHelper.textRow('Web3 deploy', uiHelper.gethDeploy(contractName.toLowerCase(), contract['interface'], contract.bytecode), 'deploy'))
    }
    var ctrSource = getSource(contractName, source, data)
    return $contractOutput.append(uiHelper.getDetails(contract, ctrSource, contractName))
  }

  var self = this

  var getSource = function (contractName, source, data) {
    var currentFile = utils.fileNameFromKey(self.editor.getCacheFile())
    return source.sources[currentFile]
  }

  var getAddress = function (cb) {
    cb(null, $('#txorigin').val())
  }

  var getValue = function (cb) {
    try {
      var comp = $('#value').val().split(' ')
      cb(null, self.executionContext.web3().toWei(comp[0], comp.slice(1).join(' ')))
    } catch (e) {
      cb(e)
    }
  }

  var getGasLimit = function (cb) {
    cb(null, $('#gasLimit').val())
  }

  this.udapp.reset(udappContracts, getAddress, getValue, getGasLimit, renderOutputModifier)

  var $contractOutput = this.udapp.render()

  var $txOrigin = $('#txorigin')

  this.udapp.getAccounts(function (err, accounts) {
    if (err) {
      self.error(err.message)
    }
    if (accounts && accounts[0]) {
      $txOrigin.empty()
      for (var a in accounts) { $txOrigin.append($('<option />').val(accounts[a]).text(accounts[a])) }
      $txOrigin.val(accounts[0])
    } else {
      $txOrigin.val('unknown')
    }
  })

  $contractOutput.find('.title').click(function (ev) { $(this).closest('.contract').toggleClass('hide') })
  $('#output').append($contractOutput)
  $('.col2 input,textarea').click(function () { this.select() })
}

module.exports = Renderer
<|endoftext|>


<commit_before>
var AWS    = require('aws-sdk'),
    bunyan = require('bunyan'),
    syslog = require('bunyan-syslog'),
    fs     = require('fs'),
    _      = require('underscore')

var timestamp = 0
var config = _.defaults(eval('c='+fs.readFileSync(process.argv[2])), {
  metrics:  [],
  backends: [],
  interval: 60,
})

AWS.config.update(config)
AWS.config.apiVersions = {
  cloudwatch: '2010-08-01',
}
var cloudwatch = new AWS.CloudWatch()

var backends = _.map(config.backends, function(spec, i) {
  backend = require(spec)
  if (!backend.init(config)) {
    console.log('[cloudwatch] failed to load backend', spec)
    process.exit(1)
  }
  return backend
})

function run() {
  var now = new Date()
  var start = timestamp
    ? new Date(timestamp)
    : new Date(now.getTime() - (config.interval * 1000))
  timestamp = now.getTime()

  _.each(config.metrics, function(m) {
    run_metric(m, start, now)
  })
}

function run_metric(metric, start, end) {
  var params = {
    Namespace: metric.Namespace,
    MetricName: metric.MetricName,
    StartTime: start.toISOString(),
    EndTime: end.toISOString(),
    Statistics: [metric.Statistic],
    Dimensions: metric.Dimensions || [],
    Period: '60',
    Unit: metric.Unit
  }

  console.log(params)

  cloudwatch.getMetricStatistics(params, function(error, response) {
    if (error) {
      return console.error("[cloudwatch] error:", error)
    }

    console.log(response)

    _.each(response.Datapoints, function(dp) {
      send_datapoint_to_backends(metric, dp)
    })
  })
}

function send_datapoint_to_backends(metric, dp) {
  var time = new Date(dp.Timestamp)
  var value = dp[metric.Statistic]

  _.each(backends, function(b) {
    send_datapoint_to_backend(b, time, metric, value)
  })
}

function send_datapoint_to_backend(backend, time, metric, value) {
  backend.send(time, metric, value)
}

run() || setInterval(run, config.interval * 1000)

process.title = 'cloudwatchd'
process.on('exit', function() {
  console.log('exiting')
})<commit_msg>Set process title before invoking cloudwatch<commit_after>
var AWS = require('aws-sdk'),
    fs  = require('fs'),
    _   = require('underscore')

var timestamp = 0
var config = _.defaults(eval('c='+fs.readFileSync(process.argv[2])), {
  metrics:  [],
  backends: [],
  interval: 60,
})

AWS.config.update(config)
AWS.config.apiVersions = {
  cloudwatch: '2010-08-01',
}
var cloudwatch = new AWS.CloudWatch()
var backends = _.map(config.backends, function(spec, i) {
  backend = require(spec)
  if (!backend.init(config)) {
    console.log('[cloudwatch] failed to load backend', spec)
    process.exit(1)
  }
  return backend
})

function run() {
  var now = new Date()
  var start = timestamp
    ? new Date(timestamp)
    : new Date(now.getTime() - (config.interval * 1000))
  timestamp = now.getTime()

  _.each(config.metrics, function(m) {
    run_metric(m, start, now)
  })
}

function run_metric(metric, start, end) {
  var params = {
    Namespace: metric.Namespace,
    MetricName: metric.MetricName,
    StartTime: start.toISOString(),
    EndTime: end.toISOString(),
    Statistics: [metric.Statistic],
    Dimensions: metric.Dimensions || [],
    Period: '60',
    Unit: metric.Unit
  }

  console.log(params)

  cloudwatch.getMetricStatistics(params, function(error, response) {
    if (error) {
      return console.error("[cloudwatch] error:", error)
    }

    console.log(response)

    _.each(response.Datapoints, function(dp) {
      send_datapoint_to_backends(metric, dp)
    })
  })
}

function send_datapoint_to_backends(metric, dp) {
  var time = new Date(dp.Timestamp)
  var value = dp[metric.Statistic]

  _.each(backends, function(b) {
    b.send(time, metric, value)
  })
}

process.title = 'cloudwatchd'
process.on('exit', function() {
  console.log('exiting')
})

run() || setInterval(run, config.interval * 1000)
<|endoftext|>


<commit_before>/**
 * Created by at15 on 2016/9/12.
 */
'use strict';

const Command = require('../lib/cli/command');
const logger = require('../lib/logger');
const render = require('../lib/template/render');

let renderCmd = new Command();
renderCmd.name = 'render';
renderCmd.description = 'render template to html with data from config file and markdown';
renderCmd.setFunc((app, args, flags) => {
    if (args.length === 0) {
        logger.debug('render using config');
        app.loadConfigOrExit();
        logger.error('not implemented');
        app.exit(1);
    }
    logger.info('try to render file', {file: args[0]});
    render.renderByFile(args[0], {title: 'abc'}).then((out)=> {
        logger.info(out);
    }).catch((e)=> {
        logger.error(e);
    });
});

module.exports = renderCmd;<commit_msg>[template] Add output flag for cmd/render<commit_after>/**
 * Created by at15 on 2016/9/12.
 */
'use strict';

const Command = require('../lib/cli/command');
const Flag = require('../lib/cli/flag');
const logger = require('../lib/logger');
const render = require('../lib/template/render');

let renderCmd = new Command();
renderCmd.name = 'render';
renderCmd.description = 'render template to html with data from config file and markdown';
renderCmd.setFunc((app, args, flags) => {
    if (args.length === 0) {
        logger.debug('render using config');
        app.loadConfigOrExit();
        logger.error('not implemented');
        app.exit(1);
    }
    logger.info('try to render file', {file: args[0]});
    render.renderByFile(args[0], {title: 'abc'}).then((out)=> {
        if (args.length === 1 || flags.o) {
            logger.info(out);
        }
        if (args.length == 2) {
            logger.warn('TODO: write output to file', {file: args[1]});
        }
    }).catch((e)=> {
        logger.error(e);
    });
});

// add flags
let outputFlag = new Flag('output', 'output content to console even if destination file is specified', false);
outputFlag.setAlias('o');
renderCmd.addFlag(outputFlag);

module.exports = renderCmd;<|endoftext|>


<commit_before>// Base BusinessProcess model

'use strict';

var memoize                   = require('memoizee/plain')
  , defineStringLine          = require('dbjs-ext/string/string-line')
  , defineUInteger            = require('dbjs-ext/number/integer/u-integer')
  , defineUrl                 = require('dbjs-ext/string/string-line/url')
  , _                         = require('mano').i18n.bind("Model: Business Process")
  , defineBusinessProcessBase = require('../lib/business-process-base')
  , defineNestedMap           = require('../lib/nested-map')
  , defineStatusLog           = require('../lib/status-log')
  , defineStatusHistoryItem   = require('../lib/status-history-item');

module.exports = memoize(function (db/*, options*/) {
	var options             = Object(arguments[1])
	  , BusinessProcessBase = defineBusinessProcessBase(db)
	  , StringLine          = defineStringLine(db)
	  , UInteger            = defineUInteger(db)
	  , Url                 = defineUrl(db)
	  , StatusLog           = defineStatusLog(db)
	  , StatusHistoryItem   = defineStatusHistoryItem(db)

	  , BusinessProcess;

	defineNestedMap(db);

	BusinessProcess = BusinessProcessBase.extend(options.className || 'BusinessProcess', {
		// General label of business process type
		// It's not specific per business process, but should provide general info as:
		// "Merchant registration", "Company registration" etc.
		label: { type: StringLine },

		// Should contain some action i.e. "start a company"
		registerServiceLabel: { type: StringLine },

		serviceDescription: { type: db.String },

		// General abbreviation of business process type
		// e.g. IT (Individual trader), C (Company), COI (Certificate of incentives)
		abbr: { type: StringLine },

		// Name of businessProcess
		// Usually computed from other properties
		businessName: { type: StringLine, label: _("Business name")  },

		// URL at which archive of files related to given business process
		// is accessible
		filesArchiveUrl: { type: Url },

		submissionNumber: { type: db.Object, nested: true },

		// Whether registration is made online
		// It may be overriden to false in case we import businessProces
		// which not processed electronically.
		// It has its use in "business update" applications where we allow updates
		// of old registrations done at the counter
		isFromEregistrations: { type: db.Boolean, value: true,
			label: _("Has registration been made online?") },

		// Whether business process was created for demo purposes
		isDemo: { type: db.Boolean, value: false },

		// String over which business processes can be searched
		// through interface panel (computed value is later indexed by persistence engine)
		searchString: { type: db.String, value: function (_observe) {
			var arr = [], submissionNumber = _observe(this.submissionNumber._value);
			if (this.businessName) arr.push(this.businessName.toLowerCase());
			if (submissionNumber) arr.push(submissionNumber.toLowerCase());
			return arr.join('\x02');
		} },

		// An array of email addresses used as notification recipients (to field).
		// Uses user and manager emails, if the exist, by default.
		notificationEmails: { type: StringLine, multiple: true, value: function (_observe) {
			var result = [];

			if (this.user) result.push(_observe(this.user._email));
			if (this.manager) result.push(_observe(this.manager._email));

			return result;
		} },
		toWebServiceJSON: {
			value: function (ignore) {
				var dataFields = {}, result, db;
				db = this.database;
				result = {
					id: this.__id__,
					service: {
						code: this.constructor.__id__
					},
					submittedTimestamp:
						this._isSubmitted.lastModified ?
								Math.floor(this._isSubmitted.lastModified / 1000) : null,
					processingSteps: {},
					request: {
						registrations: [],
						documentUploads: [],
						costs: [],
						payments: [],
						certificates: [],
						data: {}
					}
				};

				this.processingSteps.map.forEach(function self(processingStep) {
					if (db.ProcessingStepGroup && processingStep instanceof db.ProcessingStepGroup) {
						processingStep.steps.applicable.forEach(self);
						return;
					}
					result.processingSteps[processingStep.key] = processingStep.toWebServiceJSON();
				});

				this.registrations.requested.forEach(function (reg) {
					result.request.registrations.push({
						code: reg.key
					});
				});

				this.requirementUploads.applicable.forEach(function (upload) {
					result.request.documentUploads.push(upload.toWebServiceJSON());
				});

				this.costs.payable.forEach(function (cost) {
					result.request.costs.push(cost.toWebServiceJSON());
				});

				this.paymentReceiptUploads.applicable.forEach(function (payment) {
					result.request.payments.push(payment.toWebServiceJSON());
				});

				this.certificates.applicable.forEach(function (certificate) {
					result.request.certificates.push(certificate.toWebServiceJSON());
				});

				// toWebServiceJSON is not implemented on FormSectionBase
				if (this.database.FormSectionBase &&
						this.determinants.constructor !== this.database.FormSectionBase) {
					dataFields = this.determinants.toWebServiceJSON();
					Object.keys(dataFields).forEach(function (fieldName) {
						result.request.data[fieldName] = dataFields[fieldName];
					});
				}
				this.dataForms.applicable.forEach(function (section) {
					dataFields = section.toWebServiceJSON();
					Object.keys(dataFields).forEach(function (fieldName) {
						result.request.data[fieldName] = dataFields[fieldName];
					});
				});
				this.submissionForms.applicable.forEach(function (section) {
					dataFields = section.toWebServiceJSON();
					Object.keys(dataFields).forEach(function (fieldName) {
						result.request.data[fieldName] = dataFields[fieldName];
					});
				});

				return result;
			}
		},
		toMetaDataJSON: {
			type: db.Function,
			value: function (opts) {
				var fields = [];
				this.dataForms.map.forEach(function (section) {
					try {
						fields = fields.concat(section.toMetaDataJSON());
					} catch (ignore) {}
				});

				return fields;
			}
		},
		toWSSchema: {
			value: function (ignore) {
				var schema, db;
				db = this.database;
				schema = {
					typeName: this.constructor.__id__,
					properties: {
						id: { type: "string" },
						service: { type: "enum", ref: "services" },
						submittedTimestamp: { type: "timestamp" },
						processingSteps: { type: "object", properties: {} },
						request: {
							type: "object",
							properties: {
								registrations: {},
								documentUploads: {},
								costs: {},
								payments: {},
								certificates: {},
								data: {}
							}
						}
					}
				};

				this.processingSteps.map.forEach(function self(processingStep) {
					if (db.ProcessingStepGroup && processingStep instanceof db.ProcessingStepGroup) {
						processingStep.steps.map.forEach(self);
						return;
					}
					schema.properties.processingSteps.properties[processingStep.key] =
						processingStep.toWSSchema();
				});

				schema.properties.request.properties.registrations =
					this.registrations.map._descriptorPrototype_.type.prototype.toWSSchema();
				schema.properties.request.properties.costs =
					this.costs.map._descriptorPrototype_.type.prototype.toWSSchema();
				schema.properties.request.properties.certificates =
					this.certificates.map._descriptorPrototype_.type.prototype.toWSSchema();
				schema.properties.request.properties.documentUploads =
					this.requirementUploads.map._descriptorPrototype_.type.prototype.toWSSchema();
				schema.properties.request.properties.payments =
					this.paymentReceiptUploads.map._descriptorPrototype_.type.prototype.toWSSchema();

				schema.properties.request.properties.data = { type: "object", properties: {} };

				// guide
				// toWSSchema is not implemented on FormSectionBase
				if (db.FormSectionBase &&
						this.determinants.constructor !== db.FormSectionBase) {
					Object.assign(schema.properties.request.properties.data.properties,
						this.determinants.toWSSchema());
				}

				// dataForms
				this.dataForms.map.forEach(function (form) {
					if (db.FormSectionBase &&
							form.constructor !== db.FormSectionBase) {
						Object.assign(schema.properties.request.properties.data.properties,
							form.toWSSchema());
					}
				});

				//submissionForms
				this.submissionForms.map.forEach(function (form) {
					if (db.FormSectionBase &&
							form.constructor !== db.FormSectionBase) {
						Object.assign(schema.properties.request.properties.data.properties,
							form.toWSSchema());
					}
				});

				return schema;
			}
		}
	}, {
		draftLimit: { type: UInteger, value: 20 }
	});

	BusinessProcess.prototype.submissionNumber.defineProperties({
		// Stringified complete representation of number
		value: { type: StringLine, value: function () { return this.number; } },
		// Numeric part of number (usually incremented for each file)
		number: { type: UInteger, value: 0 },
		// Convinient stringification
		toString: { value: function (opts) { return this.value; } }
	});

	BusinessProcess.prototype.defineNestedMap('statusLog',
		{ itemType: StatusLog, cardinalPropertyKey: 'label' });

	BusinessProcess.prototype.defineNestedMap('statusHistory',
		{ itemType: StatusHistoryItem, cardinalPropertyKey: 'status' });

	return BusinessProcess;
}, { normalizer: require('memoizee/normalizers/get-1')() });
<commit_msg>switched to use prototype instead of instance<commit_after>// Base BusinessProcess model

'use strict';

var memoize                   = require('memoizee/plain')
  , defineStringLine          = require('dbjs-ext/string/string-line')
  , defineUInteger            = require('dbjs-ext/number/integer/u-integer')
  , defineUrl                 = require('dbjs-ext/string/string-line/url')
  , _                         = require('mano').i18n.bind("Model: Business Process")
  , defineBusinessProcessBase = require('../lib/business-process-base')
  , defineNestedMap           = require('../lib/nested-map')
  , defineStatusLog           = require('../lib/status-log')
  , defineStatusHistoryItem   = require('../lib/status-history-item');

module.exports = memoize(function (db/*, options*/) {
	var options             = Object(arguments[1])
	  , BusinessProcessBase = defineBusinessProcessBase(db)
	  , StringLine          = defineStringLine(db)
	  , UInteger            = defineUInteger(db)
	  , Url                 = defineUrl(db)
	  , StatusLog           = defineStatusLog(db)
	  , StatusHistoryItem   = defineStatusHistoryItem(db)

	  , BusinessProcess;

	defineNestedMap(db);

	BusinessProcess = BusinessProcessBase.extend(options.className || 'BusinessProcess', {
		// General label of business process type
		// It's not specific per business process, but should provide general info as:
		// "Merchant registration", "Company registration" etc.
		label: { type: StringLine },

		// Should contain some action i.e. "start a company"
		registerServiceLabel: { type: StringLine },

		serviceDescription: { type: db.String },

		// General abbreviation of business process type
		// e.g. IT (Individual trader), C (Company), COI (Certificate of incentives)
		abbr: { type: StringLine },

		// Name of businessProcess
		// Usually computed from other properties
		businessName: { type: StringLine, label: _("Business name")  },

		// URL at which archive of files related to given business process
		// is accessible
		filesArchiveUrl: { type: Url },

		submissionNumber: { type: db.Object, nested: true },

		// Whether registration is made online
		// It may be overriden to false in case we import businessProces
		// which not processed electronically.
		// It has its use in "business update" applications where we allow updates
		// of old registrations done at the counter
		isFromEregistrations: { type: db.Boolean, value: true,
			label: _("Has registration been made online?") },

		// Whether business process was created for demo purposes
		isDemo: { type: db.Boolean, value: false },

		// String over which business processes can be searched
		// through interface panel (computed value is later indexed by persistence engine)
		searchString: { type: db.String, value: function (_observe) {
			var arr = [], submissionNumber = _observe(this.submissionNumber._value);
			if (this.businessName) arr.push(this.businessName.toLowerCase());
			if (submissionNumber) arr.push(submissionNumber.toLowerCase());
			return arr.join('\x02');
		} },

		// An array of email addresses used as notification recipients (to field).
		// Uses user and manager emails, if the exist, by default.
		notificationEmails: { type: StringLine, multiple: true, value: function (_observe) {
			var result = [];

			if (this.user) result.push(_observe(this.user._email));
			if (this.manager) result.push(_observe(this.manager._email));

			return result;
		} },
		toWebServiceJSON: {
			value: function (ignore) {
				var dataFields = {}, result, db;
				db = this.database;
				result = {
					id: this.__id__,
					service: {
						code: this.constructor.__id__
					},
					submittedTimestamp:
						this._isSubmitted.lastModified ?
								Math.floor(this._isSubmitted.lastModified / 1000) : null,
					processingSteps: {},
					request: {
						registrations: [],
						documentUploads: [],
						costs: [],
						payments: [],
						certificates: [],
						data: {}
					}
				};

				this.processingSteps.map.forEach(function self(processingStep) {
					if (db.ProcessingStepGroup && processingStep instanceof db.ProcessingStepGroup) {
						processingStep.steps.applicable.forEach(self);
						return;
					}
					result.processingSteps[processingStep.key] = processingStep.toWebServiceJSON();
				});

				this.registrations.requested.forEach(function (reg) {
					result.request.registrations.push({
						code: reg.key
					});
				});

				this.requirementUploads.applicable.forEach(function (upload) {
					result.request.documentUploads.push(upload.toWebServiceJSON());
				});

				this.costs.payable.forEach(function (cost) {
					result.request.costs.push(cost.toWebServiceJSON());
				});

				this.paymentReceiptUploads.applicable.forEach(function (payment) {
					result.request.payments.push(payment.toWebServiceJSON());
				});

				this.certificates.applicable.forEach(function (certificate) {
					result.request.certificates.push(certificate.toWebServiceJSON());
				});

				// toWebServiceJSON is not implemented on FormSectionBase
				if (this.database.FormSectionBase &&
						this.determinants.constructor !== this.database.FormSectionBase) {
					dataFields = this.determinants.toWebServiceJSON();
					Object.keys(dataFields).forEach(function (fieldName) {
						result.request.data[fieldName] = dataFields[fieldName];
					});
				}
				this.dataForms.applicable.forEach(function (section) {
					dataFields = section.toWebServiceJSON();
					Object.keys(dataFields).forEach(function (fieldName) {
						result.request.data[fieldName] = dataFields[fieldName];
					});
				});
				this.submissionForms.applicable.forEach(function (section) {
					dataFields = section.toWebServiceJSON();
					Object.keys(dataFields).forEach(function (fieldName) {
						result.request.data[fieldName] = dataFields[fieldName];
					});
				});

				return result;
			}
		},
		toMetaDataJSON: {
			type: db.Function,
			value: function (opts) {
				var fields = [];
				this.dataForms.map.forEach(function (section) {
					try {
						fields = fields.concat(section.toMetaDataJSON());
					} catch (ignore) {}
				});

				return fields;
			}
		},
		toWSSchema: {
			value: function (ignore) {
				var schema, db;
				db = this.database;
				schema = {
					typeName: this.constructor.__id__,
					properties: {
						id: { type: "string" },
						service: { type: "enum", ref: "services" },
						submittedTimestamp: { type: "timestamp" },
						processingSteps: { type: "object", properties: {} },
						request: {
							type: "object",
							properties: {
								registrations: {},
								documentUploads: {},
								costs: {},
								payments: {},
								certificates: {},
								data: {}
							}
						}
					}
				};

				this.constructor.prototype.processingSteps.map.forEach(function self(processingStep) {
					if (db.ProcessingStepGroup && processingStep instanceof db.ProcessingStepGroup) {
						processingStep.steps.map.forEach(self);
						return;
					}
					schema.properties.processingSteps.properties[processingStep.key] =
						processingStep.toWSSchema();
				});

				schema.properties.request.properties.registrations =
					this.registrations.map._descriptorPrototype_.type.prototype.toWSSchema();
				schema.properties.request.properties.costs =
					this.costs.map._descriptorPrototype_.type.prototype.toWSSchema();
				schema.properties.request.properties.certificates =
					this.certificates.map._descriptorPrototype_.type.prototype.toWSSchema();
				schema.properties.request.properties.documentUploads =
					this.requirementUploads.map._descriptorPrototype_.type.prototype.toWSSchema();
				schema.properties.request.properties.payments =
					this.paymentReceiptUploads.map._descriptorPrototype_.type.prototype.toWSSchema();

				schema.properties.request.properties.data = { type: "object", properties: {} };

				// guide
				// toWSSchema is not implemented on FormSectionBase
				if (db.FormSectionBase &&
						this.determinants.constructor !== db.FormSectionBase) {
					Object.assign(schema.properties.request.properties.data.properties,
						this.constructor.prototype.determinants.toWSSchema());
				}

				// dataForms
				this.constructor.prototype.dataForms.map.forEach(function (form) {
					if (db.FormSectionBase &&
							form.constructor !== db.FormSectionBase) {
						Object.assign(schema.properties.request.properties.data.properties,
							form.toWSSchema());
					}
				});

				//submissionForms
				this.constructor.prototype.submissionForms.map.forEach(function (form) {
					if (db.FormSectionBase &&
							form.constructor !== db.FormSectionBase) {
						Object.assign(schema.properties.request.properties.data.properties,
							form.toWSSchema());
					}
				});

				return schema;
			}
		}
	}, {
		draftLimit: { type: UInteger, value: 20 }
	});

	BusinessProcess.prototype.submissionNumber.defineProperties({
		// Stringified complete representation of number
		value: { type: StringLine, value: function () { return this.number; } },
		// Numeric part of number (usually incremented for each file)
		number: { type: UInteger, value: 0 },
		// Convinient stringification
		toString: { value: function (opts) { return this.value; } }
	});

	BusinessProcess.prototype.defineNestedMap('statusLog',
		{ itemType: StatusLog, cardinalPropertyKey: 'label' });

	BusinessProcess.prototype.defineNestedMap('statusHistory',
		{ itemType: StatusHistoryItem, cardinalPropertyKey: 'status' });

	return BusinessProcess;
}, { normalizer: require('memoizee/normalizers/get-1')() });
<|endoftext|>


<commit_before>// Base BusinessProcess model

'use strict';

var memoize                   = require('memoizee/plain')
  , defineStringLine          = require('dbjs-ext/string/string-line')
  , defineUInteger            = require('dbjs-ext/number/integer/u-integer')
  , defineUrl                 = require('dbjs-ext/string/string-line/url')
  , _                         = require('mano').i18n.bind("Model: Business Process")
  , defineBusinessProcessBase = require('../lib/business-process-base')
  , defineNestedMap           = require('../lib/nested-map')
  , defineStatusLog           = require('../lib/status-log');

module.exports = memoize(function (db/*, options*/) {
	var options             = Object(arguments[1])
	  , BusinessProcessBase = defineBusinessProcessBase(db)
	  , StringLine          = defineStringLine(db)
	  , UInteger            = defineUInteger(db)
	  , Url                 = defineUrl(db)
	  , StatusLog           = defineStatusLog(db)

	  , BusinessProcess;

	defineNestedMap(db);

	BusinessProcess = BusinessProcessBase.extend(options.className || 'BusinessProcess', {
		// General label of business process type
		// It's not specific per business process, but should provide general info as:
		// "Merchant registration", "Company registration" etc.
		label: { type: StringLine },

		// General abbreviation of business process type
		// e.g. IT (Individual trader), C (Company), COI (Certificate of incentives)
		abbr: { type: StringLine },

		// Name of businessProcess
		// Usually computed from other properties
		businessName: { type: StringLine },

		// URL at which archive of files related to given business process
		// is accessible
		filesArchiveUrl: { type: Url },

		submissionNumber: { type: db.Object, nested: true },

		// Whether registration is made online
		// It may be overriden to false in case we import businessProces
		// which not processed electronically.
		// It has its use in "business update" applications where we allow updates
		// of old registrations done at the counter
		isFromEregistrations: { type: db.Boolean, value: true,
			label: _("Has registration been made online?") },

		// String over which business processes can be searched
		// through interface panel (computed value is later indexed by persistence engine)
		searchString: { type: db.String, value: function (_observe) {
			var arr = [], submissionNumber = _observe(this.submissionNumber._value);
			if (this.businessName) arr.push(this.businessName.toLowerCase());
			if (submissionNumber) arr.push(submissionNumber.toLowerCase());
			return arr.join('\x02');
		} },

		// An array of email addresses used as notification recipients (to field).
		// Uses user and manager emails, if the exist, by default.
		notificationEmails: { type: StringLine, multiple: true, value: function (_observe) {
			var result = [];

			if (this.user) result.push(_observe(this.user._email));
			if (this.manager) result.push(_observe(this.manager._email));

			return result;
		} }
	});

	BusinessProcess.prototype.submissionNumber.defineProperties({
		// Stringified complete representation of number
		value: { type: StringLine, value: function () { return this.number; } },
		// Numeric part of number (usually incremented for each file)
		number: { type: UInteger, value: 0 },
		// Convinient stringification
		toString: { value: function (opts) { return this.value; } }
	});

	BusinessProcess.prototype.defineNestedMap('statusLog',
		{ itemType: StatusLog, cardinalPropertyKey: 'label' });

	return BusinessProcess;
}, { normalizer: require('memoizee/normalizers/get-1')() });
<commit_msg>Define isDemo property<commit_after>// Base BusinessProcess model

'use strict';

var memoize                   = require('memoizee/plain')
  , defineStringLine          = require('dbjs-ext/string/string-line')
  , defineUInteger            = require('dbjs-ext/number/integer/u-integer')
  , defineUrl                 = require('dbjs-ext/string/string-line/url')
  , _                         = require('mano').i18n.bind("Model: Business Process")
  , defineBusinessProcessBase = require('../lib/business-process-base')
  , defineNestedMap           = require('../lib/nested-map')
  , defineStatusLog           = require('../lib/status-log');

module.exports = memoize(function (db/*, options*/) {
	var options             = Object(arguments[1])
	  , BusinessProcessBase = defineBusinessProcessBase(db)
	  , StringLine          = defineStringLine(db)
	  , UInteger            = defineUInteger(db)
	  , Url                 = defineUrl(db)
	  , StatusLog           = defineStatusLog(db)

	  , BusinessProcess;

	defineNestedMap(db);

	BusinessProcess = BusinessProcessBase.extend(options.className || 'BusinessProcess', {
		// General label of business process type
		// It's not specific per business process, but should provide general info as:
		// "Merchant registration", "Company registration" etc.
		label: { type: StringLine },

		// General abbreviation of business process type
		// e.g. IT (Individual trader), C (Company), COI (Certificate of incentives)
		abbr: { type: StringLine },

		// Name of businessProcess
		// Usually computed from other properties
		businessName: { type: StringLine },

		// URL at which archive of files related to given business process
		// is accessible
		filesArchiveUrl: { type: Url },

		submissionNumber: { type: db.Object, nested: true },

		// Whether registration is made online
		// It may be overriden to false in case we import businessProces
		// which not processed electronically.
		// It has its use in "business update" applications where we allow updates
		// of old registrations done at the counter
		isFromEregistrations: { type: db.Boolean, value: true,
			label: _("Has registration been made online?") },

		// Whether business process was created for demo purposes
		isDemo: { type: db.Boolean, value: false },

		// String over which business processes can be searched
		// through interface panel (computed value is later indexed by persistence engine)
		searchString: { type: db.String, value: function (_observe) {
			var arr = [], submissionNumber = _observe(this.submissionNumber._value);
			if (this.businessName) arr.push(this.businessName.toLowerCase());
			if (submissionNumber) arr.push(submissionNumber.toLowerCase());
			return arr.join('\x02');
		} },

		// An array of email addresses used as notification recipients (to field).
		// Uses user and manager emails, if the exist, by default.
		notificationEmails: { type: StringLine, multiple: true, value: function (_observe) {
			var result = [];

			if (this.user) result.push(_observe(this.user._email));
			if (this.manager) result.push(_observe(this.manager._email));

			return result;
		} }
	});

	BusinessProcess.prototype.submissionNumber.defineProperties({
		// Stringified complete representation of number
		value: { type: StringLine, value: function () { return this.number; } },
		// Numeric part of number (usually incremented for each file)
		number: { type: UInteger, value: 0 },
		// Convinient stringification
		toString: { value: function (opts) { return this.value; } }
	});

	BusinessProcess.prototype.defineNestedMap('statusLog',
		{ itemType: StatusLog, cardinalPropertyKey: 'label' });

	return BusinessProcess;
}, { normalizer: require('memoizee/normalizers/get-1')() });
<|endoftext|>


<commit_before>var mmdbreader = require('maxmind-db-reader');

// get databases files from http://dev.maxmind.com/geoip/geoip2/geolite2/ and rename them to city and country respectively

// country database
mmdbreader.open('./country.mmdb',function(err,countries){
    // get geodata
    countries.getGeoData('128.101.101.101',function(err,geodata){
        // log data
        console.log(geodata);
    });
});

// city database
mmdbreader.open('./city.mmdb',function(err,cities){
    // get geodata
    cities.getGeoData('128.101.101.101',function(err,geodata){
        // log data
        console.log(geodata);
    });
});<commit_msg>using singular file for city and country<commit_after>var mmdbreader = require('maxmind-db-reader');

// get databases files from http://dev.maxmind.com/geoip/geoip2/geolite2/ and rename them to city and country respectively

// city database
mmdbreader.open('./city.mmdb', function(err, cities) {
    cities.getGeoData('128.101.101.101', function(err, geodata) {
        var result = {
            city: geodata.city.names.en,
            country: geodata.country.names.en
        }
        console.log(result);
    });
});
<|endoftext|>