<commit_before>'use strict'
var path = require('path')
var fs = require('fs')
const Regex = require("regex");
const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow
const Menu = electron.Menu
const crashReporter = electron.crashReporter
const shell = electron.shell
const ipcMain = require('electron').ipcMain
let menu
let template
let mainWindow = null

const loki = require("lokijs")
console.log(app.getPath('userData'))

const cardDb = new loki(app.getPath('userData') + '/mainDatabase.ffdb',
  {
    autoload: true,
    autoloadCallback : loadHandler,
    autosave: true,
    autosaveInterval: 1000,
  });

  function loadHandler() {
    var coll = cardDb.getCollection('cards');
    if (coll === null) {
      coll = cardDb.addCollection('cards');
    }
    var coll1 = cardDb.getCollection('speech');
    if (coll1 === null) {
      coll1 = cardDb.addCollection('speech');
    }
  }

  function tagindex (datab) {
    console.log('\n')
    console.log('starting indexing: ')
    //tab index will return JSON in the form of a map of sTag:[CardTitles]
    /* example JSON
    {
      Aff: [card1, card2, card3],
      Pro: [card1, card22, card4]
    }
    */
    var dict = {}
    var PFST = [] //Previously Found S Tags, to avoid needless transversal of dict
    var cards = datab.getCollection("cards").data;
    var card, s, sTags
    for (card in cards) {                           //  go through each card
      sTags = JSON.parse(cards[card].sTags)      // turn sTags String into an array for transversal
      for (s in sTags) {                            // go through each sTag
        if(dict.hasOwnProperty(sTags[s]) && !dict[sTags[s]].includes(cards[card].tagLine)) {       // if the node already exists and tag is not already in node then
          console.log('Adding card ' + cards[card].tagLine +' to tag ' + sTags[s])
          dict[sTags[s]].push(cards[card].tagLine)                                                 // add the tag to the node
        } else {
          console.log('Adding card ' + cards[card].tagLine +' to newly created tag ' + sTags[s])
          dict[sTags[s]] = [cards[card].tagLine]                                                   // if the node does not already exist then create it and add tag
        }
      }
    }
    console.log(dict)
    console.log('\n')
    return dict;
  }

function speechindex (datab) {
  console.log('\n')
  //console.log('starting indexing: ')
  //tab index will return JSON in the form of a map of sTag:[CardTitles]
  /* example JSON
  {
    Aff: [card1, card2, card3],
    Pro: [card1, card22, card4]
  }
  */
  var dict = {}
  var PFST = [] //Previously Found S Tags, to avoid needless transversal of dict
  var cards = datab.getCollection("speech").data;
  var card, s, sTags, content, tagline, author
  for (card in cards) {                           //  go through each card
    sTags = cards[card].sTags
    content = cards[card].content
    tagline = cards[card].tagLine
    PFST.push(tagline.title)
  }

  //console.log(dict)
  console.log('\n')
  return PFST;

}

crashReporter.start()

if (process.env.NODE_ENV === 'development') {
  require('electron-debug')()
}

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit()
})

require('electron-debug')({
  showDevTools: true
})

app.on('ready', () => {
  mainWindow = new BrowserWindow({
    width: 1024,
    height: 728
  })

  mainWindow.loadURL(`file://${__dirname}/app.html`)

  mainWindow.on('closed', () => {
    mainWindow = null
  })

  if (process.env.NODE_ENV === 'development') {
    mainWindow.openDevTools()
  }

  if (process.platform === 'darwin') {
    template = [{
      label: 'Electron',
      submenu: [{
        label: 'About ElectronReact',
        selector: 'orderFrontStandardAboutPanel:'
      }, {
        type: 'separator'
      }, {
        label: 'Services',
        submenu: []
      }, {
        type: 'separator'
      }, {
        label: 'Hide ElectronReact',
        accelerator: 'Command+H',
        selector: 'hide:'
      }, {
        label: 'Hide Others',
        accelerator: 'Command+Shift+H',
        selector: 'hideOtherApplications:'
      }, {
        label: 'Show All',
        selector: 'unhideAllApplications:'
      }, {
        type: 'separator'
      }, {
        label: 'Quit',
        accelerator: 'Command+Q',
        click() {
          app.quit()
        }
      }]
    }, {
      label: 'Edit',
      submenu: [{
        label: 'Undo',
        accelerator: 'Command+Z',
        selector: 'undo:'
      }, {
        label: 'Redo',
        accelerator: 'Shift+Command+Z',
        selector: 'redo:'
      }, {
        type: 'separator'
      }, {
        label: 'Cut',
        accelerator: 'Command+X',
        selector: 'cut:'
      }, {
        label: 'Copy',
        accelerator: 'Command+C',
        selector: 'copy:'
      }, {
        label: 'Paste',
        accelerator: 'Command+V',
        selector: 'paste:'
      }, {
        label: 'Select All',
        accelerator: 'Command+A',
        selector: 'selectAll:'
      }]
    }, {
      label: 'View',
      submenu: (process.env.NODE_ENV === 'development') ? [{
        label: 'Reload',
        accelerator: 'Command+R',
        click() {
          mainWindow.restart()
        }
      }, {
        label: 'Toggle Full Screen',
        accelerator: 'Ctrl+Command+F',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen())
        }
      }, {
        label: 'Toggle Developer Tools',
        accelerator: 'Alt+Command+I',
        click() {
          mainWindow.toggleDevTools()
        }
      }] : [{
        label: 'Toggle Full Screen',
        accelerator: 'Ctrl+Command+F',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen())
        }
      }]
    }, {
      label: 'Window',
      submenu: [{
        label: 'Minimize',
        accelerator: 'Command+M',
        selector: 'performMiniaturize:'
      }, {
        label: 'Close',
        accelerator: 'Command+W',
        selector: 'performClose:'
      }, {
        type: 'separator'
      }, {
        label: 'Bring All to Front',
        selector: 'arrangeInFront:'
      }]
    }, {
      label: 'Help',
      submenu: [{
        label: 'Learn More',
        click() {
          shell.openExternal('http://electron.atom.io')
        }
      }, {
        label: 'Documentation',
        click() {
          shell.openExternal('https://github.com/atom/electron/tree/master/docs#readme')
        }
      }, {
        label: 'Community Discussions',
        click() {
          shell.openExternal('https://discuss.atom.io/c/electron')
        }
      }, {
        label: 'Search Issues',
        click() {
          shell.openExternal('https://github.com/atom/electron/issues')
        }
      }]
    }]

    menu = Menu.buildFromTemplate(template)
    Menu.setApplicationMenu(menu)
  } else {
    template = [{
      label: '&File',
      submenu: [{
        label: '&Open',
        accelerator: 'Ctrl+O'
      }, {
        label: '&Close',
        accelerator: 'Ctrl+W',
        click () {
          mainWindow.close()
        }
      }]
    }, {
      label: '&View',
      submenu: (process.env.NODE_ENV === 'development') ? [{
        label: '&Reload',
        accelerator: 'Ctrl+R',
        click () {
          mainWindow.reload()
        }
      }, {
        label: 'Toggle &Full Screen',
        accelerator: 'F11',
        click () {
          mainWindow.setFullScreen(!mainWindow.isFullScreen())
        }
      }, {
        label: 'Toggle &Developer Tools',
        accelerator: 'Alt+Ctrl+I',
        click () {
          mainWindow.toggleDevTools()
        }
      }] : [{
        label: 'Toggle &Full Screen',
        accelerator: 'F11',
        click () {
          mainWindow.setFullScreen(!mainWindow.isFullScreen())
        }
      }]
    }, {
      label: 'Help',
      submenu: [{
        label: 'Learn More',
        click () {
          shell.openExternal('http://electron.atom.io')
        }
      }, {
        label: 'Documentation',
        click () {
          shell.openExternal('https://github.com/atom/electron/tree/master/docs#readme')
        }
      }, {
        label: 'Community Discussions',
        click () {
          shell.openExternal('https://discuss.atom.io/c/electron')
        }
      }, {
        label: 'Search Issues',
        click () {
          shell.openExternal('https://github.com/atom/electron/issues')
        }
      }]
    }]
    menu = Menu.buildFromTemplate(template)
    mainWindow.setMenu(menu)
  }

  function uniq(a){
    //Im not walking through this, cuz honestly, i dont know what this does anymore, but it works, so be happy
      var prims = {"boolean":{}, "number":{}, "string":{}}, objs = [];

      return a.filter(function(item) {
          var type = typeof item;
          if(type in prims)
              return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);
          else
              return objs.indexOf(item) >= 0 ? false : objs.push(item);
      });
    }

  function addCardToLoki(datab, cardTagline, cardTags, cardCitation, cardContent, cardNotes) {
     //If you are reading this code and cant figure out what this does, then you need to stop reading this code right now and
     //get a different profession. It legit says "addCardToLoki" cuz thats what it does
      var cards = datab.getCollection("cards")
    	console.log(cardTags)
    	cards.insert({
    		tagLine: cardTagline,
    		sTags: cardTags,
    		citation: cardCitation,
    		content: cardContent,
    		notes: cardNotes
    	})
    	datab.saveDatabase()
    }

  function addCardToSpeech(datab, cardTagline, cardTags, cardContent) {
     //If you are reading this code and cant figure out what this does, then you need to stop reading this code right now and
     //get a different profession. It legit says "addCardToSpeech" cuz thats what it does
      var cards = datab.getCollection("speech")
    	console.log(cardTags)
    	cards.insert({
    		tagLine: cardTagline,
    		sTags: cardTags,
    		content: cardContent
    	})
    	datab.saveDatabase()
    }

  function deleteCard(datab, collection, cardName){
    //Umm, its pretty obvious, it deletes a card, duh
      var cards = datab.getCollection(collection);
      cards.removeWhere({'tagLine': {'$eq': cardName}})
    }

  function getCard(datab, collection, searchTerm){
    //ok, so this should be used to get cards from anything, but as you can see, its not, so maybe we'll integrate that to make it better
      var cards = datab.getCollection(collection);
      if(collection != "speech"){
        var cardNames = cards.find({'tagLine': {'$contains': searchTerm}});
      }else{
        var cardNames = cards.where(function(obj) {
            return (obj.tagLine["title"] == searchTerm);
        });
      }
      return cardNames;
    }

  function searchSimple(datab, collection, searchTerm){
    /*Okie dokie kids, this should work, I'm fairly confident, but if it doesnt, Uncle Pranav
     has a long day ahead of him or maybe a short day depending on what he wants to do with it idk*/
      var cards = datab.getCollection(collection);
      var returnListCards = []
      var cardTags = cards.find({'sTags': {'$contains': searchTerm}})
      var cardNames = cards.find({'tagLine': {'$contains': searchTerm}})
      var temp1 = 0;
      var temp2 = 0;

      if(cardTags != []){
        for (temp1 in cardTags){
          returnListCards.push(cardTags[temp1].name)
        }
      }

      if(cardNames != []){
        for (temp2 in cardNames){
          returnListCards.push(cardNames[temp2].name)
        }
      }
      return uniq(returnListCards)
    }

  /* The rest of this is IPC stuff */

    ipcMain.on('Search', function (event, arg) {
      console.log(arg)
      console.log("-----------")
      console.log(searchSimple(cardDb, "cards", arg))
      event.returnValue = searchSimple(cardDb, arg)
    })

    ipcMain.on('SearchSpeeches', function (event, arg) {
      console.log(arg)
      console.log("-----------")
      console.log(searchSimple(cardDb, "speech", arg))
      event.returnValue = searchSimple(cardDb,"speech", arg)
    })

    ipcMain.on('FileOpen', function (event, arg) {
      var foundCard = getCard(cardDb, "cards", arg)
      if(foundCard[0]){
        console.log('opening: ' + foundCard[0])
        event.returnValue = foundCard[0]
      } else {
        event.returnValue = false
      }
    })

    ipcMain.on('SpeechOpen', function (event, arg) {
      var foundCard = getCard(cardDb, "speech", arg)
      if(foundCard[0]){
        //console.log('opening: ' + foundCard)
        event.returnValue = JSON.stringify(foundCard[0])
      } else {
        event.returnValue = false
      }
    })

    ipcMain.on('FileRemove', function (event, arg) {
      //removeCard(db, cardName, cardTags, cardContent)
      deleteCard(cardDb, "cards", arg)
      console.log("removing:")
      console.log(arg)
      console.log("---------------")
      //removeCard(cardDb, arg[0], arg[1], arg[2])
    })

    ipcMain.on('SpeechRemove', function (event, arg) {
      //removeCard(db, cardName, cardTags, cardContent)
      deleteCard(cardDb, "speech", arg)
      console.log("removing:")
      console.log(arg)
      console.log("---------------")
      //removeCard(cardDb, arg[0], arg[1], arg[2])
    })

    ipcMain.on('CardManager', function (event, arg) {
      var dataJSON = tagindex(cardDb)
      console.log(dataJSON)
      event.returnValue = dataJSON
    })

    ipcMain.on('SpeechManager', function (event, arg) {
      var dataJSON = speechindex(cardDb)
      //console.log(dataJSON)
      event.returnValue = dataJSON
    })

    /* card saving */
    ipcMain.on('FileSave', function (event, arg) {
      console.log(arg)
      // [TitleString, TagString, ContentString]
      var cards = cardDb.getCollection("cards");
      var tagLine = arg.tagLine
      var sTags = arg.sTags
      var content = arg.content
      var notes = arg.notes
      var cite = arg.citation
      var temp = cards.find({'tagLine' : tagLine})
      if (temp.length !== 0){
        cards.removeWhere({'tagLine' : tagLine})
      }
      addCardToLoki(cardDb, tagLine, sTags, cite, content, notes);
      tagindex(cardDb)
    })

    /* speech saving */
    ipcMain.on('SpeechSave', function (event, arg) {
      console.log(arg)
      // [TitleString, TagString, ContentString]
      var cards = cardDb.getCollection("speech");
      var tagLine = arg.tagLine
      var sTags = arg.sTags
      var content = arg.content
      var temp = cards.find({'tagLine' : tagLine})
      if (temp.length !== 0){
        cards.removeWhere({'tagLine' : tagLine})
      }
      addCardToSpeech(cardDb, tagLine, sTags, content);
      speechindex(cardDb);
    })

  })
