<commit_before>'use strict'

// external deps
var ObjectId = require("mongodb").ObjectId;
var BaseManager = require('../base-manager');

// internal deps
require('mongodb-toolkit');
var DLModels = require('dl-models');
var map = DLModels.map;
var DeliveryOrder = DLModels.purchasing.DeliveryOrder;

// var PurchaseOrderBaseManager = require('../po/purchase-order-base-manager');
// var DOItem = DLModels.po.DOItem;

module.exports = class DeliveryOrderManager extends BaseManager {
    constructor(db, user) {
        super(db, user);
        this.collection = this.db.use(map.purchasing.collection.DeliveryOrder);
    }

    _getQuery(paging) {
        var deleted = {
            _deleted: false
        };
        var query = paging.keyword ? {
            '$and': [deleted]
        } : deleted;

        if (paging.keyword) {
            var regex = new RegExp(paging.keyword, "i");
            var filteNO = {
                'no': {
                    '$regex': regex
                }
            };
            var filterNRefNo = {
                'refNo': {
                    '$regex': regex
                }
            };
            var filterSupplierName = {
                'supplier.name': {
                    '$regex': regex
                }
            };

            var $or = {
                '$or': [filteNO, filterNRefNo,filterSupplierName]
            };

            query['$and'].push($or);
        }
        return query;
    }

    post(deliveryOrder) {
        return new Promise((resolve, reject) => {
            this._validate(deliveryOrder)
                .then(validDeliveryOrder => {
                    validDeliveryOrder.isPosted = true;
                    this.collection.update(validDeliveryOrder)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        });
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    _validate(deliveryOrder) {
        var errors = {};
        return new Promise((resolve, reject) => {
            var valid = deliveryOrder;

            var getDeliveryOrderPromise = this.collection.singleOrDefault({
                "$and": [{
                    _id: {
                        '$ne': new ObjectId(valid._id)
                    }
                }, {
                        no: valid.no
                    }]
            });
            // 1. end: Declare promises.

            // 2. begin: Validation.
            Promise.all([getDeliveryOrderPromise])
                .then(results => {
                    var _module = results[0];
                    var now = new Date();
                    if (_module) {
                        if (_module.supplier.name == valid.supplier.name)
                            errors["no"] = "Nomor surat jalan sudah terdaftar";
                    }
                    else if (!valid.no || valid.no == '')
                        errors["no"] = "Nomor surat jalan tidak boleh kosong";

                    if (!valid.date || valid.date == '')
                        errors["date"] = "Tanggal surat jalan tidak boleh kosong";
                    else if (valid.date > now)
                        errors["SJDate"] = "Tanggal surat jalan tidak boleh lebih besar dari tanggal hari ini";

                    // if (!valid.productArriveDate || valid.productArriveDate == '')
                    //     errors["productArriveDate"] = "Tanggal datang barang tidak boleh kosong";
                    // else if (valid.productArriveDate > now)
                    //     errors["productArriveDate"] = "Tanggal datang barang tidak boleh lebih besar dari tanggal hari ini";
                    // else if (valid.productArriveDate < valid.SJDate)
                    //     errors["productArriveDate"] = "Tanggal datang barang tidak boleh lebih kecil dari tanggal surat jalan";

                    if (!valid.supplierId)
                        errors["supplierId"] = "SupplierId tidak boleh kosong";
                    if (!valid.supplier.name || valid.supplier.name == '')
                        errors["supplier"] = "Supplier tidak boleh kosong";

                    // if (!valid.deliveryType || valid.deliveryType == '')
                    //     errors["deliveryType"] = "Jenis Pengiriman tidak boleh kosong";

                    // if (valid.deliveryType != 'Lokal')
                    //     if (!valid.deliveryNo || valid.deliveryNo == '')
                    //         errors["deliveryNo"] = "Nomor Penggiriman tidak boleh kosong";

                    // if (valid.items.length > 0) {
                    //     var itemErrors = [];
                    //     for (var item of valid.items) {
                    //         var itemError = {};

                    //         if (poItem.dealQuantity < poItem.realizationQuantity)
                    //             itemError["realizationQuantity"] = "Jumlah barang di SJ tidak boleh lebih besar dari jumlah barang di PO"
                    //         itemErrors.push(itemError);
                    //     }
                    //     for (var itemError of itemErrors) {
                    //         for (var prop in itemError) {
                    //             errors.items = itemErrors;
                    //             break;
                    //         }
                    //         if (errors.items)
                    //             break;
                    //     }

                    // }
                    // else
                    if (valid.items.length <= 0) {
                        errors["items"] = "Harus ada minimal 1 nomor PO";
                    }

                    // 2c. begin: check if data has any error, reject if it has.
                    for (var prop in errors) {
                        var ValidationError = require('../../validation-error');
                        reject(new ValidationError('data does not pass validation', errors));
                    }

                    if (!valid.stamp)
                        valid = new DeliveryOrder(valid);

                    valid.stamp(this.user.username, 'manager');
                    resolve(valid);
                })
                .catch(e => {
                    reject(e);
                })
        });
    }

}<commit_msg>add function getDataDeliveryOrder in delivery-order-manager<commit_after>'use strict'

// external deps
var ObjectId = require("mongodb").ObjectId;
var BaseManager = require('../base-manager');

// internal deps
require('mongodb-toolkit');
var DLModels = require('dl-models');
var map = DLModels.map;
var DeliveryOrder = DLModels.purchasing.DeliveryOrder;

// var PurchaseOrderBaseManager = require('../po/purchase-order-base-manager');
// var DOItem = DLModels.po.DOItem;

module.exports = class DeliveryOrderManager extends BaseManager {
    constructor(db, user) {
        super(db, user);
        this.collection = this.db.use(map.purchasing.collection.DeliveryOrder);
    }

    _getQuery(paging) {
        var deleted = {
            _deleted: false
        };
        var query = paging.keyword ? {
            '$and': [deleted]
        } : deleted;

        if (paging.keyword) {
            var regex = new RegExp(paging.keyword, "i");
            var filteNO = {
                'no': {
                    '$regex': regex
                }
            };
            var filterNRefNo = {
                'refNo': {
                    '$regex': regex
                }
            };
            var filterSupplierName = {
                'supplier.name': {
                    '$regex': regex
                }
            };

            var $or = {
                '$or': [filteNO, filterNRefNo,filterSupplierName]
            };

            query['$and'].push($or);
        }
        return query;
    }

    post(deliveryOrder) {
        return new Promise((resolve, reject) => {
            this._validate(deliveryOrder)
                .then(validDeliveryOrder => {
                    validDeliveryOrder.isPosted = true;
                    this.collection.update(validDeliveryOrder)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        });
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    _validate(deliveryOrder) {
        var errors = {};
        return new Promise((resolve, reject) => {
            var valid = deliveryOrder;

            var getDeliveryOrderPromise = this.collection.singleOrDefault({
                "$and": [{
                    _id: {
                        '$ne': new ObjectId(valid._id)
                    }
                }, {
                        no: valid.no
                    }]
            });
            // 1. end: Declare promises.

            // 2. begin: Validation.
            Promise.all([getDeliveryOrderPromise])
                .then(results => {
                    var _module = results[0];
                    var now = new Date();
                    if (_module) {
                        if (_module.supplier.name == valid.supplier.name)
                            errors["no"] = "Nomor surat jalan sudah terdaftar";
                    }
                    else if (!valid.no || valid.no == '')
                        errors["no"] = "Nomor surat jalan tidak boleh kosong";

                    if (!valid.date || valid.date == '')
                        errors["date"] = "Tanggal surat jalan tidak boleh kosong";
                    else if (valid.date > now)
                        errors["SJDate"] = "Tanggal surat jalan tidak boleh lebih besar dari tanggal hari ini";

                    // if (!valid.productArriveDate || valid.productArriveDate == '')
                    //     errors["productArriveDate"] = "Tanggal datang barang tidak boleh kosong";
                    // else if (valid.productArriveDate > now)
                    //     errors["productArriveDate"] = "Tanggal datang barang tidak boleh lebih besar dari tanggal hari ini";
                    // else if (valid.productArriveDate < valid.SJDate)
                    //     errors["productArriveDate"] = "Tanggal datang barang tidak boleh lebih kecil dari tanggal surat jalan";

                    if (!valid.supplierId)
                        errors["supplierId"] = "SupplierId tidak boleh kosong";
                    if (!valid.supplier.name || valid.supplier.name == '')
                        errors["supplier"] = "Supplier tidak boleh kosong";

                    // if (!valid.deliveryType || valid.deliveryType == '')
                    //     errors["deliveryType"] = "Jenis Pengiriman tidak boleh kosong";

                    // if (valid.deliveryType != 'Lokal')
                    //     if (!valid.deliveryNo || valid.deliveryNo == '')
                    //         errors["deliveryNo"] = "Nomor Penggiriman tidak boleh kosong";

                    // if (valid.items.length > 0) {
                    //     var itemErrors = [];
                    //     for (var item of valid.items) {
                    //         var itemError = {};

                    //         if (poItem.dealQuantity < poItem.realizationQuantity)
                    //             itemError["realizationQuantity"] = "Jumlah barang di SJ tidak boleh lebih besar dari jumlah barang di PO"
                    //         itemErrors.push(itemError);
                    //     }
                    //     for (var itemError of itemErrors) {
                    //         for (var prop in itemError) {
                    //             errors.items = itemErrors;
                    //             break;
                    //         }
                    //         if (errors.items)
                    //             break;
                    //     }

                    // }
                    // else
                    if (valid.items.length <= 0) {
                        errors["items"] = "Harus ada minimal 1 nomor PO";
                    }

                    // 2c. begin: check if data has any error, reject if it has.
                    for (var prop in errors) {
                        var ValidationError = require('../../validation-error');
                        reject(new ValidationError('data does not pass validation', errors));
                    }

                    if (!valid.stamp)
                        valid = new DeliveryOrder(valid);

                    valid.stamp(this.user.username, 'manager');
                    resolve(valid);
                })
                .catch(e => {
                    reject(e);
                })
        });
    }
    getDataDeliveryOrder(no, supplierId, dateFrom, dateTo) {
        return new Promise((resolve, reject) => {
            var query;
             if ( no != "undefined" && no != ""   && supplierId != "undefined" && supplierId!="" && dateFrom != "undefined" && dateFrom !="" && dateTo != "undefined" && dateTo !="") {
                query = {
                    no: no,
                    supplierId: supplierId,
                    date:
                    {
                        $gte: new Date(dateFrom),
                        $lte: new Date(dateTo)
                    },
                    _deleted: false
                };
            } else if  ( no != "undefined" && no != ""  &&  supplierId != "undefined" && supplierId!="") {
                query = {
                    no: no,
                    supplierId: supplierId,
                    _deleted: false
                };
            }  else if  (no != "undefined" && no != "") {
                query = {
                    no: no,
                    _deleted: false
                };
            }   else if  (dateFrom != "undefined" && dateFrom !="" && dateTo != "undefined" && dateTo !="") {
                query = {
                    date:
                    {
                        $gte: new Date(dateFrom),
                        $lte: new Date(dateTo)
                    },
                    _deleted: false
                };
            }

           this.collection
                .where(query)
                .execute()
                .then(PurchaseOrder => {
                    resolve(PurchaseOrder);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

}<|endoftext|>


<commit_before>/**
 * Created by sbardian on 5/16/17.
 */

import React from 'react';
import PropTypes from 'prop-types';
import utils from '../utils/utils';
import QuestionWrapper from './components/QuestionWrapper';

export default class OpenTrivia extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      loading: true,
      results: [{}],
      index: 0,
    }
  }

  nextQuestion () {
    this.setState({
      index: this.state.index++
    })
  }

  prevQuestion () {
    this.setState({
      index: this.state.index--
    })
  }

  componentWillMount () {
    const {
      amount,
      category,
      difficulty,
      type,
      encode,
      getToken
    } = this.props;
    const options = {
      amount: amount,
      category: category,
      difficulty: difficulty,
      type: type,
      encode: encode,
      getToken: getToken,
    }
    utils.getQuestions(options)
        .then((results) => {
          console.log('index results ', results);
          this.setState({
            results,
            loading: false,
          });
        });
  }

  render () {
    // TODO: foreach question, if multi or bool call multi wrapper or bool question
    return this.state.loading === true
        ?

Loading Question. . .

        :

            <QuestionWrapper question={this.state.results[this.state.index]} loading={this.state.loading} />

  }
}

OpenTrivia.propTypes = {
  // set default props the component will expect
  loading: PropTypes.bool,
  amount: PropTypes.number,
  category: PropTypes.number,
  difficulty: PropTypes.string,
  type: PropTypes.string,
  encode: PropTypes.string,
  getToken: PropTypes.bool,
};

OpenTrivia.defaultProps = {
  // set value of default props
  loading: true,
  results: [{}],
};<commit_msg>Remove TODOs and console log.<commit_after>/**
 * Created by sbardian on 5/16/17.
 */

import React from 'react';
import PropTypes from 'prop-types';
import utils from '../utils/utils';
import QuestionWrapper from './components/QuestionWrapper';

export default class OpenTrivia extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      loading: true,
      results: [{}],
      index: 0,
    }
  }

  nextQuestion () {
    this.setState({
      index: this.state.index++
    })
  }

  prevQuestion () {
    this.setState({
      index: this.state.index--
    })
  }

  componentWillMount () {
    const {
      amount,
      category,
      difficulty,
      type,
      encode,
      getToken
    } = this.props;
    const options = {
      amount: amount,
      category: category,
      difficulty: difficulty,
      type: type,
      encode: encode,
      getToken: getToken,
    }
    utils.getQuestions(options)
        .then((results) => {
          this.setState({
            results,
            loading: false,
          });
        });
  }

  render () {
    return this.state.loading === true
        ?

Loading Question. . .

        :

            <QuestionWrapper question={this.state.results[this.state.index]} loading={this.state.loading} />

  }
}

OpenTrivia.propTypes = {
  // set default props the component will expect
  loading: PropTypes.bool,
  amount: PropTypes.number,
  category: PropTypes.number,
  difficulty: PropTypes.string,
  type: PropTypes.string,
  encode: PropTypes.string,
  getToken: PropTypes.bool,
};

OpenTrivia.defaultProps = {
  // set value of default props
  loading: true,
  results: [{}],
};<|endoftext|>


<commit_before>/* global URL, Blob */

var airplay = require('airplay-js')
var chromecasts = require('chromecasts')()
var createTorrent = require('create-torrent')
var dragDrop = require('drag-drop')
var electron = require('electron')
var EventEmitter = require('events')
var mainLoop = require('main-loop')
var networkAddress = require('network-address')
var path = require('path')
var state = require('./state')
var torrentPoster = require('./lib/torrent-poster')
var WebTorrent = require('webtorrent')
var cfg = require('application-config')('WebTorrent')

var createElement = require('virtual-dom/create-element')
var diff = require('virtual-dom/diff')
var patch = require('virtual-dom/patch')

var App = require('./views/app')

// Force use of webtorrent trackers on all torrents
global.WEBTORRENT_ANNOUNCE = createTorrent.announceList
  .map(function (arr) {
    return arr[0]
  })
  .filter(function (url) {
    return url.indexOf('wss://') === 0 || url.indexOf('ws://') === 0
  })

var vdomLoop

/**
 * Called once when the application loads. (Not once per window.)
 * Connects to the torrent networks, sets up the UI and OS integrations like
 * the dock icon and drag+drop.
 */
function init () {
  // Connect to the WebTorrent and BitTorrent networks
  // WebTorrent.app is a hybrid client, as explained here: https://webtorrent.io/faq
  state.client = new WebTorrent()
  state.client.on('warning', onWarning)
  state.client.on('error', onError)

  // The UI is built with virtual-dom, a minimalist library extracted from React
  // The concepts--one way data flow, a pure function that renders state to a
  // virtual DOM tree, and a diff that applies changes in the vdom to the real
  // DOM, are all the same. Learn more: https://facebook.github.io/react/
  vdomLoop = mainLoop(state, render, {
    create: createElement,
    diff: diff,
    patch: patch
  })
  document.body.appendChild(vdomLoop.target)

  // Calling update() updates the UI given the current state
  // Do this at least once a second to show latest state for each torrent
  // (eg % downloaded) and to keep the cursor in sync when playing a video
  setInterval(update, 1000)

  // All state lives in state.js. `state.saved` is read from and written to a
  // file. All other state is ephemeral. Here we'll load state.saved:
  loadState()
  document.addEventListener('unload', saveState)

  // For easy debugging in Developer Tools
  global.state = state

  // OS integrations:
  // ...Chromecast and Airplay
  chromecasts.on('update', function (player) {
    state.devices.chromecast = player
    update()
  })

  airplay.createBrowser().on('deviceOn', function (player) {
    state.devices.airplay = player
  }).start()

  // ...drag and drop a torrent or video file to play or seed
  dragDrop('body', onFiles)

  // ...same thing if you paste a torrent
  document.addEventListener('paste', function () {
    electron.ipcRenderer.send('addTorrentFromPaste')
  })

  // ...keyboard shortcuts
  document.addEventListener('keydown', function (e) {
    if (e.which === 27) { /* ESC means either exit fullscreen or go back */
      if (state.isFullScreen) {
        dispatch('toggleFullScreen')
      } else {
        dispatch('back')
      }
    }
  })

  // ...focus and blur. Needed to show correct dock icon text ("badge") in OSX
  window.addEventListener('focus', function () {
    state.isFocused = true
    if (state.dock.badge > 0) electron.ipcRenderer.send('setBadge', '')
    state.dock.badge = 0
  })

  window.addEventListener('blur', function () {
    state.isFocused = false
  })
}
init()

// This is the (mostly) pure funtion from state -> UI. Returns a virtual DOM
// tree. Any events, such as button clicks, will turn into calls to dispatch()
function render (state) {
  return App(state, dispatch)
}

// Calls render() to go from state -> UI, then applies to vdom to the real DOM.
function update () {
  vdomLoop.update(state)
  updateDockIcon()
}

// Events from the UI never modify state directly. Instead they call dispatch()
function dispatch (action, ...args) {
  console.log('dispatch: %s %o', action, args)
  if (action === 'addTorrent') {
    addTorrent(args[0] /* torrentId */)
  }
  if (action === 'seed') {
    seed(args[0] /* files */)
  }
  if (action === 'openPlayer') {
    openPlayer(args[0] /* torrent */)
  }
  if (action === 'deleteTorrent') {
    deleteTorrent(args[0] /* torrent */)
  }
  if (action === 'openChromecast') {
    openChromecast(args[0] /* torrent */)
  }
  if (action === 'openAirplay') {
    openAirplay(args[0] /* torrent */)
  }
  if (action === 'setDimensions') {
    setDimensions(args[0] /* dimensions */)
  }
  if (action === 'back') {
    // TODO
    // window.history.back()
    if (state.url === '/player') {
      restoreBounds()
      closeServer()
    }
    state.url = '/'
    update()
  }
  if (action === 'forward') {
    // TODO
    // window.history.forward()
  }
  if (action === 'playPause') {
    state.video.isPaused = !state.video.isPaused
    update()
  }
  if (action === 'playbackJump') {
    state.video.jumpToTime = args[0] /* seconds */
    update()
  }
  if (action === 'toggleFullScreen') {
    electron.ipcRenderer.send('toggleFullScreen')
    update()
  }
  if (action === 'videoMouseMoved') {
    state.video.mouseStationarySince = new Date().getTime()
    update()
  }
}

electron.ipcRenderer.on('addTorrent', function (e, torrentId) {
  dispatch('addTorrent', torrentId)
})

electron.ipcRenderer.on('seed', function (e, files) {
  dispatch('seed', files)
})

electron.ipcRenderer.on('fullscreenChanged', function (e, isFullScreen) {
  state.isFullScreen = isFullScreen
  update()
})

electron.ipcRenderer.on('addFakeDevice', function (e, device) {
  var player = new EventEmitter()
  player.play = (networkURL) => console.log(networkURL)
  state.devices[device] = player
  update()
})

// Load state.saved from the JSON state file
function loadState () {
  cfg.read(function (err, data) {
    if (err) console.error(err)
    electron.ipcRenderer.send('log', 'loaded state from ' + cfg.filePath)
    state.saved = data
    if (!state.saved.torrents) state.saved.torrents = []
    state.saved.torrents.forEach((x) => startTorrenting(x.infoHash))
  })
}

// Write state.saved to the JSON state file
function saveState () {
  electron.ipcRenderer.send('log', 'saving state to ' + cfg.filePath)
  cfg.write(state.saved, function (err) {
    if (err) console.error(err)
    update()
  })
}

function updateDockIcon () {
  var progress = state.client.progress
  var activeTorrentsExist = state.client.torrents.some(function (torrent) {
    return torrent.progress !== 1
  })
  // Hide progress bar when client has no torrents, or progress is 100%
  if (!activeTorrentsExist || progress === 1) {
    progress = -1
  }
  if (progress !== state.dock.progress) {
    state.dock.progress = progress
    electron.ipcRenderer.send('setProgress', progress)
  }
}

function onFiles (files) {
  // .torrent file = start downloading the torrent
  files.filter(isTorrentFile).forEach(function (torrentFile) {
    dispatch('addTorrent', torrentFile)
  })

  // everything else = seed these files
  dispatch('seed', files.filter(isNotTorrentFile))
}

function isTorrentFile (file) {
  var extname = path.extname(file.name).toLowerCase()
  return extname === '.torrent'
}

function isNotTorrentFile (file) {
  return !isTorrentFile(file)
}

// Adds a torrent to the list, starts downloading/seeding. TorrentID can be a
// magnet URI, infohash, or torrent file: https://github.com/feross/webtorrent#clientaddtorrentid-opts-function-ontorrent-torrent-
function addTorrent (torrentId) {
  if (!torrentId) torrentId = 'magnet:?xt=urn:btih:6a9759bffd5c0af65319979fb7832189f4f3c35d&dn=sintel.mp4'
  var torrent = startTorrenting(torrentId)
  if (state.saved.torrents.find((x) => x.infoHash === torrent.infoHash)) {
    return // torrent is already in state.saved
  }
  state.saved.torrents.push({
    name: torrent.name,
    magnetURI: torrent.magnetURI,
    infoHash: torrent.infoHash,
    path: torrent.path,
    xt: torrent.xt,
    dn: torrent.dn,
    announce: torrent.announce
  })
  saveState()
}

// Starts downloading and/or seeding a given torrent file or magnet URI
function startTorrenting (torrentId) {
  var torrent = state.client.add(torrentId)
  addTorrentEvents(torrent)
  return torrent
}

// Creates a torrent for a local file and starts seeding it
function seed (files) {
  if (files.length === 0) return
  var torrent = state.client.seed(files)
  addTorrentEvents(torrent)
}

function addTorrentEvents (torrent) {
  torrent.on('infoHash', update)

  torrent.on('ready', torrentReady)
  torrent.on('done', torrentDone)

  update()

  function torrentReady () {
    torrentPoster(torrent, function (err, buf) {
      if (err) return onWarning(err)
      torrent.posterURL = URL.createObjectURL(new Blob([ buf ], { type: 'image/png' }))
      update()
    })
    update()
  }

  function torrentDone () {
    if (!state.isFocused) {
      state.dock.badge += 1
      electron.ipcRenderer.send('setBadge', state.dock.badge)
    }
    update()
  }
}

function startServer (torrent, cb) {
  if (state.server) return cb()

  // use largest file
  state.torrentPlaying = torrent.files.reduce(function (a, b) {
    return a.length > b.length ? a : b
  })
  var index = torrent.files.indexOf(state.torrentPlaying)

  var server = torrent.createServer()
  server.listen(0, function () {
    var port = server.address().port
    var urlSuffix = ':' + port + '/' + index
    state.server = {
      server: server,
      localURL: 'http://localhost' + urlSuffix,
      networkURL: 'http://' + networkAddress() + urlSuffix
    }
    cb()
  })
}

function closeServer () {
  state.server.server.destroy()
  state.server = null
}

function openPlayer (torrent) {
  startServer(torrent, function () {
    state.url = '/player'
    update()
  })
}

function deleteTorrent (torrent) {
  var ix = state.saved.torrents.findIndex((x) => x.infoHash === torrent.infoHash)
  if (ix > -1) state.saved.torrents.splice(ix, 1)
  torrent.destroy(saveState)
}

function openChromecast (torrent) {
  startServer(torrent, function () {
    state.devices.chromecast.play(state.server.networkURL, {
      title: 'WebTorrent — ' + torrent.name
    })
    state.devices.chromecast.on('error', function (err) {
      err.message = 'Chromecast: ' + err.message
      onError(err)
    })
    update()
  })
}

function openAirplay (torrent) {
  startServer(torrent, function () {
    state.devices.airplay.play(state.server.networkURL, 0, function () {
      // TODO: handle airplay errors
    })
    update()
  })
}

// Set window dimensions to match video dimensions or fill the screen
function setDimensions (dimensions) {
  state.mainWindowBounds = {
    x: window.screenX,
    y: window.screenY,
    width: window.outerWidth,
    height: window.outerHeight
  }

  // Limit window size to screen size
  var screenWidth = window.screen.width
  var screenHeight = window.screen.height
  var aspectRatio = dimensions.width / dimensions.height
  var scaleFactor = Math.min(
    Math.min(screenWidth / dimensions.width, 1),
    Math.min(screenHeight / dimensions.height, 1)
  )
  var width = Math.floor(dimensions.width * scaleFactor)
  var height = Math.floor(dimensions.height * scaleFactor)

  // Center window on screen
  var x = Math.floor((screenWidth - width) / 2)
  var y = Math.floor((screenHeight - height) / 2)

  electron.ipcRenderer.send('setAspectRatio', aspectRatio)
  electron.ipcRenderer.send('setBounds', {x, y, width, height})
}

function restoreBounds () {
  electron.ipcRenderer.send('setAspectRatio', 0)
  if (state.mainWindowBounds) {
    electron.ipcRenderer.send('setBounds', state.mainWindowBounds, true)
  }
}

function onError (err) {
  console.error(err.stack)
  window.alert(err.message || err)
  update()
}

function onWarning (err) {
  console.log('warning: %s', err.message)
}
<commit_msg>load state first<commit_after>/* global URL, Blob */

var airplay = require('airplay-js')
var chromecasts = require('chromecasts')()
var createTorrent = require('create-torrent')
var dragDrop = require('drag-drop')
var electron = require('electron')
var EventEmitter = require('events')
var mainLoop = require('main-loop')
var networkAddress = require('network-address')
var path = require('path')
var torrentPoster = require('./lib/torrent-poster')
var WebTorrent = require('webtorrent')
var cfg = require('application-config')('WebTorrent')

var createElement = require('virtual-dom/create-element')
var diff = require('virtual-dom/diff')
var patch = require('virtual-dom/patch')

var App = require('./views/app')

// For easy debugging in Developer Tools
var state = global.state = require('./state')

// Force use of webtorrent trackers on all torrents
global.WEBTORRENT_ANNOUNCE = createTorrent.announceList
  .map(function (arr) {
    return arr[0]
  })
  .filter(function (url) {
    return url.indexOf('wss://') === 0 || url.indexOf('ws://') === 0
  })

var vdomLoop

// All state lives in state.js. `state.saved` is read from and written to a file.
// All other state is ephemeral. First we load state.saved then initialize the app.
loadState(init)

/**
 * Called once when the application loads. (Not once per window.)
 * Connects to the torrent networks, sets up the UI and OS integrations like
 * the dock icon and drag+drop.
 */
function init () {
  // Connect to the WebTorrent and BitTorrent networks
  // WebTorrent.app is a hybrid client, as explained here: https://webtorrent.io/faq
  state.client = new WebTorrent()
  state.client.on('warning', onWarning)
  state.client.on('error', onError)

  // The UI is built with virtual-dom, a minimalist library extracted from React
  // The concepts--one way data flow, a pure function that renders state to a
  // virtual DOM tree, and a diff that applies changes in the vdom to the real
  // DOM, are all the same. Learn more: https://facebook.github.io/react/
  vdomLoop = mainLoop(state, render, {
    create: createElement,
    diff: diff,
    patch: patch
  })
  document.body.appendChild(vdomLoop.target)

  // Calling update() updates the UI given the current state
  // Do this at least once a second to show latest state for each torrent
  // (eg % downloaded) and to keep the cursor in sync when playing a video
  setInterval(update, 1000)

  // Resume all saved torrents now that state is loaded and vdom is ready
  resumeAllTorrents()
  document.addEventListener('unload', saveState)

  // listen for messages from the main process
  setupIpc()

  // OS integrations:
  // ...Chromecast and Airplay
  chromecasts.on('update', function (player) {
    state.devices.chromecast = player
    update()
  })

  airplay.createBrowser().on('deviceOn', function (player) {
    state.devices.airplay = player
  }).start()

  // ...drag and drop a torrent or video file to play or seed
  dragDrop('body', onFiles)

  // ...same thing if you paste a torrent
  document.addEventListener('paste', function () {
    electron.ipcRenderer.send('addTorrentFromPaste')
  })

  // ...keyboard shortcuts
  document.addEventListener('keydown', function (e) {
    if (e.which === 27) { /* ESC means either exit fullscreen or go back */
      if (state.isFullScreen) {
        dispatch('toggleFullScreen')
      } else {
        dispatch('back')
      }
    }
  })

  // ...focus and blur. Needed to show correct dock icon text ("badge") in OSX
  window.addEventListener('focus', function () {
    state.isFocused = true
    if (state.dock.badge > 0) electron.ipcRenderer.send('setBadge', '')
    state.dock.badge = 0
  })

  window.addEventListener('blur', function () {
    state.isFocused = false
  })
}

// This is the (mostly) pure funtion from state -> UI. Returns a virtual DOM
// tree. Any events, such as button clicks, will turn into calls to dispatch()
function render (state) {
  return App(state, dispatch)
}

// Calls render() to go from state -> UI, then applies to vdom to the real DOM.
function update () {
  vdomLoop.update(state)
  updateDockIcon()
}

// Events from the UI never modify state directly. Instead they call dispatch()
function dispatch (action, ...args) {
  console.log('dispatch: %s %o', action, args)
  if (action === 'addTorrent') {
    addTorrent(args[0] /* torrentId */)
  }
  if (action === 'seed') {
    seed(args[0] /* files */)
  }
  if (action === 'openPlayer') {
    openPlayer(args[0] /* torrent */)
  }
  if (action === 'deleteTorrent') {
    deleteTorrent(args[0] /* torrent */)
  }
  if (action === 'openChromecast') {
    openChromecast(args[0] /* torrent */)
  }
  if (action === 'openAirplay') {
    openAirplay(args[0] /* torrent */)
  }
  if (action === 'setDimensions') {
    setDimensions(args[0] /* dimensions */)
  }
  if (action === 'back') {
    // TODO
    // window.history.back()
    if (state.url === '/player') {
      restoreBounds()
      closeServer()
    }
    state.url = '/'
    update()
  }
  if (action === 'forward') {
    // TODO
    // window.history.forward()
  }
  if (action === 'playPause') {
    state.video.isPaused = !state.video.isPaused
    update()
  }
  if (action === 'playbackJump') {
    state.video.jumpToTime = args[0] /* seconds */
    update()
  }
  if (action === 'toggleFullScreen') {
    electron.ipcRenderer.send('toggleFullScreen')
    update()
  }
  if (action === 'videoMouseMoved') {
    state.video.mouseStationarySince = new Date().getTime()
    update()
  }
}

function setupIpc () {
  electron.ipcRenderer.on('addTorrent', function (e, torrentId) {
    dispatch('addTorrent', torrentId)
  })

  electron.ipcRenderer.on('seed', function (e, files) {
    dispatch('seed', files)
  })

  electron.ipcRenderer.on('fullscreenChanged', function (e, isFullScreen) {
    state.isFullScreen = isFullScreen
    update()
  })

  electron.ipcRenderer.on('addFakeDevice', function (e, device) {
    var player = new EventEmitter()
    player.play = (networkURL) => console.log(networkURL)
    state.devices[device] = player
    update()
  })
}

// Load state.saved from the JSON state file
function loadState (callback) {
  cfg.read(function (err, data) {
    if (err) console.error(err)
    electron.ipcRenderer.send('log', 'loaded state from ' + cfg.filePath)
    state.saved = data
    if (!state.saved.torrents) state.saved.torrents = []
    if (callback) callback()
  })
}

function resumeAllTorrents () {
  state.saved.torrents.forEach((x) => startTorrenting(x.infoHash))
}

// Write state.saved to the JSON state file
function saveState () {
  electron.ipcRenderer.send('log', 'saving state to ' + cfg.filePath)
  cfg.write(state.saved, function (err) {
    if (err) console.error(err)
    update()
  })
}

function updateDockIcon () {
  var progress = state.client.progress
  var activeTorrentsExist = state.client.torrents.some(function (torrent) {
    return torrent.progress !== 1
  })
  // Hide progress bar when client has no torrents, or progress is 100%
  if (!activeTorrentsExist || progress === 1) {
    progress = -1
  }
  if (progress !== state.dock.progress) {
    state.dock.progress = progress
    electron.ipcRenderer.send('setProgress', progress)
  }
}

function onFiles (files) {
  // .torrent file = start downloading the torrent
  files.filter(isTorrentFile).forEach(function (torrentFile) {
    dispatch('addTorrent', torrentFile)
  })

  // everything else = seed these files
  dispatch('seed', files.filter(isNotTorrentFile))
}

function isTorrentFile (file) {
  var extname = path.extname(file.name).toLowerCase()
  return extname === '.torrent'
}

function isNotTorrentFile (file) {
  return !isTorrentFile(file)
}

// Adds a torrent to the list, starts downloading/seeding. TorrentID can be a
// magnet URI, infohash, or torrent file: https://github.com/feross/webtorrent#clientaddtorrentid-opts-function-ontorrent-torrent-
function addTorrent (torrentId) {
  if (!torrentId) torrentId = 'magnet:?xt=urn:btih:6a9759bffd5c0af65319979fb7832189f4f3c35d&dn=sintel.mp4'
  var torrent = startTorrenting(torrentId)
  if (state.saved.torrents.find((x) => x.infoHash === torrent.infoHash)) {
    return // torrent is already in state.saved
  }
  state.saved.torrents.push({
    name: torrent.name,
    magnetURI: torrent.magnetURI,
    infoHash: torrent.infoHash,
    path: torrent.path,
    xt: torrent.xt,
    dn: torrent.dn,
    announce: torrent.announce
  })
  saveState()
}

// Starts downloading and/or seeding a given torrent file or magnet URI
function startTorrenting (torrentId) {
  var torrent = state.client.add(torrentId)
  addTorrentEvents(torrent)
  return torrent
}

// Creates a torrent for a local file and starts seeding it
function seed (files) {
  if (files.length === 0) return
  var torrent = state.client.seed(files)
  addTorrentEvents(torrent)
}

function addTorrentEvents (torrent) {
  torrent.on('infoHash', update)

  torrent.on('ready', torrentReady)
  torrent.on('done', torrentDone)

  update()

  function torrentReady () {
    torrentPoster(torrent, function (err, buf) {
      if (err) return onWarning(err)
      torrent.posterURL = URL.createObjectURL(new Blob([ buf ], { type: 'image/png' }))
      update()
    })
    update()
  }

  function torrentDone () {
    if (!state.isFocused) {
      state.dock.badge += 1
      electron.ipcRenderer.send('setBadge', state.dock.badge)
    }
    update()
  }
}

function startServer (torrent, cb) {
  if (state.server) return cb()

  // use largest file
  state.torrentPlaying = torrent.files.reduce(function (a, b) {
    return a.length > b.length ? a : b
  })
  var index = torrent.files.indexOf(state.torrentPlaying)

  var server = torrent.createServer()
  server.listen(0, function () {
    var port = server.address().port
    var urlSuffix = ':' + port + '/' + index
    state.server = {
      server: server,
      localURL: 'http://localhost' + urlSuffix,
      networkURL: 'http://' + networkAddress() + urlSuffix
    }
    cb()
  })
}

function closeServer () {
  state.server.server.destroy()
  state.server = null
}

function openPlayer (torrent) {
  startServer(torrent, function () {
    state.url = '/player'
    update()
  })
}

function deleteTorrent (torrent) {
  var ix = state.saved.torrents.findIndex((x) => x.infoHash === torrent.infoHash)
  if (ix > -1) state.saved.torrents.splice(ix, 1)
  torrent.destroy(saveState)
}

function openChromecast (torrent) {
  startServer(torrent, function () {
    state.devices.chromecast.play(state.server.networkURL, {
      title: 'WebTorrent — ' + torrent.name
    })
    state.devices.chromecast.on('error', function (err) {
      err.message = 'Chromecast: ' + err.message
      onError(err)
    })
    update()
  })
}

function openAirplay (torrent) {
  startServer(torrent, function () {
    state.devices.airplay.play(state.server.networkURL, 0, function () {
      // TODO: handle airplay errors
    })
    update()
  })
}

// Set window dimensions to match video dimensions or fill the screen
function setDimensions (dimensions) {
  state.mainWindowBounds = {
    x: window.screenX,
    y: window.screenY,
    width: window.outerWidth,
    height: window.outerHeight
  }

  // Limit window size to screen size
  var screenWidth = window.screen.width
  var screenHeight = window.screen.height
  var aspectRatio = dimensions.width / dimensions.height
  var scaleFactor = Math.min(
    Math.min(screenWidth / dimensions.width, 1),
    Math.min(screenHeight / dimensions.height, 1)
  )
  var width = Math.floor(dimensions.width * scaleFactor)
  var height = Math.floor(dimensions.height * scaleFactor)

  // Center window on screen
  var x = Math.floor((screenWidth - width) / 2)
  var y = Math.floor((screenHeight - height) / 2)

  electron.ipcRenderer.send('setAspectRatio', aspectRatio)
  electron.ipcRenderer.send('setBounds', {x, y, width, height})
}

function restoreBounds () {
  electron.ipcRenderer.send('setAspectRatio', 0)
  if (state.mainWindowBounds) {
    electron.ipcRenderer.send('setBounds', state.mainWindowBounds, true)
  }
}

function onError (err) {
  console.error(err.stack)
  window.alert(err.message || err)
  update()
}

function onWarning (err) {
  console.log('warning: %s', err.message)
}
<|endoftext|>


<commit_before>"use strict";
import React, { Component, PropTypes } from 'react';
import Section from './Section';
import VolumeIcon from '../icons/Volume';

function pad(num, size) {
  let s = num + "";
  while (s.length < size) s = "0" + s;
  return s;
}

function friendlyDuration (duration) {
  let remaining = duration;
  let result = '';
  if (remaining > 3600) {
    const hours = Math.floor(remaining / 3600);
    result += `${hours}:`;
    remaining -= hours * 3600;
  }
  if (remaining > 60) {
    const minutes = Math.floor(remaining / 60);
    result += `${pad(minutes, 2)}:`;
    remaining -= minutes * 60;
  }
  if (remaining > 0) {
    const seconds = Math.floor(remaining);
    result += `${pad(seconds, 2)}`;
  }
  return result;
}

export default class Audio extends Component {

  constructor () {
    super();
    this._onTimeUpdate = this._onTimeUpdate.bind(this);
    this._onEnded = this._onEnded.bind(this);
    this._onResize = this._onResize.bind(this);
    this._layout = this._layout.bind(this);
    this._onPlay = this._onPlay.bind(this);
    this._onPause = this._onPause.bind(this);
    this._onSeek = this._onSeek.bind(this);
    this._onVolume = this._onVolume.bind(this);
    this.state = { playing: false, volume: 0.7, start: 0, end: 0, at: 0 };
  }

  componentDidMount () {
    const audio = this.refs.audio;
    audio.volume = this.state.volume;
    audio.addEventListener('timeupdate', this._onTimeUpdate);
    audio.addEventListener('ended', this._onEnded);
    window.addEventListener('resize', this._onResize);
    this._layout();
  }

  componentDidUpdate () {
    const { autoPlay } = this.props;
    const { playing } = this.state;
    if (autoPlay && ! playing) {
      this._onPlay();
    }
  }

  componentWillUnmount () {
    const audio = this.refs.audio;
    audio.removeEventListener('timeupdate', this._onTimeUpdate);
    audio.removeEventListener('ended', this._onEnded);
    window.removeEventListener('resize', this._onResize);
  }

  _onTimeUpdate (event) {
    const audio = this.refs.audio;
    this.setState({ at: audio.currentTime });
  }

  _onEnded (event) {
    const { onEnd } = this.props;
    this.setState({ playing: false });
    if (onEnd) {
      onEnd();
    }
  }

  _onResize (event) {
    clearTimeout(this._resizeTimer);
    this._resizeTimer = setTimeout(this._layout, 10);
  }

  _layout () {
    // Remove?
  }

  _onPlay () {
    const { onStart } = this.props;
    const audio = this.refs.audio;
    audio.play();
    this.setState({ playing: true,
      start: audio.seekable.start(0), end: audio.seekable.end(0) });
    if (onStart) {
      onStart();
    }
  }

  _onPause () {
    const audio = this.refs.audio;
    audio.pause();
    this.setState({ playing: false });
  }

  _onSeek (event) {
    const audio = this.refs.audio;
    const value = event.target.value;
    audio.currentTime = value;
    this.setState({ at: value });
  }

  _onVolume (event) {
    const audio = this.refs.audio;
    const value = event.target.value;
    audio.volume = value;
    this.setState({ volume: value });
  }

  render () {
    const { file, className, color, full, plain } = this.props;
    const { playing, volume, start, end, at } = this.state;
    const path = `/api/files/${file._id}/${file.name}`;

    let classes = ['audio'];
    if (plain) {
      classes.push('audio--plain');
    }
    if (className) {
      classes.push(className);
    }

    let label;
    if (file.label) {
      label = {file.label};
    }

    let playControl;
    if (playing) {
      playControl = (
        <button className="button audio__control" type="button"
          onClick={this._onPause}>Pause</button>
      );
    } else {
      playControl = (
        <button className="button audio__control" type="button"
          onClick={this._onPlay}>Play</button>
      );
    }

    let positionControl, volumeControl;
    if (playing) {
      positionControl = (

          <input className="audio__position" type="range" min={start} max={end}
            value={at} onChange={this._onSeek} />
          {friendlyDuration(end - at)}

      );
      volumeControl = (

          <VolumeIcon />
          <input className="audio__volume" type="range" min={0} max={1}
            step={0.1} value={volume} onChange={this._onVolume} />

      );
    }

    return (

            {label}
            {playControl}

          {positionControl}
          {volumeControl}
          <audio ref="audio" preload="metadata">
            <source src={path} type={file.type} />
            No audio with this browser
          </audio>

    );
  }
};

Audio.propTypes = {
  autoPlay: PropTypes.bool,
  full: PropTypes.bool,
  file: PropTypes.shape({
    _id: PropTypes.string.isRequired,
    label: PropTypes.string,
    name: PropTypes.string.isRequired,
    type: PropTypes.string.isRequired
  }),
  onEnd: PropTypes.func,
  onStart: PropTypes.func,
  ...Section.propTypes
};
<commit_msg>Show Audio controls when paused.<commit_after>"use strict";
import React, { Component, PropTypes } from 'react';
import Section from './Section';
import VolumeIcon from '../icons/Volume';

function pad(num, size) {
  let s = num + "";
  while (s.length < size) s = "0" + s;
  return s;
}

function friendlyDuration (duration) {
  let remaining = duration;
  let result = '';
  if (remaining > 3600) {
    const hours = Math.floor(remaining / 3600);
    result += `${hours}:`;
    remaining -= hours * 3600;
  }
  if (remaining > 60) {
    const minutes = Math.floor(remaining / 60);
    result += `${pad(minutes, 2)}:`;
    remaining -= minutes * 60;
  }
  if (remaining > 0) {
    const seconds = Math.floor(remaining);
    result += `${pad(seconds, 2)}`;
  }
  return result;
}

export default class Audio extends Component {

  constructor () {
    super();
    this._onTimeUpdate = this._onTimeUpdate.bind(this);
    this._onEnded = this._onEnded.bind(this);
    this._onResize = this._onResize.bind(this);
    this._layout = this._layout.bind(this);
    this._onPlay = this._onPlay.bind(this);
    this._onPause = this._onPause.bind(this);
    this._onSeek = this._onSeek.bind(this);
    this._onVolume = this._onVolume.bind(this);
    this.state = { playing: false, volume: 0.7, start: 0, end: 0, at: 0 };
  }

  componentDidMount () {
    const audio = this.refs.audio;
    audio.volume = this.state.volume;
    audio.addEventListener('timeupdate', this._onTimeUpdate);
    audio.addEventListener('ended', this._onEnded);
    window.addEventListener('resize', this._onResize);
    this._layout();
  }

  componentDidUpdate () {
    const { autoPlay } = this.props;
    const { playing } = this.state;
    if (autoPlay && ! playing) {
      this._onPlay();
    }
  }

  componentWillUnmount () {
    const audio = this.refs.audio;
    audio.removeEventListener('timeupdate', this._onTimeUpdate);
    audio.removeEventListener('ended', this._onEnded);
    window.removeEventListener('resize', this._onResize);
  }

  _onTimeUpdate (event) {
    const audio = this.refs.audio;
    this.setState({ at: audio.currentTime });
  }

  _onEnded (event) {
    const { onEnd } = this.props;
    this.setState({ playing: false });
    if (onEnd) {
      onEnd();
    }
  }

  _onResize (event) {
    clearTimeout(this._resizeTimer);
    this._resizeTimer = setTimeout(this._layout, 10);
  }

  _layout () {
    // Remove?
  }

  _onPlay () {
    const { onStart } = this.props;
    const audio = this.refs.audio;
    audio.play();
    this.setState({ playing: true,
      start: audio.seekable.start(0), end: audio.seekable.end(0) });
    if (onStart) {
      onStart();
    }
  }

  _onPause () {
    const audio = this.refs.audio;
    audio.pause();
    this.setState({ playing: false });
  }

  _onSeek (event) {
    const audio = this.refs.audio;
    const value = event.target.value;
    audio.currentTime = value;
    this.setState({ at: value });
  }

  _onVolume (event) {
    const audio = this.refs.audio;
    const value = event.target.value;
    audio.volume = value;
    this.setState({ volume: value });
  }

  render () {
    const { file, className, color, full, plain } = this.props;
    const { playing, volume, start, end, at } = this.state;
    const path = `/api/files/${file._id}/${file.name}`;

    let classes = ['audio'];
    if (plain) {
      classes.push('audio--plain');
    }
    if (className) {
      classes.push(className);
    }

    let label;
    if (file.label) {
      label = {file.label};
    }

    let playControl;
    if (playing) {
      playControl = (
        <button className="button audio__control" type="button"
          onClick={this._onPause}>Pause</button>
      );
    } else {
      playControl = (
        <button className="button audio__control" type="button"
          onClick={this._onPlay}>Play</button>
      );
    }

    let positionControl, volumeControl;
    if (playing || at) {
      positionControl = (

          <input className="audio__position" type="range" min={start} max={end}
            value={at} onChange={this._onSeek} />
          {friendlyDuration(end - at)}

      );
      volumeControl = (

          <VolumeIcon />
          <input className="audio__volume" type="range" min={0} max={1}
            step={0.1} value={volume} onChange={this._onVolume} />

      );
    }

    return (

            {label}
            {playControl}

          {positionControl}
          {volumeControl}
          <audio ref="audio" preload="metadata">
            <source src={path} type={file.type} />
            No audio with this browser
          </audio>

    );
  }
};

Audio.propTypes = {
  autoPlay: PropTypes.bool,
  full: PropTypes.bool,
  file: PropTypes.shape({
    _id: PropTypes.string.isRequired,
    label: PropTypes.string,
    name: PropTypes.string.isRequired,
    type: PropTypes.string.isRequired
  }),
  onEnd: PropTypes.func,
  onStart: PropTypes.func,
  ...Section.propTypes
};
<|endoftext|>


<commit_before>(function() {
    'use strict';
    angular.module('theHiveControllers')
        .controller('CaseTaskDeleteCtrl', CaseTaskDeleteCtrl)
        .controller('CaseTasksCtrl', CaseTasksCtrl);

    function CaseTasksCtrl($scope, $state, $stateParams, $uibModal, CaseTabsSrv, PSearchSrv, CaseTaskSrv, UserInfoSrv, AlertSrv) {

        CaseTabsSrv.activateTab($state.current.data.tab);

        $scope.caseId = $stateParams.caseId;
        $scope.state = {
            'isNewTask': false
        };
        $scope.newTask = {
            status: 'Waiting'
        };

        $scope.tasks = PSearchSrv($scope.caseId, 'case_task', {
            scope: $scope,
            baseFilter: {
                '_and': [{
                    '_parent': {
                        '_type': 'case',
                        '_query': {
                            '_id': $scope.caseId
                        }
                    }
                }, {
                    '_not': {
                        'status': 'Cancel'
                    }
                }]
            },
            sort: ['-flag', '+startDate', '+title']
        });

        $scope.showTask = function(task) {
            $state.go('app.case.tasks-item', {
                itemId: task.id
            });
        };

        $scope.addTask = function() {
            CaseTaskSrv.save({
                'caseId': $scope.caseId,
                'flag': false
            }, $scope.newTask, function() {
                $scope.isNewTask = false;
                $scope.newTask.title = '';
            }, function(response) {
                AlertSrv.error('taskList', response.data, response.status);
            });
        };

        $scope.removeTask = function(task) {

            var modalInstance = $uibModal.open({
                animation: true,
                templateUrl: 'views/partials/case/case.task.delete.html',
                controller: 'CaseTaskDeleteCtrl',
                controllerAs: 'vm',
                resolve: {
                    title: function() {
                        return task.title;
                    }
                }
            });

            modalInstance.result.then(function() {
                CaseTaskSrv.update({
                    'taskId': task.id
                }, {
                    status: 'Cancel'
                }, function() {
                    $scope.$emit('tasks:task-removed', task);
                }, function(response) {
                    AlertSrv.error('taskList', response.data, response.status);
                });
            });

        };

        // open task tab with its details
        $scope.openTask = function(task) {
            if (task.status === 'Waiting') {
                CaseTaskSrv.update({
                    'taskId': task.id
                }, {
                    'status': 'InProgress'
                }, function(data) {
                    $scope.showTask(data);
                }, function(response) {
                    AlertSrv.error('taskList', response.data, response.status);
                });
            } else {
                $scope.showTask(task);
            }
        };

    }

    function CaseTaskDeleteCtrl($uibModalInstance, title) {
        this.title = title;

        this.ok = function() {
            $uibModalInstance.close();
        };

        this.cancel = function() {
            $uibModalInstance.dismiss();
        };
    }
}());
<commit_msg>#157 Set task list's page size to 30<commit_after>(function() {
    'use strict';
    angular.module('theHiveControllers')
        .controller('CaseTaskDeleteCtrl', CaseTaskDeleteCtrl)
        .controller('CaseTasksCtrl', CaseTasksCtrl);

    function CaseTasksCtrl($scope, $state, $stateParams, $uibModal, CaseTabsSrv, PSearchSrv, CaseTaskSrv, UserInfoSrv, AlertSrv) {

        CaseTabsSrv.activateTab($state.current.data.tab);

        $scope.caseId = $stateParams.caseId;
        $scope.state = {
            'isNewTask': false
        };
        $scope.newTask = {
            status: 'Waiting'
        };

        $scope.tasks = PSearchSrv($scope.caseId, 'case_task', {
            scope: $scope,
            baseFilter: {
                '_and': [{
                    '_parent': {
                        '_type': 'case',
                        '_query': {
                            '_id': $scope.caseId
                        }
                    }
                }, {
                    '_not': {
                        'status': 'Cancel'
                    }
                }]
            },
            sort: ['-flag', '+startDate', '+title'],
            pageSize: 30
        });

        $scope.showTask = function(task) {
            $state.go('app.case.tasks-item', {
                itemId: task.id
            });
        };

        $scope.addTask = function() {
            CaseTaskSrv.save({
                'caseId': $scope.caseId,
                'flag': false
            }, $scope.newTask, function() {
                $scope.isNewTask = false;
                $scope.newTask.title = '';
            }, function(response) {
                AlertSrv.error('taskList', response.data, response.status);
            });
        };

        $scope.removeTask = function(task) {

            var modalInstance = $uibModal.open({
                animation: true,
                templateUrl: 'views/partials/case/case.task.delete.html',
                controller: 'CaseTaskDeleteCtrl',
                controllerAs: 'vm',
                resolve: {
                    title: function() {
                        return task.title;
                    }
                }
            });

            modalInstance.result.then(function() {
                CaseTaskSrv.update({
                    'taskId': task.id
                }, {
                    status: 'Cancel'
                }, function() {
                    $scope.$emit('tasks:task-removed', task);
                }, function(response) {
                    AlertSrv.error('taskList', response.data, response.status);
                });
            });

        };

        // open task tab with its details
        $scope.openTask = function(task) {
            if (task.status === 'Waiting') {
                CaseTaskSrv.update({
                    'taskId': task.id
                }, {
                    'status': 'InProgress'
                }, function(data) {
                    $scope.showTask(data);
                }, function(response) {
                    AlertSrv.error('taskList', response.data, response.status);
                });
            } else {
                $scope.showTask(task);
            }
        };

    }

    function CaseTaskDeleteCtrl($uibModalInstance, title) {
        this.title = title;

        this.ok = function() {
            $uibModalInstance.close();
        };

        this.cancel = function() {
            $uibModalInstance.dismiss();
        };
    }
}());
<|endoftext|>


<commit_before>"use strict";
const { BridgedClient, BridgedClientStatus } = require("../../lib/irc/BridgedClient.js");

const STATE_DISC = {
    status: BridgedClientStatus.DISCONNECTED
}

const STATE_CONN = {
    status: BridgedClientStatus.CONNECTED,
    client: {}
}

const STATE_CONN_MAX5 = {
    status: BridgedClientStatus.CONNECTED,
    client: {
        supported: {
            nicklength: 5
        }
    }
}

describe("BridgedClient", function() {
    describe("getValidNick", function() {
        it("should not change a valid nick", function() {
            expect(BridgedClient.getValidNick("foobar", true, STATE_DISC)).toBe("foobar");
        });
        it("should remove invalid characters", function() {
            expect(BridgedClient.getValidNick("f+/\u3052oobar", false, STATE_DISC)).toBe("foobar");
        });
        it("will allow nicks that start with a special character", function() {
            expect(BridgedClient.getValidNick("foo-bar", false, STATE_DISC)).toBe("foo-bar");
            expect(BridgedClient.getValidNick("[foobar]", false, STATE_DISC)).toBe("[foobar]");
            expect(BridgedClient.getValidNick("{foobar}", false, STATE_DISC)).toBe("{foobar}");
            expect(BridgedClient.getValidNick("-foobar", false, STATE_DISC)).toBe("M-foobar");
            expect(BridgedClient.getValidNick("12345", false, STATE_DISC)).toBe("M12345");
        });
        it("will throw if the nick is invalid", function() {
            expect(() => BridgedClient.getValidNick("f+/\u3052oobar", true, STATE_DISC)).toThrowError();
            expect(() => BridgedClient.getValidNick("a".repeat(20), true, STATE_CONN)).toThrowError();
            expect(() => BridgedClient.getValidNick("-foobar", true, STATE_CONN)).toThrowError();
        });
        it("will not truncate a nick if disconnected", function() {
            expect(BridgedClient.getValidNick("a".repeat(20), false, STATE_DISC)).toBe("a".repeat(20));
        });
        it("will truncate nick", function() {
            expect(BridgedClient.getValidNick("a".repeat(20), false, STATE_CONN)).toBe("a".repeat(9));
        });
        it("will truncate a nick with a custom max character limit", function() {
            expect(BridgedClient.getValidNick("a".repeat(20), false, STATE_CONN_MAX5)).toBe("a".repeat(5));
        });
    });
});
<commit_msg>Add more valid nick tests<commit_after>"use strict";
const { BridgedClient, BridgedClientStatus } = require("../../lib/irc/BridgedClient.js");

const STATE_DISC = {
    status: BridgedClientStatus.DISCONNECTED
}

const STATE_CONN = {
    status: BridgedClientStatus.CONNECTED,
    client: {}
}

const STATE_CONN_MAX5 = {
    status: BridgedClientStatus.CONNECTED,
    client: {
        supported: {
            nicklength: 5
        }
    }
}

describe("BridgedClient", function() {
    describe("getValidNick", function() {
        it("should not change a valid nick", function() {
            const nicks = ["foobar", "foo-bar`", "[foobar]", "{foobar}", "|foobar", "`foobar", "foobar\\", "f1|23_45"];
            for (const nick of nicks) {
                expect(BridgedClient.getValidNick(nick, true, STATE_DISC)).toBe(nick);
            }
        });
        it("should remove invalid characters", function() {
            expect(BridgedClient.getValidNick("f+/\u3052oobar", false, STATE_DISC)).toBe("foobar");
        });
        it("will ensure nicks start with a letter or special character", function() {
            expect(BridgedClient.getValidNick("-foobar", false, STATE_DISC)).toBe("M-foobar");
            expect(BridgedClient.getValidNick("12345", false, STATE_DISC)).toBe("M12345");
        });
        it("will throw if the nick is invalid", function() {
            expect(() => BridgedClient.getValidNick("f+/\u3052oobar", true, STATE_DISC)).toThrowError();
            expect(() => BridgedClient.getValidNick("a".repeat(20), true, STATE_CONN)).toThrowError();
            expect(() => BridgedClient.getValidNick("-foobar", true, STATE_CONN)).toThrowError();
        });
        it("will not truncate a nick if disconnected", function() {
            expect(BridgedClient.getValidNick("a".repeat(20), false, STATE_DISC)).toBe("a".repeat(20));
        });
        it("will truncate nick", function() {
            expect(BridgedClient.getValidNick("a".repeat(20), false, STATE_CONN)).toBe("a".repeat(9));
        });
        it("will truncate a nick with a custom max character limit", function() {
            expect(BridgedClient.getValidNick("a".repeat(20), false, STATE_CONN_MAX5)).toBe("a".repeat(5));
        });
    });
});
<|endoftext|>


<commit_before>'use strict';
var util            = require('util');
var yeoman          = require('yeoman-generator');
var chalk           = require('chalk');
var updateNotifier  = require('update-notifier');
var pkg             = require('../package.json');
var opn             = require('opn');
var _s              = require('underscore.string');

var KickoffGenerator = module.exports = function KickoffGenerator(args, options) {
	yeoman.generators.Base.apply(this, arguments);
};

util.inherits(KickoffGenerator, yeoman.generators.Base);

KickoffGenerator.prototype.askFor = function () {
	var done = this.async();

	// Checks for available update and returns an instance
	var notifier = updateNotifier({
		packageName: pkg.name,
		packageVersion: pkg.version,
		updateCheckInterval: 1000 * 60 // Every hour
	});

	var kickoffWelcome = chalk.white('\n ##  ## ######  ####  ##  ##  ') + chalk.yellow('####  ###### ######') + chalk.white('\n ## ##    ##   ##  ## ## ##  ') + chalk.yellow('##  ## ##     ##') + chalk.white('\n ####     ##   ##     ####   ') + chalk.yellow('##  ## ####   ####') + chalk.white('\n ## ##    ##   ##  ## ## ##  ') + chalk.yellow('##  ## ##     ##') + chalk.white('\n ##  ## ######  ####  ##  ##  ') + chalk.yellow('####  ##     ##') + '\n\n ' + chalk.white.bold('A Yeoman generator for the Kickoff front-end framework') + '\n\n Find out more at ' + chalk.cyan('trykickoff.com') + '\n Yeoman Generator version:  ' + pkg.version + '\n\n Kickoff is free and open-source and maintained by ' + chalk.yellow('@MrMartineau') + ',\n ' + chalk.green('@AshNolan_') + ', ' + chalk.red('@nicbell') + ' & the ' + chalk.blue('@tmwTechTeam') + '. \n';

	// Have Yeoman greet the user.
	this.log(kickoffWelcome);

	if (notifier.update) {
		// Check for npm package update and print message if needed
		var updateMessage = chalk.yellow('   ┌────────────────────────────────────────────────┐\n   │') + ' Update available: '  + chalk.green(notifier.update.latest) + chalk.gray(' (current: ' + pkg.version + ')') + '       '+ chalk.yellow('│\n   │') + ' Run ' + chalk.cyan('npm update -g ' + pkg.name) + ' to update. ' + chalk.yellow('│\n   └────────────────────────────────────────────────┘\n');

		this.log(updateMessage);
	}

	var prompts = [
		{
			name: 'projectName',
			message: 'Project name',
			default: 'Your project name'
		},
		{
			name: 'projectDescription',
			message: 'Description',
			default: 'Project description'
		},
		{
			name: 'devNames',
			message: 'Developer\'s names?',
			default: 'Tom, Dick & Harry'
		},
		{
			name: 'features',
			type: 'checkbox',
			message: 'Which features would you like?',
			choices: [
				{
					name: 'Does this project support IE8?',
					value: 'oldIE',
					default: false,
				},
				{
					name: 'Include Kickoff\'s styleguide?',
					value: 'styleguide'
				},
				{
					name: 'Use Kickoff Statix?',
					value: 'statix'
				},
				{
					name: 'Use Grunticon?',
					value: 'grunticon'
				}
			],
			store: true
		},
		{
			name: 'browserify',
			type: 'confirm',
			message: 'Use Browserify to bundle your Javascript?',
			default: true,
			store: true
		},
		{
			name: 'jsNamespace',
			message: 'Choose your javascript namespace',
			default: 'KO',
			store: true,
			when: function(response) {
				return !response.browserify;
			}
		},
		{
			name: 'jsLibs',
			type: 'checkbox',
			message: 'Which Javascript libraries would you like to use?',
			choices: [
				{
					name: 'jQuery 1.x - only choose one jQuery version',
					value: 'jquery1'
				},
				{
					name: 'jQuery 2.x - only choose one jQuery version',
					value: 'jquery2'
				},
				{
					name: 'trak.js - Universal event tracking API',
					value: 'trak'
				},
				{
					name: 'Swiftclick - Eliminates the 300ms click event delay on touch devices',
					value: 'swiftclick'
				},
				{
					name: 'Include some Javascript polyfills/shims? (These are generated by the \'grunt shimly\' command)',
					value: 'shims'
				},
				{
					name: 'Use Modernizr?',
					value: 'modernizr'
				}
			],
			store: true
		}
	];

	this.prompt(prompts, function (answers) {
		for (var key in answers) {
			this[key] = answers[key];
		}

		var jsLibs = answers.jsLibs;
		var features = answers.features;

		function hasFeature(feat, prop) {
			return prop && prop.indexOf(feat) !== -1;
		}

		console.log('jsLibs', jsLibs);
		console.log('features', features);

		// JS Libs
		this.includeTrak       = hasFeature('trak', jsLibs);
		this.includeJquery1    = hasFeature('jquery1', jsLibs);
		this.includeJquery2    = hasFeature('jquery2', jsLibs);
		this.includeSwiftclick = hasFeature('swiftclick', jsLibs);
		this.includeShims      = hasFeature('shims', jsLibs);
		this.includeModernizr  = hasFeature('modernizr', jsLibs);

		// Features
		this.includeGrunticon  = hasFeature('grunticon', features);
		this.includeStatix     = hasFeature('statix', features);
		this.includeStyleguide = hasFeature('styleguide', features);
		this.oldIE = hasFeature('oldIE', features);

		done();
	}.bind(this));
};

/**
 * Info
 * http://yeoman.io/generator/actions_actions.html
 * http://yeoman.io/authoring/file-system.html
 */
KickoffGenerator.prototype.packageFiles = function packageFiles() {

	this.fs.copyTpl(
		this.templatePath('_index.html'),
		this.destinationPath('index.html'),
		{
			projectName: this.projectName,
			projectNameSlugified: _s.slugify(this.projectName),
			oldIE: this.oldIE,
			grunticon: this.includeGrunticon,
			modernizr: this.includeModernizr,
			shims: this.includeShims
		}
	);

	if (this.includeStyleguide && !this.includeStatix) {
		this.fs.copyTpl(
			this.templatePath('styleguide/_index.html'),
			this.destinationPath('styleguide/index.html'),
			{
				projectName: this.projectName,
				projectNameSlugified: _s.slugify(this.projectName),
				oldIE: this.oldIE,
				grunticon: this.includeGrunticon,
				modernizr: this.includeModernizr,
				shims: this.includeShims
			}
		);
	}

	// CSS, SCSS, images & grunticon source directory
	this.directory('assets/dist/css', 'assets/dist/css');
	this.directory('assets/src/scss', 'assets/src/scss');
	this.directory('assets/src/img', 'assets/src/img');
	this.directory('assets/src/grunticon', 'assets/src/grunticon');

	// Javascript
	if (this.browserify) {
		this.fs.copyTpl(
			this.templatePath('assets/src/js/_script-browserify.js'),
			this.destinationPath('assets/src/js/script.js'),
			{
				projectName: this.projectName,
				devNames: this.devNames,
				browserify: this.browserify,
				includeSwiftclick: this.includeSwiftclick,
				includeTrak: this.includeTrak,
				includeJquery1: this.includeJquery1,
				includeJquery2: this.includeJquery2,
				statix: this.includeStatix,
				shims: this.includeShims
			}
		);

		this.directory('assets/src/js/modules', 'assets/src/js/modules');

	} else {
		this.fs.copyTpl(
			this.templatePath('assets/src/js/_script-fileArray.js'),
			this.destinationPath('assets/src/js/script.js'),
			{
				projectName: this.projectName,
				devNames: this.devNames,
				includeJquery1: this.includeJquery1,
				includeJquery2: this.includeJquery2,
				jsNamespace: this.jsNamespace
			}
		);
	}

	if (this.modernizr) {
		this.copy('assets/src/js/standalone/modernizr.js', 'assets/src/js/standalone/modernizr.js');
	}

	if (this.shims) {
		this.copy('assets/src/js/standalone/shims.js', 'assets/src/js/standalone/shims.js');
	}

	// Grunt configs
	this.fs.copyTpl(
		this.templatePath('_Gruntfile.js'),
		this.destinationPath('Gruntfile.js'),
		{
			browserify: this.browserify,
			grunticon: this.includeGrunticon,
			modernizr: this.includeModernizr,
			statix: this.includeStatix,
			shims: this.includeShims,
			styleguide: this.includeStyleguide
		}
	);

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_config.js'),
		this.destinationPath('_grunt-configs/config.js'),
		{
			projectName: this.projectName,
			projectNameSlugified: _s.slugify(this.projectName),
			browserify: this.browserify,
			includeSwiftclick: this.includeSwiftclick,
			includeTrak: this.includeTrak,
			includeJquery1: this.includeJquery1,
			includeJquery2: this.includeJquery2,
			statix: this.includeStatix
		}
	);

	this.copy('_grunt-configs/css.js', '_grunt-configs/css.js');

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_images.js'),
		this.destinationPath('_grunt-configs/images.js'),
		{
			grunticon: this.includeGrunticon
		}
	);

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_javascript.js'),
		this.destinationPath('_grunt-configs/javascript.js'),
		{
			browserify: this.browserify,
			includeJquery1: this.includeJquery1,
			includeJquery2: this.includeJquery2,
			includeShims: this.includeShims
		}
	);

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_server.js'),
		this.destinationPath('_grunt-configs/server.js'),
		{
			statix: this.includeStatix,
			styleguide: this.includeStyleguide
		}
	);

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_utilities.js'),
		this.destinationPath('_grunt-configs/utilities.js'),
		{
			browserify: this.browserify,
			statix: this.includeStatix,
			styleguide: this.includeStyleguide,
			shims: this.includeShims,
			modernizr: this.includeModernizr
		}
	);

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_watch.js'),
		this.destinationPath('_grunt-configs/watch.js'),
		{
			browserify: this.browserify,
			statix: this.includeStatix,
			grunticon: this.includeGrunticon
		}
	);

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_tests.js'),
		this.destinationPath('_grunt-configs/tests.js'),
		{}
	);
	this.copy('_grunt-configs/grunticon-tpl.hbs', '_grunt-configs/grunticon-tpl.hbs');

	this.fs.copyTpl(
		this.templatePath('_package.json'),
		this.destinationPath('package.json'),
		{
			projectName: this.projectName,
			projectNameSlugified: _s.slugify(this.projectName),
			projectDescription: this.projectDescription,
			devNames: this.devNames,
			browserify: this.browserify,
			includeSwiftclick: this.includeSwiftclick,
			includeTrak: this.includeTrak,
			includeJquery1: this.includeJquery1,
			includeJquery2: this.includeJquery2,
			statix: this.includeStatix
		}
	);

	this.fs.copyTpl(
		this.templatePath('_readme.md'),
		this.destinationPath('readme.md'),
		{
			projectName: this.projectName,
			projectDescription: this.projectDescription,
			devNames: this.devNames
		}
	);

	this.fs.copyTpl(
		this.templatePath('_humans.txt'),
		this.destinationPath('humans.txt'),
		{
			projectName: this.projectName,
			projectDescription: this.projectDescription,
			devNames: this.devNames
		}
	);

	this.fs.copyTpl(
		this.templatePath('_jshintrc'),
		this.destinationPath('.jshintrc'),
		{
			includeJquery1: this.includeJquery1,
			includeJquery2: this.includeJquery2
		}
	);

	this.copy('editorconfig', '.editorconfig');
	this.copy('gitignore', '.gitignore');
	this.copy('gitattributes', '.gitattributes');
	this.copy('scss-lint.yml', '.scss-lint.yml');

	if (this.includeStatix) {
		this.directory('statix/dist', 'statix/dist');

		this.directory('statix/src/data', 'statix/src/data');
		this.directory('statix/src/helpers', 'statix/src/helpers');

		if (this.includeStyleguide) {
			this.directory('statix/src/templates/layouts', 'statix/src/templates/layouts');
			this.directory('statix/src/templates/views', 'statix/src/templates/views');
		} else {
			this.copy('statix/src/templates/views/index.hbs', 'statix/src/templates/views/index.hbs');
			this.copy('statix/src/templates/layouts/default.hbs', 'statix/src/templates/layouts/default.hbs');
		}

		this.directory('statix/src/templates/partials', 'statix/src/templates/partials');

		this.fs.copyTpl(
			this.templatePath('statix/src/templates/_html_start.hbs'),
			this.destinationPath('statix/src/templates/partials/html_start.hbs'),
			{
				projectName: this.projectName,
				projectNameSlugified: _s.slugify(this.projectName),
				projectDescription: this.projectDescription,
				oldIE: this.oldIE,
				grunticon: this.includeGrunticon,
				modernizr: this.includeModernizr
			}
		);
	}
};