<commit_msg>Speech works except for duplicates<commit_after>'use strict'
var path = require('path')
var fs = require('fs')
const Regex = require("regex");
const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow
const Menu = electron.Menu
const crashReporter = electron.crashReporter
const shell = electron.shell
const ipcMain = require('electron').ipcMain
let menu
let template
let mainWindow = null

const loki = require("lokijs")
console.log(app.getPath('userData'))

const cardDb = new loki(app.getPath('userData') + '/mainDatabase.ffdb',
  {
    autoload: true,
    autoloadCallback : loadHandler,
    autosave: true,
    autosaveInterval: 1000,
  });

  function loadHandler() {
    var coll = cardDb.getCollection('cards');
    if (coll === null) {
      coll = cardDb.addCollection('cards');
    }
    var coll1 = cardDb.getCollection('speech');
    if (coll1 === null) {
      coll1 = cardDb.addCollection('speech');
    }
  }

  function tagindex (datab) {
    console.log('\n')
    console.log('starting indexing: ')
    //tab index will return JSON in the form of a map of sTag:[CardTitles]
    /* example JSON
    {
      Aff: [card1, card2, card3],
      Pro: [card1, card22, card4]
    }
    */
    var dict = {}
    var PFST = [] //Previously Found S Tags, to avoid needless transversal of dict
    var cards = datab.getCollection("cards").data;
    var card, s, sTags
    for (card in cards) {                           //  go through each card
      sTags = JSON.parse(cards[card].sTags)      // turn sTags String into an array for transversal
      for (s in sTags) {                            // go through each sTag
        if(dict.hasOwnProperty(sTags[s]) && !dict[sTags[s]].includes(cards[card].tagLine)) {       // if the node already exists and tag is not already in node then
          console.log('Adding card ' + cards[card].tagLine +' to tag ' + sTags[s])
          dict[sTags[s]].push(cards[card].tagLine)                                                 // add the tag to the node
        } else {
          console.log('Adding card ' + cards[card].tagLine +' to newly created tag ' + sTags[s])
          dict[sTags[s]] = [cards[card].tagLine]                                                   // if the node does not already exist then create it and add tag
        }
      }
    }
    console.log(dict)
    console.log('\n')
    return dict;
  }

function speechindex (datab) {
  console.log('\n')
  //console.log('starting indexing: ')
  //tab index will return JSON in the form of a map of sTag:[CardTitles]
  /* example JSON
  {
    Aff: [card1, card2, card3],
    Pro: [card1, card22, card4]
  }
  */
  var dict = {}
  var PFST = [] //Previously Found S Tags, to avoid needless transversal of dict
  var cards = datab.getCollection("speech").data;
  var card, s, sTags, content, tagline, author
  for (card in cards) {                           //  go through each card
    sTags = cards[card].sTags
    content = cards[card].content
    tagline = cards[card].tagLine
    PFST.push(tagline.title)
  }

  //console.log(dict)
  console.log('\n')
  return PFST;

}

crashReporter.start()

if (process.env.NODE_ENV === 'development') {
  require('electron-debug')()
}

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit()
})

require('electron-debug')({
  showDevTools: true
})

app.on('ready', () => {
  mainWindow = new BrowserWindow({
    width: 1024,
    height: 728
  })

  mainWindow.loadURL(`file://${__dirname}/app.html`)

  mainWindow.on('closed', () => {
    mainWindow = null
  })

  if (process.env.NODE_ENV === 'development') {
    mainWindow.openDevTools()
  }

  if (process.platform === 'darwin') {
    template = [{
      label: 'Electron',
      submenu: [{
        label: 'About ElectronReact',
        selector: 'orderFrontStandardAboutPanel:'
      }, {
        type: 'separator'
      }, {
        label: 'Services',
        submenu: []
      }, {
        type: 'separator'
      }, {
        label: 'Hide ElectronReact',
        accelerator: 'Command+H',
        selector: 'hide:'
      }, {
        label: 'Hide Others',
        accelerator: 'Command+Shift+H',
        selector: 'hideOtherApplications:'
      }, {
        label: 'Show All',
        selector: 'unhideAllApplications:'
      }, {
        type: 'separator'
      }, {
        label: 'Quit',
        accelerator: 'Command+Q',
        click() {
          app.quit()
        }
      }]
    }, {
      label: 'Edit',
      submenu: [{
        label: 'Undo',
        accelerator: 'Command+Z',
        selector: 'undo:'
      }, {
        label: 'Redo',
        accelerator: 'Shift+Command+Z',
        selector: 'redo:'
      }, {
        type: 'separator'
      }, {
        label: 'Cut',
        accelerator: 'Command+X',
        selector: 'cut:'
      }, {
        label: 'Copy',
        accelerator: 'Command+C',
        selector: 'copy:'
      }, {
        label: 'Paste',
        accelerator: 'Command+V',
        selector: 'paste:'
      }, {
        label: 'Select All',
        accelerator: 'Command+A',
        selector: 'selectAll:'
      }]
    }, {
      label: 'View',
      submenu: (process.env.NODE_ENV === 'development') ? [{
        label: 'Reload',
        accelerator: 'Command+R',
        click() {
          mainWindow.restart()
        }
      }, {
        label: 'Toggle Full Screen',
        accelerator: 'Ctrl+Command+F',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen())
        }
      }, {
        label: 'Toggle Developer Tools',
        accelerator: 'Alt+Command+I',
        click() {
          mainWindow.toggleDevTools()
        }
      }] : [{
        label: 'Toggle Full Screen',
        accelerator: 'Ctrl+Command+F',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen())
        }
      }]
    }, {
      label: 'Window',
      submenu: [{
        label: 'Minimize',
        accelerator: 'Command+M',
        selector: 'performMiniaturize:'
      }, {
        label: 'Close',
        accelerator: 'Command+W',
        selector: 'performClose:'
      }, {
        type: 'separator'
      }, {
        label: 'Bring All to Front',
        selector: 'arrangeInFront:'
      }]
    }, {
      label: 'Help',
      submenu: [{
        label: 'Learn More',
        click() {
          shell.openExternal('http://electron.atom.io')
        }
      }, {
        label: 'Documentation',
        click() {
          shell.openExternal('https://github.com/atom/electron/tree/master/docs#readme')
        }
      }, {
        label: 'Community Discussions',
        click() {
          shell.openExternal('https://discuss.atom.io/c/electron')
        }
      }, {
        label: 'Search Issues',
        click() {
          shell.openExternal('https://github.com/atom/electron/issues')
        }
      }]
    }]

    menu = Menu.buildFromTemplate(template)
    Menu.setApplicationMenu(menu)
  } else {
    template = [{
      label: '&File',
      submenu: [{
        label: '&Open',
        accelerator: 'Ctrl+O'
      }, {
        label: '&Close',
        accelerator: 'Ctrl+W',
        click () {
          mainWindow.close()
        }
      }]
    }, {
      label: '&View',
      submenu: (process.env.NODE_ENV === 'development') ? [{
        label: '&Reload',
        accelerator: 'Ctrl+R',
        click () {
          mainWindow.reload()
        }
      }, {
        label: 'Toggle &Full Screen',
        accelerator: 'F11',
        click () {
          mainWindow.setFullScreen(!mainWindow.isFullScreen())
        }
      }, {
        label: 'Toggle &Developer Tools',
        accelerator: 'Alt+Ctrl+I',
        click () {
          mainWindow.toggleDevTools()
        }
      }] : [{
        label: 'Toggle &Full Screen',
        accelerator: 'F11',
        click () {
          mainWindow.setFullScreen(!mainWindow.isFullScreen())
        }
      }]
    }, {
      label: 'Help',
      submenu: [{
        label: 'Learn More',
        click () {
          shell.openExternal('http://electron.atom.io')
        }
      }, {
        label: 'Documentation',
        click () {
          shell.openExternal('https://github.com/atom/electron/tree/master/docs#readme')
        }
      }, {
        label: 'Community Discussions',
        click () {
          shell.openExternal('https://discuss.atom.io/c/electron')
        }
      }, {
        label: 'Search Issues',
        click () {
          shell.openExternal('https://github.com/atom/electron/issues')
        }
      }]
    }]
    menu = Menu.buildFromTemplate(template)
    mainWindow.setMenu(menu)
  }

  function uniq(a){
    //Im not walking through this, cuz honestly, i dont know what this does anymore, but it works, so be happy
      var prims = {"boolean":{}, "number":{}, "string":{}}, objs = [];

      return a.filter(function(item) {
          var type = typeof item;
          if(type in prims)
              return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);
          else
              return objs.indexOf(item) >= 0 ? false : objs.push(item);
      });
    }

  function addCardToLoki(datab, cardTagline, cardTags, cardCitation, cardContent, cardNotes) {
     //If you are reading this code and cant figure out what this does, then you need to stop reading this code right now and
     //get a different profession. It legit says "addCardToLoki" cuz thats what it does
      var cards = datab.getCollection("cards")
    	console.log(cardTags)
    	cards.insert({
    		tagLine: cardTagline,
    		sTags: cardTags,
    		citation: cardCitation,
    		content: cardContent,
    		notes: cardNotes
    	})
    	datab.saveDatabase()
    }

  function addCardToSpeech(datab, cardTagline, cardTags, cardContent) {
     //If you are reading this code and cant figure out what this does, then you need to stop reading this code right now and
     //get a different profession. It legit says "addCardToSpeech" cuz thats what it does
     console.log("------------------------------")
      var cards = datab.getCollection("speech")
    	console.log(cardTags)
    	cards.insert({
    		tagLine: cardTagline,
    		sTags: cardTags,
    		content: cardContent
    	})
    	datab.saveDatabase()
    }

  function deleteCard(datab, collection, cardName){
    //Umm, its pretty obvious, it deletes a card, duh
      var cards = datab.getCollection(collection);
      cards.removeWhere({'tagLine': {'$eq': cardName}})
    }

  function getCard(datab, collection, searchTerm){
    //ok, so this should be used to get cards from anything, but as you can see, its not, so maybe we'll integrate that to make it better
      var cards = datab.getCollection(collection);
      if(collection != "speech"){
        var cardNames = cards.find({'tagLine': {'$contains': searchTerm}});
      }else{
        var cardNames = cards.where(function(obj) {
            return (obj.tagLine["title"] == searchTerm);
        });
      }
      return cardNames;
    }

  function searchSimple(datab, collection, searchTerm){
    /*Okie dokie kids, this should work, I'm fairly confident, but if it doesnt, Uncle Pranav
     has a long day ahead of him or maybe a short day depending on what he wants to do with it idk*/
      var cards = datab.getCollection(collection);
      var returnListCards = []
      var cardTags = cards.find({'sTags': {'$contains': searchTerm}})
      var cardNames = cards.find({'tagLine': {'$contains': searchTerm}})
      var temp1 = 0;
      var temp2 = 0;

      if(cardTags != []){
        for (temp1 in cardTags){
          returnListCards.push(cardTags[temp1].name)
        }
      }

      if(cardNames != []){
        for (temp2 in cardNames){
          returnListCards.push(cardNames[temp2].name)
        }
      }
      return uniq(returnListCards)
    }

  /* The rest of this is IPC stuff */

    ipcMain.on('Search', function (event, arg) {
      console.log(arg)
      console.log("-----------")
      console.log(searchSimple(cardDb, "cards", arg))
      event.returnValue = searchSimple(cardDb, arg)
    })

    ipcMain.on('SearchSpeeches', function (event, arg) {
      console.log(arg)
      console.log("-----------")
      console.log(searchSimple(cardDb, "speech", arg))
      event.returnValue = searchSimple(cardDb,"speech", arg)
    })

    ipcMain.on('FileOpen', function (event, arg) {
      var foundCard = getCard(cardDb, "cards", arg)
      if(foundCard[0]){
        console.log('opening: ' + foundCard[0])
        event.returnValue = foundCard[0]
      } else {
        event.returnValue = false
      }
    })

    ipcMain.on('SpeechOpen', function (event, arg) {
      var foundCard = getCard(cardDb, "speech", arg)
      if(foundCard[0]){
        //console.log('opening: ' + foundCard)
        event.returnValue = JSON.stringify(foundCard[0])
      } else {
        event.returnValue = false
      }
    })

    ipcMain.on('FileRemove', function (event, arg) {
      //removeCard(db, cardName, cardTags, cardContent)
      deleteCard(cardDb, "cards", arg)
      console.log("removing:")
      console.log(arg)
      console.log("---------------")
      //removeCard(cardDb, arg[0], arg[1], arg[2])
    })

    ipcMain.on('SpeechRemove', function (event, arg) {
      //removeCard(db, cardName, cardTags, cardContent)
      deleteCard(cardDb, "speech", arg)
      console.log("removing:")
      console.log(arg)
      console.log("---------------")
      //removeCard(cardDb, arg[0], arg[1], arg[2])
    })

    ipcMain.on('CardManager', function (event, arg) {
      var dataJSON = tagindex(cardDb)
      console.log(dataJSON)
      event.returnValue = dataJSON
    })

    ipcMain.on('SpeechManager', function (event, arg) {
      var dataJSON = speechindex(cardDb)
      //console.log(dataJSON)
      event.returnValue = dataJSON
    })

    /* card saving */
    ipcMain.on('FileSave', function (event, arg) {
      console.log(arg)
      // [TitleString, TagString, ContentString]
      var cards = cardDb.getCollection("cards");
      var tagLine = arg.tagLine
      var sTags = arg.sTags
      var content = arg.content
      var notes = arg.notes
      var cite = arg.citation
      var temp = cards.find({'tagLine' : tagLine})
      if (temp.length !== 0){
        cards.removeWhere({'tagLine' : tagLine})
      }
      addCardToLoki(cardDb, tagLine, sTags, cite, content, notes);
      tagindex(cardDb)
    })

    /* speech saving */
    ipcMain.on('SpeechSave', function (event, arg) {
      console.log(arg)
      // [TitleString, TagString, ContentString]
      var cards = cardDb.getCollection("speech");
      var tagLine = arg.tagLine
      var sTags = arg.sTags
      var content = arg.content
      var temp = cards.where(function(obj) {
          return (obj.tagLine == tagLine);
      });

      if (temp.length !== 0){
        cards.removeWhere(function(obj) {
            return (obj.tagLine == tagLine);
        });      }
      addCardToSpeech(cardDb, tagLine, sTags, content);
      speechindex(cardDb);
    })

  })