KickoffGenerator.prototype.install = function packageFiles() {
	opn('http://trykickoff.com/learn/checklist.html');
	this.installDependencies();
};
<commit_msg>swap ampersand for `and`<commit_after>'use strict';
var util            = require('util');
var yeoman          = require('yeoman-generator');
var chalk           = require('chalk');
var updateNotifier  = require('update-notifier');
var pkg             = require('../package.json');
var opn             = require('opn');
var _s              = require('underscore.string');

var KickoffGenerator = module.exports = function KickoffGenerator(args, options) {
	yeoman.generators.Base.apply(this, arguments);
};

util.inherits(KickoffGenerator, yeoman.generators.Base);

KickoffGenerator.prototype.askFor = function () {
	var done = this.async();

	// Checks for available update and returns an instance
	var notifier = updateNotifier({
		packageName: pkg.name,
		packageVersion: pkg.version,
		updateCheckInterval: 1000 * 60 // Every hour
	});

	var kickoffWelcome = chalk.white('\n ##  ## ######  ####  ##  ##  ') + chalk.yellow('####  ###### ######') + chalk.white('\n ## ##    ##   ##  ## ## ##  ') + chalk.yellow('##  ## ##     ##') + chalk.white('\n ####     ##   ##     ####   ') + chalk.yellow('##  ## ####   ####') + chalk.white('\n ## ##    ##   ##  ## ## ##  ') + chalk.yellow('##  ## ##     ##') + chalk.white('\n ##  ## ######  ####  ##  ##  ') + chalk.yellow('####  ##     ##') + '\n\n ' + chalk.white.bold('A Yeoman generator for the Kickoff front-end framework') + '\n\n Find out more at ' + chalk.cyan('trykickoff.com') + '\n Yeoman Generator version:  ' + pkg.version + '\n\n Kickoff is free and open-source and maintained by ' + chalk.yellow('@MrMartineau') + ',\n ' + chalk.green('@AshNolan_') + ', ' + chalk.red('@nicbell') + ' & the ' + chalk.blue('@tmwTechTeam') + '. \n';

	// Have Yeoman greet the user.
	this.log(kickoffWelcome);

	if (notifier.update) {
		// Check for npm package update and print message if needed
		var updateMessage = chalk.yellow('   ┌────────────────────────────────────────────────┐\n   │') + ' Update available: '  + chalk.green(notifier.update.latest) + chalk.gray(' (current: ' + pkg.version + ')') + '       '+ chalk.yellow('│\n   │') + ' Run ' + chalk.cyan('npm update -g ' + pkg.name) + ' to update. ' + chalk.yellow('│\n   └────────────────────────────────────────────────┘\n');

		this.log(updateMessage);
	}

	var prompts = [
		{
			name: 'projectName',
			message: 'Project name',
			default: 'Your project name'
		},
		{
			name: 'projectDescription',
			message: 'Description',
			default: 'Project description'
		},
		{
			name: 'devNames',
			message: 'Developer\'s names?',
			default: 'Tom, Dick and Harry'
		},
		{
			name: 'features',
			type: 'checkbox',
			message: 'Which features would you like?',
			choices: [
				{
					name: 'Does this project support IE8?',
					value: 'oldIE',
					default: false,
				},
				{
					name: 'Include Kickoff\'s styleguide?',
					value: 'styleguide'
				},
				{
					name: 'Use Kickoff Statix?',
					value: 'statix'
				},
				{
					name: 'Use Grunticon?',
					value: 'grunticon'
				}
			],
			store: true
		},
		{
			name: 'browserify',
			type: 'confirm',
			message: 'Use Browserify to bundle your Javascript?',
			default: true,
			store: true
		},
		{
			name: 'jsNamespace',
			message: 'Choose your javascript namespace',
			default: 'KO',
			store: true,
			when: function(response) {
				return !response.browserify;
			}
		},
		{
			name: 'jsLibs',
			type: 'checkbox',
			message: 'Which Javascript libraries would you like to use?',
			choices: [
				{
					name: 'jQuery 1.x - only choose one jQuery version',
					value: 'jquery1'
				},
				{
					name: 'jQuery 2.x - only choose one jQuery version',
					value: 'jquery2'
				},
				{
					name: 'trak.js - Universal event tracking API',
					value: 'trak'
				},
				{
					name: 'Swiftclick - Eliminates the 300ms click event delay on touch devices',
					value: 'swiftclick'
				},
				{
					name: 'Include some Javascript polyfills/shims? (These are generated by the \'grunt shimly\' command)',
					value: 'shims'
				},
				{
					name: 'Use Modernizr?',
					value: 'modernizr'
				}
			],
			store: true
		}
	];

	this.prompt(prompts, function (answers) {
		for (var key in answers) {
			this[key] = answers[key];
		}

		var jsLibs = answers.jsLibs;
		var features = answers.features;

		function hasFeature(feat, prop) {
			return prop && prop.indexOf(feat) !== -1;
		}

		console.log('jsLibs', jsLibs);
		console.log('features', features);

		// JS Libs
		this.includeTrak       = hasFeature('trak', jsLibs);
		this.includeJquery1    = hasFeature('jquery1', jsLibs);
		this.includeJquery2    = hasFeature('jquery2', jsLibs);
		this.includeSwiftclick = hasFeature('swiftclick', jsLibs);
		this.includeShims      = hasFeature('shims', jsLibs);
		this.includeModernizr  = hasFeature('modernizr', jsLibs);

		// Features
		this.includeGrunticon  = hasFeature('grunticon', features);
		this.includeStatix     = hasFeature('statix', features);
		this.includeStyleguide = hasFeature('styleguide', features);
		this.oldIE = hasFeature('oldIE', features);

		done();
	}.bind(this));
};