<|endoftext|>


<commit_before>// process.on('uncaughtException', (...args) => console.error(...args))
const {app, BrowserWindow, Tray, Menu, ipcMain, shell} = require('electron')
const path = require('path')
const AppSettings = require('./utils/settings')
let microbreakIdeas = require('./microbreakIdeas')

let appIcon = null
let processWin = null
let microbreakWin = null
let appStartupWin = null
let aboutWin = null
let settingsWin = null
let finishMicrobreakTimer
let startMicrobreakTimer
let planMicrobreakTimer
let resumeMicrobreaksTimer
let settings
let isPaused = false

global.shared = {
  isNewVersion: false
}

function createTrayIcon () {
  if (process.platform === 'darwin') {
    app.dock.hide()
  }
  const iconPath = path.join(__dirname, 'images/stretchly_18x18.png')
  appIcon = new Tray(iconPath)
  appIcon.setToolTip('stretchly - break time reminder app')
  isPaused = false
  appIcon.setContextMenu(getTrayMenu())
}

function startProcessWin () {
  const modalPath = path.join('file://', __dirname, 'process.html')
  processWin = new BrowserWindow({
    show: false
  })
  processWin.loadURL(modalPath)
  processWin.webContents.on('did-finish-load', () => {
    planVersionCheck()
  })
}

function planVersionCheck (seconds = 1) {
  setTimeout(checkVersion, seconds * 1000)
}

function checkVersion () {
  processWin.webContents.send('checkVersion', `v${app.getVersion()}`)
  planVersionCheck(3600 * 5)
}

function showStartUpWindow () {
  const modalPath = path.join('file://', __dirname, 'start.html')
  appStartupWin = new BrowserWindow({
    frame: false,
    alwaysOnTop: true,
    title: 'stretchly',
    backgroundColor: settings.get('mainColor'),
    width: 600,
    height: 170
  })
  appStartupWin.loadURL(modalPath)
  setTimeout(function () {
    appStartupWin.close()
  }, 5000)
}

function startMicrobreak () {
  const modalPath = path.join('file://', __dirname, 'microbreak.html')
  microbreakWin = new BrowserWindow({
    frame: false,
    alwaysOnTop: true,
    backgroundColor: settings.get('mainColor'),
    title: 'stretchly'
  })
  microbreakWin.on('close', function () { microbreakWin = null })
  microbreakWin.loadURL(modalPath)
  // microbreakWin.webContents.openDevTools()
  microbreakWin.webContents.on('did-finish-load', () => {
    microbreakWin.webContents.send('breakIdea', microbreakIdeas.randomElement)
  })
  finishMicrobreakTimer = setTimeout(finishMicrobreak, settings.get('microbreakDuration'))
}

function finishMicrobreak (shouldPlaySound = true) {
  if (shouldPlaySound) {
    processWin.webContents.send('playSound', settings.get('microbreakAudio'))
  }
  microbreakWin.close()
  microbreakWin = null
  planMicrobreakTimer = setTimeout(planMicrobreak, 100)
}

function planMicrobreak (time) {
  let startTime = (typeof time === 'number') ? time :settings.get('microbreakInterval')
  startMicrobreakTimer = setTimeout(startMicrobreak, startTime)
}

ipcMain.on('finish-microbreak', function (event, shouldPlaySound) {
  clearTimeout(finishMicrobreakTimer)
  finishMicrobreak(shouldPlaySound)
})

ipcMain.on('save-setting', function (event, key, value) {
  settings.set(key, value)
  settingsWin.webContents.send('renderSettings', settings.data)
})

ipcMain.on('update-tray', function (event) {
  appIcon.setContextMenu(getTrayMenu())
})

let shouldQuit = app.makeSingleInstance(function (commandLine, workingDirectory) {
  if (appIcon) {
    // Someone tried to run a second instance
  }
})

if (shouldQuit) {
  console.log('stretchly is already running.')
  app.quit()
}

app.on('ready', startProcessWin)
app.on('ready', loadSettings)
app.on('ready', createTrayIcon)
app.on('ready', planMicrobreak)
app.on('ready', showStartUpWindow)

app.on('window-all-closed', () => {
  // do nothing, so app wont get closed
})

function loadSettings () {
  const dir = app.getPath('userData')
  const settingsFile = `${dir}/config.json`
  settings = new AppSettings(settingsFile)
}

function pauseMicrobreaks (seconds) {
  if (microbreakWin) {
    clearTimeout(finishMicrobreakTimer)
    finishMicrobreak()
  }
  clearTimeout(planMicrobreakTimer)
  clearTimeout(startMicrobreakTimer)
  if (seconds !== 1) {
    resumeMicrobreaksTimer = setTimeout(resumeMicrobreaks, seconds)
  }
  isPaused = true
  appIcon.setContextMenu(getTrayMenu())
}

function resumeMicrobreaks () {
  clearTimeout(resumeMicrobreaksTimer)
  isPaused = false
  appIcon.setContextMenu(getTrayMenu())
  planMicrobreak()
}

function showAboutWindow () {
  const modalPath = path.join('file://', __dirname, 'about.html')
  aboutWin = new BrowserWindow({
    alwaysOnTop: true,
    backgroundColor: settings.get('mainColor'),
    title: `About stretchly v${app.getVersion()}`
  })
  aboutWin.loadURL(modalPath)
}

function showSettingsWindow () {
  const modalPath = path.join('file://', __dirname, 'settings.html')
  settingsWin = new BrowserWindow({
    alwaysOnTop: true,
    backgroundColor: settings.get('mainColor'),
    title: 'Settings'
  })
  settingsWin.loadURL(modalPath)
  settingsWin.webContents.on('did-finish-load', () => {
    settingsWin.webContents.send('renderSettings', settings.data)
  })
}

function getTrayMenu () {
  let trayMenu = []
  if (global.shared.isNewVersion) {
    trayMenu.push({
      label: 'Download latest version',
      click: function () {
        shell.openExternal('https://github.com/hovancik/stretchly/releases')
      }
    })
  }

  trayMenu.push({
    label: 'About',
    click: function () {
      showAboutWindow()
    }
  }, {
    type: 'separator'
  })

  trayMenu.push({
    label: 'Start a break!',
    click: function () {
      planMicrobreak(200)
    }
  })

  if (isPaused) {
    trayMenu.push({
      label: 'Resume',
      click: function () {
        resumeMicrobreaks()
      }
    })
  } else {
    trayMenu.push({
      label: 'Pause',
      submenu: [
        {
          label: 'for an hour',
          click: function () {
            pauseMicrobreaks(3600 * 1000)
          }
        }, {
          label: 'for 2 hours',
          click: function () {
            pauseMicrobreaks(3600 * 2 * 1000)
          }
        }, {
          label: 'for 5 hours',
          click: function () {
            pauseMicrobreaks(3600 * 5 * 1000)
          }
        }, {
          label: 'indefinitely',
          click: function () {
            pauseMicrobreaks(1)
          }
        }
      ]
    })
  }

  trayMenu.push({
    label: 'Settings',
    click: function () {
      showSettingsWindow()
    }
  })

  if (process.platform === 'darwin' || process.platform === 'win32') {
    let loginItemSettings = app.getLoginItemSettings()
    let openAtLogin = loginItemSettings.openAtLogin
    trayMenu.push({
      label: 'Start at login',
      type: 'checkbox',
      checked: openAtLogin,
      click: function () {
        app.setLoginItemSettings({openAtLogin: !openAtLogin})
      }
    })
  }

  trayMenu.push({
    type: 'separator'
  }, {
    label: 'Quit',
    click: function () {
      app.quit()
    }
  })

  return Menu.buildFromTemplate(trayMenu)
}
<commit_msg>fix linting on ternary<commit_after>// process.on('uncaughtException', (...args) => console.error(...args))
const {app, BrowserWindow, Tray, Menu, ipcMain, shell} = require('electron')
const path = require('path')
const AppSettings = require('./utils/settings')
let microbreakIdeas = require('./microbreakIdeas')

let appIcon = null
let processWin = null
let microbreakWin = null
let appStartupWin = null
let aboutWin = null
let settingsWin = null
let finishMicrobreakTimer
let startMicrobreakTimer
let planMicrobreakTimer
let resumeMicrobreaksTimer
let settings
let isPaused = false

global.shared = {
  isNewVersion: false
}

function createTrayIcon () {
  if (process.platform === 'darwin') {
    app.dock.hide()
  }
  const iconPath = path.join(__dirname, 'images/stretchly_18x18.png')
  appIcon = new Tray(iconPath)
  appIcon.setToolTip('stretchly - break time reminder app')
  isPaused = false
  appIcon.setContextMenu(getTrayMenu())
}

function startProcessWin () {
  const modalPath = path.join('file://', __dirname, 'process.html')
  processWin = new BrowserWindow({
    show: false
  })
  processWin.loadURL(modalPath)
  processWin.webContents.on('did-finish-load', () => {
    planVersionCheck()
  })
}

function planVersionCheck (seconds = 1) {
  setTimeout(checkVersion, seconds * 1000)
}

function checkVersion () {
  processWin.webContents.send('checkVersion', `v${app.getVersion()}`)
  planVersionCheck(3600 * 5)
}

function showStartUpWindow () {
  const modalPath = path.join('file://', __dirname, 'start.html')
  appStartupWin = new BrowserWindow({
    frame: false,
    alwaysOnTop: true,
    title: 'stretchly',
    backgroundColor: settings.get('mainColor'),
    width: 600,
    height: 170
  })
  appStartupWin.loadURL(modalPath)
  setTimeout(function () {
    appStartupWin.close()
  }, 5000)
}

function startMicrobreak () {
  const modalPath = path.join('file://', __dirname, 'microbreak.html')
  microbreakWin = new BrowserWindow({
    frame: false,
    alwaysOnTop: true,
    backgroundColor: settings.get('mainColor'),
    title: 'stretchly'
  })
  microbreakWin.on('close', function () { microbreakWin = null })
  microbreakWin.loadURL(modalPath)
  // microbreakWin.webContents.openDevTools()
  microbreakWin.webContents.on('did-finish-load', () => {
    microbreakWin.webContents.send('breakIdea', microbreakIdeas.randomElement)
  })
  finishMicrobreakTimer = setTimeout(finishMicrobreak, settings.get('microbreakDuration'))
}

function finishMicrobreak (shouldPlaySound = true) {
  if (shouldPlaySound) {
    processWin.webContents.send('playSound', settings.get('microbreakAudio'))
  }
  microbreakWin.close()
  microbreakWin = null
  planMicrobreakTimer = setTimeout(planMicrobreak, 100)
}

function planMicrobreak (time) {
  let startTime = (typeof time === 'number') ? time : settings.get('microbreakInterval')
  startMicrobreakTimer = setTimeout(startMicrobreak, startTime)
}

ipcMain.on('finish-microbreak', function (event, shouldPlaySound) {
  clearTimeout(finishMicrobreakTimer)
  finishMicrobreak(shouldPlaySound)
})

ipcMain.on('save-setting', function (event, key, value) {
  settings.set(key, value)
  settingsWin.webContents.send('renderSettings', settings.data)
})

ipcMain.on('update-tray', function (event) {
  appIcon.setContextMenu(getTrayMenu())
})

let shouldQuit = app.makeSingleInstance(function (commandLine, workingDirectory) {
  if (appIcon) {
    // Someone tried to run a second instance
  }
})

if (shouldQuit) {
  console.log('stretchly is already running.')
  app.quit()
}

app.on('ready', startProcessWin)
app.on('ready', loadSettings)
app.on('ready', createTrayIcon)
app.on('ready', planMicrobreak)
app.on('ready', showStartUpWindow)

app.on('window-all-closed', () => {
  // do nothing, so app wont get closed
})

function loadSettings () {
  const dir = app.getPath('userData')
  const settingsFile = `${dir}/config.json`
  settings = new AppSettings(settingsFile)
}

function pauseMicrobreaks (seconds) {
  if (microbreakWin) {
    clearTimeout(finishMicrobreakTimer)
    finishMicrobreak()
  }
  clearTimeout(planMicrobreakTimer)
  clearTimeout(startMicrobreakTimer)
  if (seconds !== 1) {
    resumeMicrobreaksTimer = setTimeout(resumeMicrobreaks, seconds)
  }
  isPaused = true
  appIcon.setContextMenu(getTrayMenu())
}

function resumeMicrobreaks () {
  clearTimeout(resumeMicrobreaksTimer)
  isPaused = false
  appIcon.setContextMenu(getTrayMenu())
  planMicrobreak()
}

function showAboutWindow () {
  const modalPath = path.join('file://', __dirname, 'about.html')
  aboutWin = new BrowserWindow({
    alwaysOnTop: true,
    backgroundColor: settings.get('mainColor'),
    title: `About stretchly v${app.getVersion()}`
  })
  aboutWin.loadURL(modalPath)
}

function showSettingsWindow () {
  const modalPath = path.join('file://', __dirname, 'settings.html')
  settingsWin = new BrowserWindow({
    alwaysOnTop: true,
    backgroundColor: settings.get('mainColor'),
    title: 'Settings'
  })
  settingsWin.loadURL(modalPath)
  settingsWin.webContents.on('did-finish-load', () => {
    settingsWin.webContents.send('renderSettings', settings.data)
  })
}

function getTrayMenu () {
  let trayMenu = []
  if (global.shared.isNewVersion) {
    trayMenu.push({
      label: 'Download latest version',
      click: function () {
        shell.openExternal('https://github.com/hovancik/stretchly/releases')
      }
    })
  }

  trayMenu.push({
    label: 'About',
    click: function () {
      showAboutWindow()
    }
  }, {
    type: 'separator'
  })

  trayMenu.push({
    label: 'Start a break!',
    click: function () {
      planMicrobreak(200)
    }
  })

  if (isPaused) {
    trayMenu.push({
      label: 'Resume',
      click: function () {
        resumeMicrobreaks()
      }
    })
  } else {
    trayMenu.push({
      label: 'Pause',
      submenu: [
        {
          label: 'for an hour',
          click: function () {
            pauseMicrobreaks(3600 * 1000)
          }
        }, {
          label: 'for 2 hours',
          click: function () {
            pauseMicrobreaks(3600 * 2 * 1000)
          }
        }, {
          label: 'for 5 hours',
          click: function () {
            pauseMicrobreaks(3600 * 5 * 1000)
          }
        }, {
          label: 'indefinitely',
          click: function () {
            pauseMicrobreaks(1)
          }
        }
      ]
    })
  }

  trayMenu.push({
    label: 'Settings',
    click: function () {
      showSettingsWindow()
    }
  })

  if (process.platform === 'darwin' || process.platform === 'win32') {
    let loginItemSettings = app.getLoginItemSettings()
    let openAtLogin = loginItemSettings.openAtLogin
    trayMenu.push({
      label: 'Start at login',
      type: 'checkbox',
      checked: openAtLogin,
      click: function () {
        app.setLoginItemSettings({openAtLogin: !openAtLogin})
      }
    })
  }

  trayMenu.push({
    type: 'separator'
  }, {
    label: 'Quit',
    click: function () {
      app.quit()
    }
  })

  return Menu.buildFromTemplate(trayMenu)
}
<|endoftext|>


<commit_before>const {app, BrowserWindow, ipcMain} = require('electron');
const url = require('url');
const isDebug = process.env.NODE_ENV === 'development'

if (isDebug) {
  try
  {
    require('electron-debug')({showDevTools: true});
  }
  catch (err) // electron-debug is in devDependencies, but some
  {
    console.error(err)
  }
}

const path = require('path');
const jayson = require('jayson');
const semver = require('semver');
const https = require('https');
const keytar = require('keytar');
// tree-kill has better cross-platform handling of
// killing a process.  child-process.kill was unreliable
const kill = require('tree-kill');
const child_process = require('child_process');
const assert = require('assert');
const {version: localVersion} = require(app.getAppPath() + '/package.json');

const VERSION_CHECK_INTERVAL = 30 * 60 * 1000;
const LATEST_RELEASE_API_URL = 'https://api.github.com/repos/lbryio/lbry-app/releases/latest';

let client = jayson.client.http({
  host: 'localhost',
  port: 5279,
  path: '/lbryapi',
  timeout: 1000
});

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;
// Also keep the daemon subprocess alive
let daemonSubprocess;

// This is set to true right before we try to shut the daemon subprocess --
// if it dies when we didn't ask it to shut down, we want to alert the user.
let daemonStopRequested = false;

// When a quit is attempted, we cancel the quit, do some preparations, then
// this is set to true and app.quit() is called again to quit for real.
let readyToQuit = false;

// If we receive a URI to open from an external app but there's no window to
// send it to, it's cached in this variable.
let openUri = null;

function denormalizeUri(uri) {
  // Windows normalizes URIs when they're passed in from other apps. This tries
  // to restore the original URI that was typed.
  //   - If the URI has no path, Windows adds a trailing slash. LBRY URIs
  //     can't have a slash with no path, so we just strip it off.
  //   - In a URI with a claim ID, like lbry://channel#claimid, Windows
  //     interprets the hash mark as an anchor and converts it to
  //     lbry://channel/#claimid. We remove the slash here as well.

  if (process.platform == 'win32') {
    return uri.replace(/\/$/, '').replace('/#', '#');
  } else {
    return uri;
  }
}