/**
 * Info
 * http://yeoman.io/generator/actions_actions.html
 * http://yeoman.io/authoring/file-system.html
 */
KickoffGenerator.prototype.packageFiles = function packageFiles() {

	this.fs.copyTpl(
		this.templatePath('_index.html'),
		this.destinationPath('index.html'),
		{
			projectName: this.projectName,
			projectNameSlugified: _s.slugify(this.projectName),
			oldIE: this.oldIE,
			grunticon: this.includeGrunticon,
			modernizr: this.includeModernizr,
			shims: this.includeShims
		}
	);

	if (this.includeStyleguide && !this.includeStatix) {
		this.fs.copyTpl(
			this.templatePath('styleguide/_index.html'),
			this.destinationPath('styleguide/index.html'),
			{
				projectName: this.projectName,
				projectNameSlugified: _s.slugify(this.projectName),
				oldIE: this.oldIE,
				grunticon: this.includeGrunticon,
				modernizr: this.includeModernizr,
				shims: this.includeShims
			}
		);
	}

	// CSS, SCSS, images & grunticon source directory
	this.directory('assets/dist/css', 'assets/dist/css');
	this.directory('assets/src/scss', 'assets/src/scss');
	this.directory('assets/src/img', 'assets/src/img');
	this.directory('assets/src/grunticon', 'assets/src/grunticon');

	// Javascript
	if (this.browserify) {
		this.fs.copyTpl(
			this.templatePath('assets/src/js/_script-browserify.js'),
			this.destinationPath('assets/src/js/script.js'),
			{
				projectName: this.projectName,
				devNames: this.devNames,
				browserify: this.browserify,
				includeSwiftclick: this.includeSwiftclick,
				includeTrak: this.includeTrak,
				includeJquery1: this.includeJquery1,
				includeJquery2: this.includeJquery2,
				statix: this.includeStatix,
				shims: this.includeShims
			}
		);

		this.directory('assets/src/js/modules', 'assets/src/js/modules');

	} else {
		this.fs.copyTpl(
			this.templatePath('assets/src/js/_script-fileArray.js'),
			this.destinationPath('assets/src/js/script.js'),
			{
				projectName: this.projectName,
				devNames: this.devNames,
				includeJquery1: this.includeJquery1,
				includeJquery2: this.includeJquery2,
				jsNamespace: this.jsNamespace
			}
		);
	}

	if (this.modernizr) {
		this.copy('assets/src/js/standalone/modernizr.js', 'assets/src/js/standalone/modernizr.js');
	}

	if (this.shims) {
		this.copy('assets/src/js/standalone/shims.js', 'assets/src/js/standalone/shims.js');
	}

	// Grunt configs
	this.fs.copyTpl(
		this.templatePath('_Gruntfile.js'),
		this.destinationPath('Gruntfile.js'),
		{
			browserify: this.browserify,
			grunticon: this.includeGrunticon,
			modernizr: this.includeModernizr,
			statix: this.includeStatix,
			shims: this.includeShims,
			styleguide: this.includeStyleguide
		}
	);

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_config.js'),
		this.destinationPath('_grunt-configs/config.js'),
		{
			projectName: this.projectName,
			projectNameSlugified: _s.slugify(this.projectName),
			browserify: this.browserify,
			includeSwiftclick: this.includeSwiftclick,
			includeTrak: this.includeTrak,
			includeJquery1: this.includeJquery1,
			includeJquery2: this.includeJquery2,
			statix: this.includeStatix
		}
	);

	this.copy('_grunt-configs/css.js', '_grunt-configs/css.js');

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_images.js'),
		this.destinationPath('_grunt-configs/images.js'),
		{
			grunticon: this.includeGrunticon
		}
	);

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_javascript.js'),
		this.destinationPath('_grunt-configs/javascript.js'),
		{
			browserify: this.browserify,
			includeJquery1: this.includeJquery1,
			includeJquery2: this.includeJquery2,
			includeShims: this.includeShims
		}
	);

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_server.js'),
		this.destinationPath('_grunt-configs/server.js'),
		{
			statix: this.includeStatix,
			styleguide: this.includeStyleguide
		}
	);

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_utilities.js'),
		this.destinationPath('_grunt-configs/utilities.js'),
		{
			browserify: this.browserify,
			statix: this.includeStatix,
			styleguide: this.includeStyleguide,
			shims: this.includeShims,
			modernizr: this.includeModernizr
		}
	);

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_watch.js'),
		this.destinationPath('_grunt-configs/watch.js'),
		{
			browserify: this.browserify,
			statix: this.includeStatix,
			grunticon: this.includeGrunticon
		}
	);

	this.fs.copyTpl(
		this.templatePath('_grunt-configs/_tests.js'),
		this.destinationPath('_grunt-configs/tests.js'),
		{}
	);
	this.copy('_grunt-configs/grunticon-tpl.hbs', '_grunt-configs/grunticon-tpl.hbs');

	this.fs.copyTpl(
		this.templatePath('_package.json'),
		this.destinationPath('package.json'),
		{
			projectName: this.projectName,
			projectNameSlugified: _s.slugify(this.projectName),
			projectDescription: this.projectDescription,
			devNames: this.devNames,
			browserify: this.browserify,
			includeSwiftclick: this.includeSwiftclick,
			includeTrak: this.includeTrak,
			includeJquery1: this.includeJquery1,
			includeJquery2: this.includeJquery2,
			statix: this.includeStatix
		}
	);

	this.fs.copyTpl(
		this.templatePath('_readme.md'),
		this.destinationPath('readme.md'),
		{
			projectName: this.projectName,
			projectDescription: this.projectDescription,
			devNames: this.devNames
		}
	);

	this.fs.copyTpl(
		this.templatePath('_humans.txt'),
		this.destinationPath('humans.txt'),
		{
			projectName: this.projectName,
			projectDescription: this.projectDescription,
			devNames: this.devNames
		}
	);

	this.fs.copyTpl(
		this.templatePath('_jshintrc'),
		this.destinationPath('.jshintrc'),
		{
			includeJquery1: this.includeJquery1,
			includeJquery2: this.includeJquery2
		}
	);

	this.copy('editorconfig', '.editorconfig');
	this.copy('gitignore', '.gitignore');
	this.copy('gitattributes', '.gitattributes');
	this.copy('scss-lint.yml', '.scss-lint.yml');

	if (this.includeStatix) {
		this.directory('statix/dist', 'statix/dist');

		this.directory('statix/src/data', 'statix/src/data');
		this.directory('statix/src/helpers', 'statix/src/helpers');

		if (this.includeStyleguide) {
			this.directory('statix/src/templates/layouts', 'statix/src/templates/layouts');
			this.directory('statix/src/templates/views', 'statix/src/templates/views');
		} else {
			this.copy('statix/src/templates/views/index.hbs', 'statix/src/templates/views/index.hbs');
			this.copy('statix/src/templates/layouts/default.hbs', 'statix/src/templates/layouts/default.hbs');
		}

		this.directory('statix/src/templates/partials', 'statix/src/templates/partials');

		this.fs.copyTpl(
			this.templatePath('statix/src/templates/_html_start.hbs'),
			this.destinationPath('statix/src/templates/partials/html_start.hbs'),
			{
				projectName: this.projectName,
				projectNameSlugified: _s.slugify(this.projectName),
				projectDescription: this.projectDescription,
				oldIE: this.oldIE,
				grunticon: this.includeGrunticon,
				modernizr: this.includeModernizr
			}
		);
	}
};

KickoffGenerator.prototype.install = function packageFiles() {
	opn('http://trykickoff.com/learn/checklist.html');
	this.installDependencies();
};
<|endoftext|>