function checkForNewVersion(callback) {
  function formatRc(ver) {
    // Adds dash if needed to make RC suffix semver friendly
    return ver.replace(/([^-])rc/, '$1-rc');
  }

  let result = '';
  const opts = {
    headers: {
      'User-Agent': `LBRY/${localVersion}`,
    }
  };

  const req = https.get(Object.assign(opts, url.parse(LATEST_RELEASE_API_URL)), (res) => {
    res.on('data', (data) => {
      result += data;
    });
    res.on('end', () => {
      const tagName = JSON.parse(result).tag_name;
      const [_, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
      if (!remoteVersion) {
        if (win) {
          win.webContents.send('version-info-received', null);
        }
      } else {
        const upgradeAvailable = semver.gt(formatRc(remoteVersion), formatRc(localVersion));
        if (win) {
          win.webContents.send('version-info-received', {remoteVersion, localVersion, upgradeAvailable});
        }
      }
    })
  });

  req.on('error', (err) => {
    console.log('Failed to get current version from GitHub. Error:', err);
    if (win) {
      win.webContents.send('version-info-received', null);
    }
  });
}

ipcMain.on('version-info-requested', checkForNewVersion);

/*
 * Replacement for Electron's shell.openItem. The Electron version doesn't
 * reliably work from the main process, and we need to be able to run it
 * when no windows are open.
 */
function openItem(fullPath) {
    const subprocOptions = {
      detached: true,
      stdio: 'ignore',
    };

    let child;
    if (process.platform == 'darwin') {
      child = child_process.spawn('open', [fullPath], subprocOptions);
    } else if (process.platform == 'linux') {
      child = child_process.spawn('xdg-open', [fullPath], subprocOptions);
    } else if (process.platform == 'win32') {
      child = child_process.spawn(fullPath, Object.assign({}, subprocOptions, {shell: true}));
    }

    // Causes child process reference to be garbage collected, allowing main process to exit
    child.unref();
}

function getPidsForProcessName(name) {
  if (process.platform == 'win32') {
    const tasklistOut = child_process.execSync(`tasklist /fi "Imagename eq ${name}.exe" /nh`, {encoding: 'utf8'});
    if (tasklistOut.startsWith('INFO')) {
      return [];
    } else {
      return tasklistOut.match(/[^\r\n]+/g).map((line) => line.split(/\s+/)[1]); // Second column of every non-empty line
    }
  } else {
    const pgrepOut = child_process.spawnSync('pgrep', ['-x', name], {encoding: 'utf8'}).stdout;
    return pgrepOut.match(/\d+/g);
  }
}

function createWindow () {
  win = new BrowserWindow({backgroundColor: '#155B4A', minWidth: 800, minHeight: 600 }) //$color-primary

  win.maximize()
  if (isDebug) {
    win.webContents.openDevTools();
  }
  win.loadURL(`file://${__dirname}/dist/index.html`)
  if (openUri) { // We stored and received a URI that an external app requested before we had a window object
    win.webContents.on('did-finish-load', () => {
      win.webContents.send('open-uri-requested', openUri);
    });
  }

  win.on('closed', () => {
    win = null
  })
};

function handleDaemonSubprocessExited() {
  console.log('The daemon has exited.');
  daemonSubprocess = null;
  if (!daemonStopRequested) {
    // We didn't request to stop the daemon, so display a
    // warning and schedule a quit.
    //
    // TODO: maybe it would be better to restart the daemon?
    if (win) {
      console.log('Did not request daemon stop, so quitting in 5 seconds.');
      win.loadURL(`file://${__dirname}/dist/warning.html`);
      setTimeout(quitNow, 5000);
    } else {
      console.log('Did not request daemon stop, so quitting.');
      quitNow();
    }
  }
}

function launchDaemon() {
  assert(!daemonSubprocess, 'Tried to launch daemon twice');

  if (process.env.LBRY_DAEMON) {
    executable = process.env.LBRY_DAEMON;
  } else {
    executable = path.join(__dirname, 'dist', 'lbrynet-daemon');
  }
  console.log('Launching daemon:', executable)
  daemonSubprocess = child_process.spawn(executable)
  // Need to handle the data event instead of attaching to
  // process.stdout because the latter doesn't work. I believe on
  // windows it buffers stdout and we don't get any meaningful output
  daemonSubprocess.stdout.on('data', (buf) => {console.log(String(buf).trim());});
  daemonSubprocess.stderr.on('data', (buf) => {console.log(String(buf).trim());});
  daemonSubprocess.on('exit', handleDaemonSubprocessExited);
}

/*
 * Quits without any preparation. When a quit is requested (either through the
 * interface or through app.quit()), we abort the quit, try to shut down the daemon,
 * and then call this to quit for real.
 */
function quitNow() {
  readyToQuit = true;
  app.quit();
}

if (process.platform != 'linux') {
  // On Linux, this is always returning true due to an Electron bug,
  // so for now we just don't support single-instance apps on Linux.
  const isSecondaryInstance = app.makeSingleInstance((argv) => {
    if (win) {
      if (win.isMinimized()) {
        win.restore();
      }
      win.focus();

      if (argv.length >= 2) {
        win.webContents.send('open-uri-requested', denormalizeUri(argv[1]));
      }
    } else if (argv.length >= 2) {
      openUri = denormalizeUri(argv[1]);
    }
  });

  if (isSecondaryInstance) { // We're not in the original process, so quit
    quitNow();
    return;
  }
}

app.on('ready', function(){
  launchDaemonIfNotRunning();
  createWindow();
});

function launchDaemonIfNotRunning() {
  // Check if the daemon is already running. If we get
  // an error its because its not running
  console.log('Checking for lbrynet daemon');
  client.request(
    'status', [],
    function (err, res) {
      if (err) {
        console.log('lbrynet daemon needs to be launched')
        launchDaemon();
      } else {
        console.log('lbrynet daemon is already running')
      }
    }
  );
}

/*
 * Last resort for killing unresponsive daemon instances.
 * Looks for any processes called "lbrynet-daemon" and
 * tries to force kill them.
 */
function forceKillAllDaemonsAndQuit() {
  console.log('Attempting to force kill any running lbrynet-daemon instances...');

  const daemonPids = getPidsForProcessName('lbrynet-daemon');
  if (!daemonPids) {
    console.log('No lbrynet-daemon found running.');
    quitNow();
  } else {
    console.log(`Found ${daemonPids.length} running daemon instances. Attempting to force kill...`);

    for (const pid of daemonPids) {
      let daemonKillAttemptsComplete = 0;
      kill(pid, 'SIGKILL', (err) => {
        daemonKillAttemptsComplete++;
        if (err) {
          console.log(`Failed to force kill daemon task with pid ${pid}. Error message: ${err.message}`);
        } else {
          console.log(`Force killed daemon task with pid ${pid}.`);
        }
        if (daemonKillAttemptsComplete >= daemonPids.length - 1) {
          quitNow();
        }
      });
    }
  }
}

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('before-quit', (event) => {
  if (!readyToQuit) {
    // We need to shutdown the daemon before we're ready to actually quit. This
    // event will be triggered re-entrantly once preparation is done.
    event.preventDefault();
    shutdownDaemonAndQuit();
  } else {
    console.log('Quitting.')
  }
});

app.on('activate', () => {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (win === null) {
    createWindow()
  }
});

// When a quit is attempted, this is called. It attempts to shutdown the daemon,
// then calls quitNow() to quit for real.
function shutdownDaemonAndQuit(evenIfNotStartedByApp = false) {
  function doShutdown() {
    console.log('Shutting down daemon');
    daemonStopRequested = true;
    client.request('daemon_stop', [], (err, res) => {
      if (err) {
        console.log(`received error when stopping lbrynet-daemon. Error message: ${err.message}\n`);
        console.log('You will need to manually kill the daemon.');
      } else {
        console.log('Successfully stopped daemon via RPC call.')
        quitNow();
      }
    });
  }

  if (daemonSubprocess) {
    doShutdown();
  } else if (!evenIfNotStartedByApp) {
    console.log('Not killing lbrynet-daemon because app did not start it');
    quitNow();
  } else {
    doShutdown();
  }

  // Is it safe to start the installer before the daemon finishes running?
  // If not, we should wait until the daemon is closed before we start the install.
}

function upgrade(event, installerPath) {
  app.on('quit', () => {
    console.log('Launching upgrade installer at', installerPath);
    // This gets triggered called after *all* other quit-related events, so
    // we'll only get here if we're fully prepared and quitting for real.
    openItem(installerPath);
  });

  if (win) {
    win.loadURL(`file://${__dirname}/dist/upgrade.html`);
  }

  shutdownDaemonAndQuit(true);
  // wait for daemon to shut down before upgrading
  // what to do if no shutdown in a long time?
  console.log('Update downloaded to', installerPath);
  console.log('The app will close, and you will be prompted to install the latest version of LBRY.');
  console.log('After the install is complete, please reopen the app.');
}

ipcMain.on('upgrade', upgrade);

app.setAsDefaultProtocolClient('lbry');

if (process.platform == 'darwin') {
  app.on('open-url', (event, uri) => {
    if (!win) {
      // Window not created yet, so store up requested URI for when it is
      openUri = uri;
    } else {
      win.webContents.send('open-uri-requested', uri);
    }
  });
} else if (process.argv.length >= 2) {
  if (!win) {
    openUri = denormalizeUri(process.argv[1]);
  } else {
    win.webContents.send('open-uri-requested', denormalizeUri(process.argv[1]));
  }
}

ipcMain.on('get-auth-token', (event) => {
  keytar.getPassword("LBRY", "auth_token").then(token => {
    event.sender.send('auth-token-response', token ? token.toString().trim() : null)
  });
});

ipcMain.on('set-auth-token', (event, token) => {
  keytar.setPassword("LBRY", "auth_token", token ? token.toString().trim() : null);
});<commit_msg>Reliably focus app window when opening lbry:// links<commit_after>const {app, BrowserWindow, ipcMain} = require('electron');
const url = require('url');
const isDebug = process.env.NODE_ENV === 'development'

if (isDebug) {
  try
  {
    require('electron-debug')({showDevTools: true});
  }
  catch (err) // electron-debug is in devDependencies, but some
  {
    console.error(err)
  }
}

const path = require('path');
const jayson = require('jayson');
const semver = require('semver');
const https = require('https');
const keytar = require('keytar');
// tree-kill has better cross-platform handling of
// killing a process.  child-process.kill was unreliable
const kill = require('tree-kill');
const child_process = require('child_process');
const assert = require('assert');
const {version: localVersion} = require(app.getAppPath() + '/package.json');

const VERSION_CHECK_INTERVAL = 30 * 60 * 1000;
const LATEST_RELEASE_API_URL = 'https://api.github.com/repos/lbryio/lbry-app/releases/latest';

let client = jayson.client.http({
  host: 'localhost',
  port: 5279,
  path: '/lbryapi',
  timeout: 1000
});

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;
// Also keep the daemon subprocess alive
let daemonSubprocess;

// This is set to true right before we try to shut the daemon subprocess --
// if it dies when we didn't ask it to shut down, we want to alert the user.
let daemonStopRequested = false;

// When a quit is attempted, we cancel the quit, do some preparations, then
// this is set to true and app.quit() is called again to quit for real.
let readyToQuit = false;

// If we receive a URI to open from an external app but there's no window to
// send it to, it's cached in this variable.
let openUri = null;

function processRequestedUri(uri) {
  // Windows normalizes URIs when they're passed in from other apps. On Windows,
  // this function tries to restore the original URI that was typed.
  //   - If the URI has no path, Windows adds a trailing slash. LBRY URIs
  //     can't have a slash with no path, so we just strip it off.
  //   - In a URI with a claim ID, like lbry://channel#claimid, Windows
  //     interprets the hash mark as an anchor and converts it to
  //     lbry://channel/#claimid. We remove the slash here as well.
  // On Linux and Mac, we just return the URI as given.

  if (process.platform == 'win32') {
    return uri.replace(/\/$/, '').replace('/#', '#');
  } else {
    return uri;
  }
}

function checkForNewVersion(callback) {
  function formatRc(ver) {
    // Adds dash if needed to make RC suffix semver friendly
    return ver.replace(/([^-])rc/, '$1-rc');
  }

  let result = '';
  const opts = {
    headers: {
      'User-Agent': `LBRY/${localVersion}`,
    }
  };

  const req = https.get(Object.assign(opts, url.parse(LATEST_RELEASE_API_URL)), (res) => {
    res.on('data', (data) => {
      result += data;
    });
    res.on('end', () => {
      const tagName = JSON.parse(result).tag_name;
      const [_, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
      if (!remoteVersion) {
        if (win) {
          win.webContents.send('version-info-received', null);
        }
      } else {
        const upgradeAvailable = semver.gt(formatRc(remoteVersion), formatRc(localVersion));
        if (win) {
          win.webContents.send('version-info-received', {remoteVersion, localVersion, upgradeAvailable});
        }
      }
    })
  });

  req.on('error', (err) => {
    console.log('Failed to get current version from GitHub. Error:', err);
    if (win) {
      win.webContents.send('version-info-received', null);
    }
  });
}

ipcMain.on('version-info-requested', checkForNewVersion);

/*
 * Replacement for Electron's shell.openItem. The Electron version doesn't
 * reliably work from the main process, and we need to be able to run it
 * when no windows are open.
 */
function openItem(fullPath) {
    const subprocOptions = {
      detached: true,
      stdio: 'ignore',
    };

    let child;
    if (process.platform == 'darwin') {
      child = child_process.spawn('open', [fullPath], subprocOptions);
    } else if (process.platform == 'linux') {
      child = child_process.spawn('xdg-open', [fullPath], subprocOptions);
    } else if (process.platform == 'win32') {
      child = child_process.spawn(fullPath, Object.assign({}, subprocOptions, {shell: true}));
    }

    // Causes child process reference to be garbage collected, allowing main process to exit
    child.unref();
}

function getPidsForProcessName(name) {
  if (process.platform == 'win32') {
    const tasklistOut = child_process.execSync(`tasklist /fi "Imagename eq ${name}.exe" /nh`, {encoding: 'utf8'});
    if (tasklistOut.startsWith('INFO')) {
      return [];
    } else {
      return tasklistOut.match(/[^\r\n]+/g).map((line) => line.split(/\s+/)[1]); // Second column of every non-empty line
    }
  } else {
    const pgrepOut = child_process.spawnSync('pgrep', ['-x', name], {encoding: 'utf8'}).stdout;
    return pgrepOut.match(/\d+/g);
  }
}

function createWindow () {
  win = new BrowserWindow({backgroundColor: '#155B4A', minWidth: 800, minHeight: 600 }) //$color-primary

  win.maximize()
  if (isDebug) {
    win.webContents.openDevTools();
  }
  win.loadURL(`file://${__dirname}/dist/index.html`)
  if (openUri) { // We stored and received a URI that an external app requested before we had a window object
    win.webContents.on('did-finish-load', () => {
      win.webContents.send('open-uri-requested', openUri);
    });
  }

  win.on('closed', () => {
    win = null
  })
};

function handleOpenUriRequested(uri) {
  if (!win) {
    // Window not created yet, so store up requested URI for when it is
    openUri = uri;
  } else {
    if (win.isMinimized()) {
      win.restore();
    }
    win.focus();
    win.webContents.send('open-uri-requested', processRequestedUri(uri));
  }
}

function handleDaemonSubprocessExited() {
  console.log('The daemon has exited.');
  daemonSubprocess = null;
  if (!daemonStopRequested) {
    // We didn't request to stop the daemon, so display a
    // warning and schedule a quit.
    //
    // TODO: maybe it would be better to restart the daemon?
    if (win) {
      console.log('Did not request daemon stop, so quitting in 5 seconds.');
      win.loadURL(`file://${__dirname}/dist/warning.html`);
      setTimeout(quitNow, 5000);
    } else {
      console.log('Did not request daemon stop, so quitting.');
      quitNow();
    }
  }
}

function launchDaemon() {
  assert(!daemonSubprocess, 'Tried to launch daemon twice');

  if (process.env.LBRY_DAEMON) {
    executable = process.env.LBRY_DAEMON;
  } else {
    executable = path.join(__dirname, 'dist', 'lbrynet-daemon');
  }
  console.log('Launching daemon:', executable)
  daemonSubprocess = child_process.spawn(executable)
  // Need to handle the data event instead of attaching to
  // process.stdout because the latter doesn't work. I believe on
  // windows it buffers stdout and we don't get any meaningful output
  daemonSubprocess.stdout.on('data', (buf) => {console.log(String(buf).trim());});
  daemonSubprocess.stderr.on('data', (buf) => {console.log(String(buf).trim());});
  daemonSubprocess.on('exit', handleDaemonSubprocessExited);
}

/*
 * Quits without any preparation. When a quit is requested (either through the
 * interface or through app.quit()), we abort the quit, try to shut down the daemon,
 * and then call this to quit for real.
 */
function quitNow() {
  readyToQuit = true;
  app.quit();
}

if (process.platform != 'linux') {
  // On Linux, this is always returning true due to an Electron bug,
  // so for now we just don't support single-instance apps on Linux.
  const isSecondaryInstance = app.makeSingleInstance((argv) => {
    if (argv.length >= 2) {
      handleOpenUriRequested(argv[1]); // This will handle restoring and focusing the window
    } else if (win) {
      if (win.isMinimized()) {
        win.restore();
      }
      win.focus();
    }
  });

  if (isSecondaryInstance) { // We're not in the original process, so quit
    quitNow();
    return;
  }
}

app.on('ready', function(){
  launchDaemonIfNotRunning();
  createWindow();
});

function launchDaemonIfNotRunning() {
  // Check if the daemon is already running. If we get
  // an error its because its not running
  console.log('Checking for lbrynet daemon');
  client.request(
    'status', [],
    function (err, res) {
      if (err) {
        console.log('lbrynet daemon needs to be launched')
        launchDaemon();
      } else {
        console.log('lbrynet daemon is already running')
      }
    }
  );
}

/*
 * Last resort for killing unresponsive daemon instances.
 * Looks for any processes called "lbrynet-daemon" and
 * tries to force kill them.
 */
function forceKillAllDaemonsAndQuit() {
  console.log('Attempting to force kill any running lbrynet-daemon instances...');

  const daemonPids = getPidsForProcessName('lbrynet-daemon');
  if (!daemonPids) {
    console.log('No lbrynet-daemon found running.');
    quitNow();
  } else {
    console.log(`Found ${daemonPids.length} running daemon instances. Attempting to force kill...`);

    for (const pid of daemonPids) {
      let daemonKillAttemptsComplete = 0;
      kill(pid, 'SIGKILL', (err) => {
        daemonKillAttemptsComplete++;
        if (err) {
          console.log(`Failed to force kill daemon task with pid ${pid}. Error message: ${err.message}`);
        } else {
          console.log(`Force killed daemon task with pid ${pid}.`);
        }
        if (daemonKillAttemptsComplete >= daemonPids.length - 1) {
          quitNow();
        }
      });
    }
  }
}

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('before-quit', (event) => {
  if (!readyToQuit) {
    // We need to shutdown the daemon before we're ready to actually quit. This
    // event will be triggered re-entrantly once preparation is done.
    event.preventDefault();
    shutdownDaemonAndQuit();
  } else {
    console.log('Quitting.')
  }
});

app.on('activate', () => {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (win === null) {
    createWindow()
  }
});

// When a quit is attempted, this is called. It attempts to shutdown the daemon,
// then calls quitNow() to quit for real.
function shutdownDaemonAndQuit(evenIfNotStartedByApp = false) {
  function doShutdown() {
    console.log('Shutting down daemon');
    daemonStopRequested = true;
    client.request('daemon_stop', [], (err, res) => {
      if (err) {
        console.log(`received error when stopping lbrynet-daemon. Error message: ${err.message}\n`);
        console.log('You will need to manually kill the daemon.');
      } else {
        console.log('Successfully stopped daemon via RPC call.')
        quitNow();
      }
    });
  }

  if (daemonSubprocess) {
    doShutdown();
  } else if (!evenIfNotStartedByApp) {
    console.log('Not killing lbrynet-daemon because app did not start it');
    quitNow();
  } else {
    doShutdown();
  }

  // Is it safe to start the installer before the daemon finishes running?
  // If not, we should wait until the daemon is closed before we start the install.
}

function upgrade(event, installerPath) {
  app.on('quit', () => {
    console.log('Launching upgrade installer at', installerPath);
    // This gets triggered called after *all* other quit-related events, so
    // we'll only get here if we're fully prepared and quitting for real.
    openItem(installerPath);
  });

  if (win) {
    win.loadURL(`file://${__dirname}/dist/upgrade.html`);
  }

  shutdownDaemonAndQuit(true);
  // wait for daemon to shut down before upgrading
  // what to do if no shutdown in a long time?
  console.log('Update downloaded to', installerPath);
  console.log('The app will close, and you will be prompted to install the latest version of LBRY.');
  console.log('After the install is complete, please reopen the app.');
}

ipcMain.on('upgrade', upgrade);

app.setAsDefaultProtocolClient('lbry');

if (process.platform == 'darwin') {
  app.on('open-url', (event, uri) => {
    handleOpenUriRequested(uri);
  });
} else if (process.argv.length >= 2) {
  handleOpenUriRequested(process.argv[1]);
}

ipcMain.on('get-auth-token', (event) => {
  keytar.getPassword("LBRY", "auth_token").then(token => {
    event.sender.send('auth-token-response', token ? token.toString().trim() : null)
  });
});

ipcMain.on('set-auth-token', (event, token) => {
  keytar.setPassword("LBRY", "auth_token", token ? token.toString().trim() : null);
});<|endoftext|>


<commit_before>/* global document, ga */
var size = 64;
var host = '/emojis';
var _ = require('underscore');
_.templateSettings = {interpolate: /\{\{(.+?)\}\}/g};
var Emoji = require('random-emoji');
var domready = require('domready');
var share = require('../lib/share');
var addEvent = require('../lib/event');
var attachFastClick = require('fastclick');
var shareTextTmpl =  _.template('My emoji fortune is {{ characters }} ({{ text }}) —');
var $ = function (id) { return document.querySelector('#' + id); };
var ondeck = null;

function preload(images) {
    _.each(images, function(src) {
        (new Image()).src = src;
    });
}

function getEmoji() {
    var emoji = Emoji.random({
        count: 3,
        host: host,
        height: size
    });
    preload(_.pluck(emoji, 'imageSrc'));
    var names = _.pluck(emoji, 'name');
    var text = names.join(' ').replace(/_/g, ' ');
    var characters = _.pluck(emoji, 'character').join(' ');
    var shareText = shareTextTmpl({text: text, characters: characters});
    var images = _.map(emoji, function (e) {
        var url = 'http://emojipedia.org/' + e.name.replace(/_/g, '-').toLowerCase() + '/';
        return '' + e.image + '';
    }).join('');
    return {
        images: '' + images + '',
        share: share(shareText),
        text: text
    };
}

function setDom(opts) {
    $('fortune').innerHTML = opts.images;
    $('copy').setAttribute('data-text', opts.share.copy);
    $('fortuneText').innerHTML = opts.text;
    $('tweetButton').setAttribute('href', opts.share.twitter);
}

function copyit() {
    window.prompt('Copy to clipboard: Ctrl+C, Enter', this.getAttribute('data-text'));
}

function doit() {
    setDom(ondeck ? ondeck : getEmoji());
    ondeck = getEmoji();
}

function trackit () {
    doit();
    ga('send', 'pageview');
}

domready(function () {
    attachFastClick(document.body);
    doit();
    addEvent($('refresh'), 'click', trackit);
    addEvent($('copy'), 'click', copyit);
});
<commit_msg>link with character<commit_after>/* global document, ga */
var size = 64;
var host = '/emojis';
var _ = require('underscore');
_.templateSettings = {interpolate: /\{\{(.+?)\}\}/g};
var Emoji = require('random-emoji');
var domready = require('domready');
var share = require('../lib/share');
var addEvent = require('../lib/event');
var attachFastClick = require('fastclick');
var shareTextTmpl =  _.template('My emoji fortune is {{ characters }} ({{ text }}) —');
var $ = function (id) { return document.querySelector('#' + id); };
var ondeck = null;

function preload(images) {
    _.each(images, function(src) {
        (new Image()).src = src;
    });
}

function getEmoji() {
    var emoji = Emoji.random({
        count: 3,
        host: host,
        height: size
    });
    preload(_.pluck(emoji, 'imageSrc'));
    var names = _.pluck(emoji, 'name');
    var text = names.join(' ').replace(/_/g, ' ');
    var characters = _.pluck(emoji, 'character').join(' ');
    var shareText = shareTextTmpl({text: text, characters: characters});
    var images = _.map(emoji, function (e) {
        var url = 'http://emojipedia.org/' + e.character;
        return '' + e.image + '';
    }).join('');
    return {
        images: '' + images + '',
        share: share(shareText),
        text: text
    };
}

function setDom(opts) {
    $('fortune').innerHTML = opts.images;
    $('copy').setAttribute('data-text', opts.share.copy);
    $('fortuneText').innerHTML = opts.text;
    $('tweetButton').setAttribute('href', opts.share.twitter);
}

function copyit() {
    window.prompt('Copy to clipboard: Ctrl+C, Enter', this.getAttribute('data-text'));
}

function doit() {
    setDom(ondeck ? ondeck : getEmoji());
    ondeck = getEmoji();
}

function trackit () {
    doit();
    ga('send', 'pageview');
}

domready(function () {
    attachFastClick(document.body);
    doit();
    addEvent($('refresh'), 'click', trackit);
    addEvent($('copy'), 'click', copyit);
});
<|endoftext|>


<commit_before>angular.module('Todo', [])
  .controller('MainCtrl', function ($scope) {
    $scope.tasks = [
      {
        "id": 0,
        "title": "First task",
        "description": "Description of the first task.",
        "done": false
      },
      {
        "id": 1,
        "title": "Second task",
        "description": "Description of the second task.",
        "done": false
      }
    ]
  });
<commit_msg>reindent JS code plus add 'addTask' method<commit_after>angular.module('Todo', [])
  .controller('MainCtrl', function($scope) {
    $scope.tasks = [
      {
        id: 0,
        title: "First task",
        description: "Description of the first task.",
        done: false
      },
      {
        id: 1,
        title: "Second task",
        description: "Description of the second task.",
        done: false
      }
    ];

    // Add a task.
    $scope.addTask = function addTask() {
      $scope.tasks.push({
        title: $scope.task.title,
        description: $scope.task.desc,
        done: false
      });
    };
  });
<|endoftext|>


<commit_before>'use strict';

var validations = require('./lib/validations'),
    manifestTools = require('./lib/tools'),
    projectBuilder = require('./lib/projectBuilder'),
    log = require('loglevel');

function checkParameters(argv) {
    if (argv._.length < 2) {
        throw 'ERROR: Missing required arguments.';
    }

    // Check platforms
    if (argv.p) {
        var platforms = argv.p.split(/[\s,]+/);
        if (!validations.platformsValid(platforms)) {
            throw 'ERROR: Invalid platform(s) specified.';
        }
    }
}

var parameters = require('optimist')
                .usage('Usage: node appmyweb.js <website URL> <app directory> [-p <platforms>]')
                .alias('p', 'platforms')
                .default('p', 'windows,android,ios')
                .check(checkParameters)
                .argv;

var siteUrl = parameters._[0];
var rootDir = parameters._[1];
var platforms = parameters.p.split(/[\s,]+/);

log.setLevel('info');

// scan a site to retrieve its manifest
log.info('Scanning ' + siteUrl + ' for manifest...');

manifestTools.getManifestFromSite(siteUrl, function (err, manifestInfo) {
    if (err) {
        log.error("ERROR: " + err.message);
        return err;
    }

    // query manifest info and retrieve its app name
    log.info('Found a ' + manifestInfo.format.toUpperCase() + ' manifest...');

    // TODO: implement log level logic to decide when to show these messages
    //console.log();
    //console.log(JSON.stringify(manifestInfo.content, null, 4));

    // create the cordova application
    projectBuilder.createCordovaApp(manifestInfo, rootDir, platforms, function (err) {
        if (err) {
            log.error("ERROR: " + err.message);
            return err;
        }

        log.info('The Cordova application is ready!');
    });
});<commit_msg>Updated to write manifest to log if trace level is 'debug'<commit_after>'use strict';

var validations = require('./lib/validations'),
    manifestTools = require('./lib/tools'),
    projectBuilder = require('./lib/projectBuilder'),
    log = require('loglevel');

function checkParameters(argv) {
    if (argv._.length < 2) {
        throw 'ERROR: Missing required arguments.';
    }

    // Check platforms
    if (argv.p) {
        var platforms = argv.p.split(/[\s,]+/);
        if (!validations.platformsValid(platforms)) {
            throw 'ERROR: Invalid platform(s) specified.';
        }
    }
}

var parameters = require('optimist')
                .usage('Usage: node appmyweb.js <website URL> <app directory> [-p <platforms>]')
                .alias('p', 'platforms')
                .default('p', 'windows,android,ios')
                .check(checkParameters)
                .argv;

var siteUrl = parameters._[0];
var rootDir = parameters._[1];
var platforms = parameters.p.split(/[\s,]+/);

log.setLevel('info');

// scan a site to retrieve its manifest
log.info('Scanning ' + siteUrl + ' for manifest...');

manifestTools.getManifestFromSite(siteUrl, function (err, manifestInfo) {
    if (err) {
        log.error("ERROR: " + err.message);
        return err;
    }

    // query manifest info and retrieve its app name
    log.info('Found a ' + manifestInfo.format.toUpperCase() + ' manifest...');
    log.debug('Manifest contents:');
    log.debug(JSON.stringify(manifestInfo.content, null, 4));

    // create the cordova application
    projectBuilder.createCordovaApp(manifestInfo, rootDir, platforms, function (err) {
        if (err) {
            log.error("ERROR: " + err.message);
            return err;
        }

        log.info('The Cordova application is ready!');
    });
});<|endoftext|>