<commit_before>/*
    TO-DO:
     [x] use an array or object to store settings variables
     [x] save settings when app quits
     [x] add custom proxy support
     [x] create function to process settingsData
     [x] add in-app settings
     [x] make settings beautiful
     [x] add 'already saved' to settings
     [x] add about page
     [] praise energy drinks
*/
const {remote,BrowserWindow,app,electron,shell,Menu,MenuItem,clipboard,dialog,ipcMain} = require('electron')
const fs = require('fs')

let Settings = [//Could do smth. like Settings = [[undefined,'use-tor ='],...] see: https://stackoverflow.com/a/966234
  [undefined,'use-tor ='], //useTor
  [false,'use-round-pics ='],//roundPics
  [false,'truly-dark ='],//trulyDark
  [1336,'width ='],//windowWidth
  [720,'height ='],//windowHeight
  [false,'use-custom-proxy ='],//useProxy
  ['foopy:80','customProxy =']//customProxy
]

const settingsFile = "./settings.json"
const tor = "./resources/app.asar.unpacked/tor-win32-0.3.0.9/Tor/tor.exe"
let mainWindow,settingsWin,twitterwin,aboutWin

function createWindow (Settings) {
  mainWindow = new BrowserWindow({autoHideMenuBar: true,width: Settings[3][0], height: Settings[4][0]})
  console.log(Settings)
  const url2 = 'file://' + app.getAppPath() +'/fail.html'
  const home = 'https://tweetdeck.twitter.com/'
  var retries = 0
  if(Settings[0][0] && !Settings[5][0])
  {
    mainWindow.webContents.session.setProxy({proxyRules:"socks5://127.0.0.1:9050"}, () => {
      mainWindow.loadURL(home)
      console.log("using Tor")
    })
  }
  else if(Settings[5][0])
  {
    mainWindow.webContents.session.setProxy({proxyRules: Settings[6][0]}, () => {
      mainWindow.loadURL(home)
      console.log("using custom Proxy")
    })
  }
  else {
    mainWindow.loadURL(home)
    console.log("Not using Tor or custom Proxy")
  }
  mainWindow.webContents.on('did-fail-load', () => {
    mainWindow.loadURL(home)
    if(retries==3) mainWindow.loadURL(url2)
    retries++
  })
  mainWindow.webContents.on('did-finish-load', () => {
    if(!Settings[1][0])
    {
      mainWindow.webContents.insertCSS(".avatar{border-radius:0 !important}")// makes profile pics angular shaped again Woohoo!
    }
    if(Settings[2][0])
    {
      mainWindow.webContents.insertCSS("\
      .is-inverted-dark .scroll-conversation{background: #222426 !important}\
      .mdl.s-full{background-color: #111 !important}\
      .mdl-placeholder{text-shadow: 0 1px 0 rgba(0, 0, 0, 0.8) !important}\
      .list-account .username{color: #eaeaea !important}\
      .list-account .fullname{color: #eaeaea !important}\
      .list-account:hover{background-color: #666 !important}\
      .list-account{text-shadow: 0 1px 0 #000 !important}\
      .is-inverted-dark .column-scroller::-webkit-scrollbar-thumb{background-color: #666 !important}\
      .column-background-fill{background-color: #222426 !important}\
      .scroll-alt::-webkit-scrollbar-thumb{background-color: #666 !important}\
      .is-inverted-dark .stream-item{background-color: #222426 !important}\
      .is-inverted-dark .account-link{color: #e1e8ed !important}\
      .follow-btn{background-color: #292f33 !important;color: #fff !important;border-color: #111 !important}\
      .s-following .follow-btn{background-color: #50a5e6 !important}\
      .s-following .follow-btn:hover{color:#fff !important;background-color:#a0041e !important}\
      .is-inverted-dark .btn-square:focus{color: #eaeaea !important;background-color: #292f33 !important}\
      .is-inverted-dark .btn-square{color: #e1e8ed !important;background-color: #292f33 !important;border-color: #111 !important} \
      .lst-profile{background-color: #2a2c2d !important}\
      .text-like-keyboard-key{color: #000 !important}\
      .social-proof-container{background-color: #2a2e31 !important}\
      .is-inverted-dark{color: #fff !important}\
      .prf-stats a strong{color: #8899a6 !important}\
      .caret-inner{border-bottom: 6px solid #222426 !important}\
      .bg-r-white,.prf-meta{background-color: #222426 !important}\
      .txt-seamful-black{color: #fff !important}\
      .dropdown-menu,.dropdown-menu [data-action]{background-color: #222426 !important;color: #fff !important}\
      .list-link:hover{background-color: #0e0e0e !important}\
      .mdl,.mdl-inner,.mdl-column,.mdl-col-settings,.bg-seamful-faint-gray,.bg-seamful-faded-gray{background-color: #222426 !important}\
      .frm,.a-list-link,.list-link,.mdl-header,.mdl-dismiss,.non-selectable-item{color: #fff !important}")
    }
  })
  mainWindow.webContents.on('new-window', (event,url) => {
    if(url.search('https://tweetdeck.twitter.com/') !== 0 || url.search('https://twitter.com/') !== 0)
    {
      event.preventDefault()
      shell.openExternal(url)
    }
  })
  mainWindow.webContents.on('will-navigate', (event, url) => {

    if(url.search('https://twitter.com/login') == 0)
    {
      event.preventDefault()
      twitterwin = new BrowserWindow({parent: mainWindow})
      twitterwin.setMenu(null)
      if(Settings[0][0] && !Settings[5][0])
      {
        twitterwin.webContents.session.setProxy({proxyRules:"socks5://127.0.0.1:9050"}, () => {
          twitterwin.loadURL(url)
          console.log("using Tor")
        })
      }
      else if(Settings[5][0])
      {
        twitterwin.webContents.session.setProxy({proxyRules: Settings[6][0]}, () => {
          twitterwin.loadURL(url)
          console.log("using custom Proxy")
        })
      }
      else {
        twitterwin.loadURL(url)
        console.log("Not using Tor or custom Proxy")
      }
      twitterwin.webContents.on('did-fail-load',() => {
        twitterwin.loadURL(url2)
      })
      event.newGuest = twitterwin
      twitterwin.webContents.on('will-navigate', (event,url) => {
        mainWindow.loadURL(url)
        twitterwin.close()
      })
    }
  })
  mainWindow.on('close', (event) => {
    const size = mainWindow.getSize()
    Settings[3][0] = size[0]
    Settings[4][0] = size[1]
    var saveSettings = ""
    for(var i=0;i<Settings.length;i++)
    {
      saveSettings += (Settings[i][1] + Settings[i][0] + '\n')
    }
    fs.writeFileSync(settingsFile,saveSettings, (err) =>{
      if(err) return console.log(err)
    })
  })
  mainWindow.on('closed', function () {
    app.quit()
  })
  ipcMain.on('Settings',(event,newSettings) => {
    console.log(newSettings)
    if(newSettings.toString() == Settings.toString())
    {
      event.returnValue = false
    }
    else {
      Settings = newSettings
      event.returnValue = true
    }
    console.log(Settings)
  })
}
function startTor() {
  var child = require('child_process').execFile(tor)
}

app.on('ready', () => {

  if(!fs.existsSync(settingsFile))
  {
    dialog.showMessageBox({type:'question', buttons:['No','Yes'],message:'This app is capable of using Tor.\n Do you want to use Tor?'}, (response)=>{
      if(response){
        Settings[0][0] = true
        var saveSettings = ""
        for(var i=0;i<Settings.length;i++)
        {
          saveSettings += (Settings[i][1] + Settings[i][0] + '\n')
        }
        fs.writeFileSync(settingsFile,saveSettings, (err) =>{
          if(err) return console.log(err)
          else return console.log("wrote file")
        })
        console.log("clicked YES")
        startTor()
        createWindow(Settings)
        }
      else {
        Settings[0][0] = false
        var saveSettings = ""
        for(var i=0;i<Settings.length;i++)
        {
          saveSettings += (Settings[i][1] + Settings[i][0] + '\n')
        }
        fs.writeFileSync(settingsFile,saveSettings, (err) =>{
          if(err) return console.log(err)
          else return console.log("wrote file")
        })
        console.log("clicked NO")
        createWindow(Settings)
      }
    })
  }
  else if(fs.existsSync(settingsFile)) {
    const settingsData= fs.readFileSync(settingsFile,'utf8')
    console.log("Data:\n" + settingsData + "\nend of data")

    for(var i=0;i<Settings.length;i++)
    {
      Settings[i][0] = settingsData.slice(settingsData.search(Settings[i][1])+Settings[i][1].length,settingsData.indexOf('\n',settingsData.search(Settings[i][1]))).trim()
      if(Settings[i][0] == 'true'||Settings[i][0] == 'false')
      {
        Settings[i][0] = (Settings[i][0] == 'true')
      }
      else if(!isNaN(Number(Settings[i][0]))){
        Settings[i][0] = Number(Settings[i][0])
      }
    }
    console.log(Settings)
      if(Settings[0][0] && !Settings[1][0])
      {
        startTor()
      }
      createWindow(Settings)
  }
  else { //unreachable code, but... you know
    console.log("Something went terribly wrong")
  }
  createMenu()
})
app.on('browser-window-created', function (event, win) {

  win.webContents.on('context-menu', function (e, params) {
    const cmenu = new Menu()
    if(params.linkURL && params.mediaType === 'none')
    {
      cmenu.append(new MenuItem({
        label: 'Copy URL',
        click () {
          clipboard.writeText(params.linkURL)
        }
      }))
      if(params.linkText.charAt(0) === '#')
      {
        cmenu.append(new MenuItem({
          label: 'Copy Hashtag',
          click () {
            clipboard.writeText(params.linkText)
          }
        }))
      }
      if(params.linkText.charAt(0) === '@')
      {
        cmenu.append(new MenuItem({
          label: 'Copy Username',
          click () {
            clipboard.writeText(params.linkText)
          }
        }))
      }
    }
    else if(params.mediaType === 'image')
    {
      cmenu.append(new MenuItem({
        label: 'Copy Image',
        click () {
          win.webContents.copyImageAt(params.x,params.y)
        }
      }))
    }
    else if(params.mediaType === 'none'){
      cmenu.append(new MenuItem({role: 'copy'}))
      cmenu.append(new MenuItem({label:'Paste', role: 'pasteandmatchstyle'}))
      cmenu.append(new MenuItem({role: 'cut'}))
      cmenu.append(new MenuItem({role: 'selectall'}))
    }
    else {
      cmenu.append(new MenuItem({label:'...'}))
    }
    cmenu.popup(win, params.x, params.y)
  })
})

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
    app.quit()
})
function createMenu() {
  if (Menu.getApplicationMenu()) return

  const template = [
    {
      label: 'App',
      submenu: [
        {
          role: 'quit'
        },
        {
          label: 'Settings',
          click () {
            if(settingsWin != undefined) settingsWin.focus()
            else {
              settingsWin = new BrowserWindow({width: 450,height: 310,parent: mainWindow})
              settingsWin.setMenu(null)
              settingsWin.loadURL('file://' + app.getAppPath() + '/settings.html')
            }
            settingsWin.on('closed', () => {
              settingsWin = undefined
            })
          }
        }
      ]
    },
    {
      label: 'Edit',
      submenu: [
        {
          role: 'cut'
        },
        {
          role: 'copy'
        },
        {
          label:'Paste',
          accelerator: 'CmdOrCtrl+V',
          role: 'pasteandmatchstyle'
        },
        {
          role: 'selectall'
        }
      ]
    },
    {
      label: 'View',
      submenu: [
        {
          label: 'TweetDeck',
          click (item, focusedWindow) {
            if (focusedWindow) focusedWindow.loadURL("https://tweetdeck.twitter.com/")}
        },
        {
          label: 'Twitter',
          click (item, focusedWindow) {
            if(focusedWindow) focusedWindow.loadURL("https://twitter.com/")}
        },
        {
          label: 'Reload',
          accelerator: 'F5',
          click (item, focusedWindow) {
            if (focusedWindow) focusedWindow.reload()
          }
        },
        {
          label: 'DevTools',
          accelerator: 'F12',
          click (item, focusedWindow){
            if(focusedWindow) focusedWindow.webContents.toggleDevTools()
          }
        },
        {
          role: 'togglefullscreen'
        }
      ]
    },
    {
      label: 'About',
      click(){
        if(aboutWin != undefined) aboutWin.focus()
        else {
          aboutWin = new BrowserWindow({width: 500,height: 300,parent: mainWindow})
          aboutWin.setMenu(null)
          aboutWin.loadURL('file://' + app.getAppPath() + '/about.html')
        }
        aboutWin.on('closed', ()=> {
          aboutWin = undefined
        })
        aboutWin.webContents.on('will-navigate', (event,url) => {
          event.preventDefault()
          shell.openExternal(url)
        })
      }
    }
  ]

  const menu = Menu.buildFromTemplate(template)
  Menu.setApplicationMenu(menu)
}
<commit_msg>Window reloads when theme is changed<commit_after>/*
    TO-DO:
     [x] use an array or object to store settings variables
     [x] save settings when app quits
     [x] add custom proxy support
     [x] create function to process settingsData
     [x] add in-app settings
     [x] make settings beautiful
     [x] add 'already saved' to settings
     [x] add about page
     [] praise energy drinks
*/
const {remote,BrowserWindow,app,electron,shell,Menu,MenuItem,clipboard,dialog,ipcMain} = require('electron')
const fs = require('fs')

let Settings = [
  [undefined,'use-tor ='],
  [false,'use-round-pics ='],
  [false,'truly-dark ='],
  [1336,'width ='],
  [720,'height ='],
  [false,'use-custom-proxy ='],
  ['foopy:80','customProxy =']
]

const settingsFile = "./settings.json"
const tor = "./resources/app.asar.unpacked/tor-win32-0.3.0.9/Tor/tor.exe"
let mainWindow,settingsWin,twitterwin,aboutWin

function createWindow (Settings) {
  mainWindow = new BrowserWindow({autoHideMenuBar: true,width: Settings[3][0], height: Settings[4][0]})
  console.log(Settings)
  const url2 = 'file://' + app.getAppPath() +'/fail.html'
  const home = 'https://tweetdeck.twitter.com/'
  var retries = 0
  if(Settings[0][0] && !Settings[5][0])
  {
    mainWindow.webContents.session.setProxy({proxyRules:"socks5://127.0.0.1:9050"}, () => {
      mainWindow.loadURL(home)
      console.log("using Tor")
    })
  }
  else if(Settings[5][0])
  {
    mainWindow.webContents.session.setProxy({proxyRules: Settings[6][0]}, () => {
      mainWindow.loadURL(home)
      console.log("using custom Proxy")
    })
  }
  else {
    mainWindow.loadURL(home)
    console.log("Not using Tor or custom Proxy")
  }
  mainWindow.webContents.on('did-fail-load', () => {
    mainWindow.loadURL(home)
    if(retries==3) mainWindow.loadURL(url2)
    retries++
  })
  mainWindow.webContents.on('did-finish-load', () => {
    if(!Settings[1][0])
    {
      mainWindow.webContents.insertCSS(".avatar{border-radius:0 !important}")// makes profile pics angular shaped again Woohoo!
    }
    if(Settings[2][0])
    {
      mainWindow.webContents.insertCSS("\
      .cmp-replyto{background-color: #222426 !important}\
      .is-inverted-dark .scroll-conversation{background: #222426 !important}\
      .mdl.s-full{background-color: #111 !important}\
      .mdl-placeholder{text-shadow: 0 1px 0 rgba(0, 0, 0, 0.8) !important}\
      .list-account .username{color: #eaeaea !important}\
      .list-account .fullname{color: #eaeaea !important}\
      .list-account:hover{background-color: #666 !important}\
      .list-account{text-shadow: 0 1px 0 #000 !important}\
      .is-inverted-dark .column-scroller::-webkit-scrollbar-thumb{background-color: #666 !important}\
      .column-background-fill{background-color: #222426 !important}\
      .scroll-alt::-webkit-scrollbar-thumb{background-color: #666 !important}\
      .is-inverted-dark .stream-item{background-color: #222426 !important}\
      .is-inverted-dark .account-link{color: #e1e8ed !important}\
      .follow-btn{background-color: #292f33 !important;color: #fff !important;border-color: #111 !important}\
      .s-following .follow-btn{background-color: #50a5e6 !important}\
      .s-following .follow-btn:hover{color:#fff !important;background-color:#a0041e !important}\
      .is-inverted-dark .btn-square:focus{color: #eaeaea !important;background-color: #292f33 !important}\
      .is-inverted-dark .btn-square{color: #e1e8ed !important;background-color: #292f33 !important;border-color: #111 !important} \
      .lst-profile{background-color: #2a2c2d !important}\
      .text-like-keyboard-key{color: #000 !important}\
      .social-proof-container{background-color: #2a2e31 !important}\
      .is-inverted-dark{color: #fff !important}\
      .prf-stats a strong{color: #8899a6 !important}\
      .caret-inner{border-bottom: 6px solid #222426 !important}\
      .bg-r-white,.prf-meta{background-color: #222426 !important}\
      .txt-seamful-black{color: #fff !important}\
      .dropdown-menu,.dropdown-menu [data-action]{background-color: #222426 !important;color: #fff !important}\
      .list-link:hover{background-color: #0e0e0e !important}\
      .mdl,.mdl-inner,.mdl-column,.mdl-col-settings,.bg-seamful-faint-gray,.bg-seamful-faded-gray{background-color: #222426 !important}\
      .frm,.a-list-link,.list-link,.mdl-header,.mdl-dismiss,.non-selectable-item{color: #fff !important}")
    }
  })
  mainWindow.webContents.on('new-window', (event,url) => {
    if(url.search('https://tweetdeck.twitter.com/') !== 0 || url.search('https://twitter.com/') !== 0)
    {
      event.preventDefault()
      shell.openExternal(url)
    }
  })
  mainWindow.webContents.on('will-navigate', (event, url) => {

    if(url.search('https://twitter.com/login') == 0)
    {
      event.preventDefault()
      twitterwin = new BrowserWindow({parent: mainWindow})
      twitterwin.setMenu(null)
      if(Settings[0][0] && !Settings[5][0])
      {
        twitterwin.webContents.session.setProxy({proxyRules:"socks5://127.0.0.1:9050"}, () => {
          twitterwin.loadURL(url)
          console.log("using Tor")
        })
      }
      else if(Settings[5][0])
      {
        twitterwin.webContents.session.setProxy({proxyRules: Settings[6][0]}, () => {
          twitterwin.loadURL(url)
          console.log("using custom Proxy")
        })
      }
      else {
        twitterwin.loadURL(url)
        console.log("Not using Tor or custom Proxy")
      }
      twitterwin.webContents.on('did-fail-load',() => {
        twitterwin.loadURL(url2)
      })
      event.newGuest = twitterwin
      twitterwin.webContents.on('will-navigate', (event,url) => {
        mainWindow.loadURL(url)
        twitterwin.close()
      })
    }
  })
  mainWindow.on('close', (event) => {
    const size = mainWindow.getSize()
    Settings[3][0] = size[0]
    Settings[4][0] = size[1]
    var saveSettings = ""
    for(var i=0;i<Settings.length;i++)
    {
      saveSettings += (Settings[i][1] + Settings[i][0] + '\n')
    }
    fs.writeFileSync(settingsFile,saveSettings, (err) =>{
      if(err) return console.log(err)
    })
  })
  mainWindow.on('closed', function () {
    app.quit()
  })
  ipcMain.on('Settings',(event,newSettings) => {
    console.log(newSettings)
    if(newSettings.toString() == Settings.toString())
    {
      event.returnValue = false
    }
    else {
      var reload = false
      if(Settings[2][0]!==newSettings[2][0])
      {
        reload = true
      }
      Settings = newSettings
      if(reload){
        mainWindow.reload()
      }
      event.returnValue = true
    }
    console.log(Settings)
  })
}
function startTor() {
  var child = require('child_process').execFile(tor)
}

app.on('ready', () => {

  if(!fs.existsSync(settingsFile))
  {
    dialog.showMessageBox({type:'question', buttons:['No','Yes'],message:'Do you want to use Tor?'}, (response)=>{
      if(response){
        Settings[0][0] = true
        var saveSettings = ""
        for(var i=0;i<Settings.length;i++)
        {
          saveSettings += (Settings[i][1] + Settings[i][0] + '\n')
        }
        fs.writeFileSync(settingsFile,saveSettings, (err) =>{
          if(err) return console.log(err)
          else return console.log("wrote file")
        })
        console.log("clicked YES")
        startTor()
        createWindow(Settings)
        }
      else {
        Settings[0][0] = false
        var saveSettings = ""
        for(var i=0;i<Settings.length;i++)
        {
          saveSettings += (Settings[i][1] + Settings[i][0] + '\n')
        }
        fs.writeFileSync(settingsFile,saveSettings, (err) =>{
          if(err) return console.log(err)
          else return console.log("wrote file")
        })
        console.log("clicked NO")
        createWindow(Settings)
      }
    })
  }
  else if(fs.existsSync(settingsFile)) {
    const settingsData= fs.readFileSync(settingsFile,'utf8')
    console.log("Data:\n" + settingsData + "\nend of data")

    for(var i=0;i<Settings.length;i++)
    {
      Settings[i][0] = settingsData.slice(settingsData.search(Settings[i][1])+Settings[i][1].length,settingsData.indexOf('\n',settingsData.search(Settings[i][1]))).trim()
      if(Settings[i][0] == 'true'||Settings[i][0] == 'false')
      {
        Settings[i][0] = (Settings[i][0] == 'true')
      }
      else if(!isNaN(Number(Settings[i][0]))){
        Settings[i][0] = Number(Settings[i][0])
      }
    }
    console.log(Settings)
      if(Settings[0][0] && !Settings[1][0])
      {
        startTor()
      }
      createWindow(Settings)
  }
  else { //unreachable code, but... you know
    console.log("Something went terribly wrong")
  }
  createMenu()
})
app.on('browser-window-created', function (event, win) {

  win.webContents.on('context-menu', function (e, params) {
    const cmenu = new Menu()
    if(params.linkURL && params.mediaType === 'none')
    {
      cmenu.append(new MenuItem({
        label: 'Copy URL',
        click () {
          clipboard.writeText(params.linkURL)
        }
      }))
      if(params.linkText.charAt(0) === '#')
      {
        cmenu.append(new MenuItem({
          label: 'Copy Hashtag',
          click () {
            clipboard.writeText(params.linkText)
          }
        }))
      }
      if(params.linkText.charAt(0) === '@')
      {
        cmenu.append(new MenuItem({
          label: 'Copy Username',
          click () {
            clipboard.writeText(params.linkText)
          }
        }))
      }
    }
    else if(params.mediaType === 'image')
    {
      cmenu.append(new MenuItem({
        label: 'Copy Image',
        click () {
          win.webContents.copyImageAt(params.x,params.y)
        }
      }))
    }
    else if(params.mediaType === 'none'){
      cmenu.append(new MenuItem({role: 'copy'}))
      cmenu.append(new MenuItem({label:'Paste', role: 'pasteandmatchstyle'}))
      cmenu.append(new MenuItem({role: 'cut'}))
      cmenu.append(new MenuItem({role: 'selectall'}))
    }
    else {
      cmenu.append(new MenuItem({label:'...'}))
    }
    cmenu.popup(win, params.x, params.y)
  })
})

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
    app.quit()
})
function createMenu() {
  if (Menu.getApplicationMenu()) return

  const template = [
    {
      label: 'App',
      submenu: [
        {
          role: 'quit'
        },
        {
          label: 'Settings',
          click () {
            if(settingsWin != undefined) settingsWin.focus()
            else {
              settingsWin = new BrowserWindow({width: 450,height: 310,parent: mainWindow})
              settingsWin.setMenu(null)
              settingsWin.loadURL('file://' + app.getAppPath() + '/settings.html')
            }
            settingsWin.on('closed', () => {
              settingsWin = undefined
            })
          }
        }
      ]
    },
    {
      label: 'Edit',
      submenu: [
        {
          role: 'cut'
        },
        {
          role: 'copy'
        },
        {
          label:'Paste',
          accelerator: 'CmdOrCtrl+V',
          role: 'pasteandmatchstyle'
        },
        {
          role: 'selectall'
        }
      ]
    },
    {
      label: 'View',
      submenu: [
        {
          label: 'TweetDeck',
          click (item, focusedWindow) {
            if (focusedWindow) focusedWindow.loadURL("https://tweetdeck.twitter.com/")}
        },
        {
          label: 'Twitter',
          click (item, focusedWindow) {
            if(focusedWindow) focusedWindow.loadURL("https://twitter.com/")}
        },
        {
          label: 'Reload',
          accelerator: 'F5',
          click (item, focusedWindow) {
            if (focusedWindow) focusedWindow.reload()
          }
        },
        {
          label: 'DevTools',
          accelerator: 'F12',
          click (item, focusedWindow){
            if(focusedWindow) focusedWindow.webContents.toggleDevTools()
          }
        },
        {
          role: 'togglefullscreen'
        }
      ]
    },
    {
      label: 'About',
      click(){
        if(aboutWin != undefined) aboutWin.focus()
        else {
          aboutWin = new BrowserWindow({width: 500,height: 300,parent: mainWindow})
          aboutWin.setMenu(null)
          aboutWin.loadURL('file://' + app.getAppPath() + '/about.html')
        }
        aboutWin.on('closed', ()=> {
          aboutWin = undefined
        })
        aboutWin.webContents.on('will-navigate', (event,url) => {
          event.preventDefault()
          shell.openExternal(url)
        })
      }
    }
  ]

  const menu = Menu.buildFromTemplate(template)
  Menu.setApplicationMenu(menu)
}
<|endoftext|>


<commit_before>import syllable from 'syllable';
import _ from 'lodash';
import wordnet from 'wordnet';
var $ = require('jquery-deferred');
import stopwords from './data/stopwords.js';
import descriptors from './data/descriptors.js';
import cusseth from './data/cusseth.js';
import nouns from './data/nouns.js';
import thesaurus from './data/thesaurus.js';

let adjectives = descriptors.map(word => [word, syllable(word)]);
let curses = cusseth.map(word => [word, syllable(word)]);

const HAIKU_LENGTH = 17;
const separator = '//';
const FOUL = false;

// Chrys' Domain
function addModifier(phrase, length, mod) {
  let tokens = phrase.split(/\W/);
  let nounList = tokens.map(word => _.contains(nouns, word));
  console.log(nounList, tokens);
  for (var i in nounList) {
    if (nounList[i]) {
      tokens.splice(i, 0, mod);
      return tokens.join(' ');
    }
  }

  return mod + ' ' + phrase;
}

export function addExpletive(phrase, length) {
  var curse = _.sample(curses.filter(tuple => tuple[1] === length));
  if (!curse) {
    return addExpletive(addExpletive(phrase, length - 1), 1);
  }

  return addModifier(phrase, length, curse[0]);
}

export function addAdjective(phrase, length) {
  var adj = _.sample(adjectives.filter(tuple => tuple[1] === length));
  if (!adj) {
    return addAdjective(addAdjective(phrase, length - 1), 1);
  }

  return addModifier(phrase, length, adj[0]);
}

export function removeWords(phrase, length) {
  length *= -1;
  let tokens = phrase.split(/\W/);
  let newTokens = [];
  tokens.forEach(function(token) {
    if (length && _.contains(stopwords, token)) {
      length -= syllable(token);
    } else {
      newTokens.push(token);
    }
  });

  return newTokens.join(' ');
}

function addWords(phrase, length) {
  if (FOUL) {
    return addExpletive(phrase, length);
  } else {
    return addAdjective(phrase, length);
  }
}

// Nicole WUZ HERE
export function shortenWord(word, adjustment) {
  let possibleNewWord = [];
  let theNewWord;
  let newWordSyllables;
  let adjustedList;
  let otheradjustednotasgoodList;
  let currentWordSyllables = syllable(word);

  adjustment = -adjustment;

  let list = []

  var response = possibleSynonymArray(word);

  if (!_.isEmpty(response)) {
    for (let x=0; x<response.length; x++) {
      list[x] = [response[x], syllable(response[x])]
    }

    adjustedList = list.filter(synonym => synonym[1] - currentWordSyllables === adjustment);

    if (!_.isEmpty(adjustedList)) {
      return adjustedList[0][0];
    }

    else {
      otheradjustednotasgoodList = list.filter(synonym => (synonym[1] - currentWordSyllables > adjustment) && (synonym[1] < currentWordSyllables)).sort(function(a, b) {return a[1]-b[1]});
    }

    if (!_.isEmpty(otheradjustednotasgoodList)) {
      return otheradjustednotasgoodList[0][0]
    } else {
      return word;
    }
  } else {
    return word;
  }

}

function possibleSynonymArray(word) {
  if (thesaurus[word]) {
    return thesaurus[word];
  }
}

function possibleSynonymArrayAsync(word) {
  var promise = $.Deferred();

  var possibleNewWords = [];
  wordnet.lookup(word, function(err, definitions) {
    if (definitions) {
      definitions.forEach(function(definition) {
        var words = definition.meta.words;
        words.forEach(function(word) {
          if (!_.includes(possibleNewWords, word.word)) {
            possibleNewWords.push(word.word);
          }
        });
      });
    }
    promise.resolve(possibleNewWords);
  });
  return promise;
}

export function expandWord(word, adjustment) {
  let possibleNewWord = [];
  let theNewWord;
  let newWordSyllables;
  let adjustedList;
  let otheradjustednotasgoodList;
  let currentWordSyllables = syllable(word);
  let list = []

  var response = possibleSynonymArray(word);

  if (!_.isEmpty(response)){
    for (let x=0; x<response.length; x++) {
      list[x] = [response[x], syllable(response[x])]
    }

    adjustedList = list.filter(synonym => synonym[1] - currentWordSyllables === adjustment);
    if (!_.isEmpty(adjustedList)) {
      return adjustedList[0][0];
    } else {
      otheradjustednotasgoodList = list.filter(synonym => (synonym[1] - currentWordSyllables < adjustment) && (synonym[1] > currentWordSyllables)).sort(function(a, b) {return b[1]-a[1]});
    }

    if (!_.isEmpty(otheradjustednotasgoodList)) {
      return otheradjustednotasgoodList[0][0]
    } else {
      return word;
    }
  } else {
    return word;
  }
}

let countSyllables = function(phrase) {
  let tokens = phrase.split(/\W/);
  return _.sum(tokens.map(syllable));
};

function adjustWord(word, adjustment) {
  if (adjustment > 0) {
    return expandWord(word, adjustment);
  } else if (adjustment < 0) {
    return shortenWord(word, adjustment);
  } else {
    return word;
  }
}

export function adjustPhrase(phrase, adjustment) {
  if (adjustment > 0) {
    return addWords(phrase, adjustment);
  } else if (adjustment < 0) {
    return removeWords(phrase, adjustment);
  } else {
    return phrase;
  }
}

function adjustSyllables(lines, adjustment) {
  let line = 0;
  let idx = 0;
  let token = lines[line][idx];

  // First loop to make small adjustments to existing words' lengths.
  while (adjustment !== 0 && line < 3) {
    let newWord = adjustWord(token, adjustment);

    if (newWord) {
      lines[line][idx] = newWord;
      adjustment -= (syllable(newWord) - syllable(token));
    }

    idx++;
    token = lines[line][idx];
    if (!token) {
      line++;
      idx = 0;
      if (line > 2) {
        break;
      }
      token = lines[line][idx];

    }
  }

  var joined = lines.map(line => line.join(' '));
  line = 0;

  // Second while loop to add / remove extraneous words
  while (adjustment !== 0 && line < 3) {
    let oldPhrase = joined[line];
    let lineCount = countSyllables(oldPhrase);

    if ((line === 1 && lineCount === 7) || lineCount === 5) {
      line++;
    } else {
      var newPhrase;
      var maxLineAdjustment = (line === 1) ? 7 : 5;
      var lineAdjustment;

      if (adjustment < 0) {
        maxLineAdjustment *= -1;
        lineAdjustment = adjustment < maxLineAdjustment ?  maxLineAdjustment : adjustment;
        lineAdjustment += lineCount;
      } else if (adjustment > 0) {

        let maxPossibleAdjustment = (maxLineAdjustment - lineCount);
        lineAdjustment = adjustment > maxPossibleAdjustment ? maxPossibleAdjustment : adjustment;

      }

      newPhrase = adjustPhrase(oldPhrase, lineAdjustment);

      joined[line] = newPhrase;
      adjustment -= (countSyllables(newPhrase) - countSyllables(oldPhrase));
      line++;
    }

  }

  return joined.join(' ' + separator + ' ');
}

export function isHaiku(msg) {
  return countSyllables(msg, separator) === HAIKU_LENGTH;
}

export function breakIntoHaiku(msg) {
  var tokens = msg.trim().split(/\W/);
  var rows = [[], [], []];
  var rowSyllables = 0;
  var line = 0;
  while (tokens.length) {
    let token = tokens.shift();
    let tokenLength = syllable(token);

    if (line === 0) {
      var diff = (rowSyllables + tokenLength) - 5;
      if (diff > 0) {
        line += 1;
        rowSyllables = 0;
      }

    } else if (line === 1) {

      var diff = (rowSyllables + tokenLength) - 7;
      if (diff > 0) {
        line += 1;
        rowSyllables = 0;
      }

    }

    rowSyllables += tokenLength;
    rows[line].push(token);

  }

  return rows;
}

/**
 * steps to check if it is a haiku
 * 1. check syllable length of commit
 * 2. if longer - > check for haikus in commit..
 *  a) if haiku -> print done !
 *  b) if not -> get most of haiku and continue? choose key words and continue?
 * 3. if shorter -> check syllable counts?
 * for what is missing -> fill in rhyme etc. to make up length ?? nonsensical ??
 */
 export function makeHaiku(msg) {
  let syllables = countSyllables(msg);
  let difference = HAIKU_LENGTH - syllables;

  msg = breakIntoHaiku(msg);
  return adjustSyllables(msg, difference);
}<commit_msg>This weekend the // codex hackathon happened // and we made a really incorrigible fresh buggy thing<commit_after>import syllable from 'syllable';
import _ from 'lodash';
import wordnet from 'wordnet';
var $ = require('jquery-deferred');
import stopwords from './data/stopwords.js';
import descriptors from './data/descriptors.js';
import cusseth from './data/cusseth.js';
import nouns from './data/nouns.js';
import thesaurus from './data/thesaurus.js';

let adjectives = descriptors.map(word => [word, syllable(word)]);
let curses = cusseth.map(word => [word, syllable(word)]);

const HAIKU_LENGTH = 17;
const separator = '//';
const FOUL = false;

// Chrys' Domain
function addModifier(phrase, length, mod) {
  let tokens = phrase.split(/\W/);
  let nounList = tokens.map(word => _.contains(nouns, word));
  for (var i in nounList) {
    if (nounList[i]) {
      tokens.splice(i, 0, mod);
      return tokens.join(' ');
    }
  }

  return mod + ' ' + phrase;
}

export function addExpletive(phrase, length) {
  var curse = _.sample(curses.filter(tuple => tuple[1] === length));
  if (!curse) {
    return addExpletive(addExpletive(phrase, length - 1), 1);
  }

  return addModifier(phrase, length, curse[0]);
}

export function addAdjective(phrase, length) {
  var adj = _.sample(adjectives.filter(tuple => tuple[1] === length));
  if (!adj) {
    return addAdjective(addAdjective(phrase, length - 1), 1);
  }

  return addModifier(phrase, length, adj[0]);
}

export function removeWords(phrase, length) {
  length *= -1;
  let tokens = phrase.split(/\W/);
  let newTokens = [];
  tokens.forEach(function(token) {
    if (length && _.contains(stopwords, token)) {
      length -= syllable(token);
    } else {
      newTokens.push(token);
    }
  });

  return newTokens.join(' ');
}

function addWords(phrase, length) {
  if (FOUL) {
    return addExpletive(phrase, length);
  } else {
    return addAdjective(phrase, length);
  }
}

// Nicole WUZ HERE
export function shortenWord(word, adjustment) {
  let possibleNewWord = [];
  let theNewWord;
  let newWordSyllables;
  let adjustedList;
  let otheradjustednotasgoodList;
  let currentWordSyllables = syllable(word);

  adjustment = -adjustment;

  let list = []

  var response = possibleSynonymArray(word);

  if (!_.isEmpty(response)) {
    for (let x=0; x<response.length; x++) {
      list[x] = [response[x], syllable(response[x])]
    }

    adjustedList = list.filter(synonym => synonym[1] - currentWordSyllables === adjustment);

    if (!_.isEmpty(adjustedList)) {
      return adjustedList[0][0];
    }

    else {
      otheradjustednotasgoodList = list.filter(synonym => (synonym[1] - currentWordSyllables > adjustment) && (synonym[1] < currentWordSyllables)).sort(function(a, b) {return a[1]-b[1]});
    }

    if (!_.isEmpty(otheradjustednotasgoodList)) {
      return otheradjustednotasgoodList[0][0]
    } else {
      return word;
    }
  } else {
    return word;
  }

}

function possibleSynonymArray(word) {
  if (thesaurus[word]) {
    return thesaurus[word];
  }
}

function possibleSynonymArrayAsync(word) {
  var promise = $.Deferred();

  var possibleNewWords = [];
  wordnet.lookup(word, function(err, definitions) {
    if (definitions) {
      definitions.forEach(function(definition) {
        var words = definition.meta.words;
        words.forEach(function(word) {
          if (!_.includes(possibleNewWords, word.word)) {
            possibleNewWords.push(word.word);
          }
        });
      });
    }
    promise.resolve(possibleNewWords);
  });
  return promise;
}

export function expandWord(word, adjustment) {
  let possibleNewWord = [];
  let theNewWord;
  let newWordSyllables;
  let adjustedList;
  let otheradjustednotasgoodList;
  let currentWordSyllables = syllable(word);
  let list = []

  var response = possibleSynonymArray(word);

  if (!_.isEmpty(response)){
    for (let x=0; x<response.length; x++) {
      list[x] = [response[x], syllable(response[x])]
    }

    adjustedList = list.filter(synonym => synonym[1] - currentWordSyllables === adjustment);
    if (!_.isEmpty(adjustedList)) {
      return adjustedList[0][0];
    } else {
      otheradjustednotasgoodList = list.filter(synonym => (synonym[1] - currentWordSyllables < adjustment) && (synonym[1] > currentWordSyllables)).sort(function(a, b) {return b[1]-a[1]});
    }

    if (!_.isEmpty(otheradjustednotasgoodList)) {
      return otheradjustednotasgoodList[0][0]
    } else {
      return word;
    }
  } else {
    return word;
  }
}

let countSyllables = function(phrase) {
  let tokens = phrase.split(/\W/);
  return _.sum(tokens.map(syllable));
};

function adjustWord(word, adjustment) {
  if (adjustment > 0) {
    return expandWord(word, adjustment);
  } else if (adjustment < 0) {
    return shortenWord(word, adjustment);
  } else {
    return word;
  }
}

export function adjustPhrase(phrase, adjustment) {
  if (adjustment > 0) {
    return addWords(phrase, adjustment);
  } else if (adjustment < 0) {
    return removeWords(phrase, adjustment);
  } else {
    return phrase;
  }
}

function adjustSyllables(lines, adjustment) {
  let line = 0;
  let idx = 0;
  let token = lines[line][idx];

  // First loop to make small adjustments to existing words' lengths.
  while (adjustment !== 0 && line < 3) {
    let newWord = adjustWord(token, adjustment);

    if (newWord) {
      lines[line][idx] = newWord;
      adjustment -= (syllable(newWord) - syllable(token));
    }

    idx++;
    token = lines[line][idx];
    if (!token) {
      line++;
      idx = 0;
      if (line > 2) {
        break;
      }
      token = lines[line][idx];

    }
  }

  var joined = lines.map(line => line.join(' '));
  line = 0;

  // Second while loop to add / remove extraneous words
  while (adjustment !== 0 && line < 3) {
    let oldPhrase = joined[line];
    let lineCount = countSyllables(oldPhrase);

    if ((line === 1 && lineCount === 7) || lineCount === 5) {
      line++;
    } else {
      var newPhrase;
      var maxLineAdjustment = (line === 1) ? 7 : 5;
      var lineAdjustment;

      if (adjustment < 0) {
        maxLineAdjustment *= -1;
        lineAdjustment = adjustment < maxLineAdjustment ?  maxLineAdjustment : adjustment;
        lineAdjustment += lineCount;
      } else if (adjustment > 0) {

        let maxPossibleAdjustment = (maxLineAdjustment - lineCount);
        lineAdjustment = adjustment > maxPossibleAdjustment ? maxPossibleAdjustment : adjustment;

      }

      newPhrase = adjustPhrase(oldPhrase, lineAdjustment);

      joined[line] = newPhrase;
      adjustment -= (countSyllables(newPhrase) - countSyllables(oldPhrase));
      line++;
    }

  }

  return joined.join(' ' + separator + ' ');
}

export function isHaiku(msg) {
  return countSyllables(msg, separator) === HAIKU_LENGTH;
}

export function breakIntoHaiku(msg) {
  var tokens = msg.trim().split(/\W/);
  var rows = [[], [], []];
  var rowSyllables = 0;
  var line = 0;
  while (tokens.length) {
    let token = tokens.shift();
    let tokenLength = syllable(token);

    if (line === 0) {
      var diff = (rowSyllables + tokenLength) - 5;
      if (diff > 0) {
        line += 1;
        rowSyllables = 0;
      }

    } else if (line === 1) {

      var diff = (rowSyllables + tokenLength) - 7;
      if (diff > 0) {
        line += 1;
        rowSyllables = 0;
      }

    }

    rowSyllables += tokenLength;
    rows[line].push(token);

  }

  return rows;
}

/**
 * steps to check if it is a haiku
 * 1. check syllable length of commit
 * 2. if longer - > check for haikus in commit..
 *  a) if haiku -> print done !
 *  b) if not -> get most of haiku and continue? choose key words and continue?
 * 3. if shorter -> check syllable counts?
 * for what is missing -> fill in rhyme etc. to make up length ?? nonsensical ??
 */
 export function makeHaiku(msg) {
  let syllables = countSyllables(msg);
  let difference = HAIKU_LENGTH - syllables;

  msg = breakIntoHaiku(msg);
  return adjustSyllables(msg, difference);
}<|endoftext|>


<commit_before>var Issue = require('../issue');

module.exports = {
    name: 'attr-bans',
    on: ['tag']
};

module.exports.lint = function (element, opts) {
    var bannedAttrs = opts[this.name];

    if (!bannedAttrs || !element.attribs) {
        return [];
    }

    var issues = [];

    bannedAttrs.forEach(function (attr) {
        if (element.attribs.hasOwnProperty(attr)) {
            var a = element.attribs[attr],
                issue = this.createIssue(attr, a);

            issues.push(issue);
        }
    }.bind(this));

    return issues;
};

module.exports.createIssue = function (attrName, attr) {
    var pos = attr.nameLineCol,
        data = { attribute: attrName };

    return new Issue('E001', pos, data);
};
<commit_msg>Clean up attr-bans code<commit_after>var Issue = require('../issue');

module.exports = {
    name: 'attr-bans',
    on: ['tag']
};

module.exports.lint = function (element, opts) {
    var bannedAttrs = opts[this.name];

    if (!bannedAttrs || !element.attribs) {
        return [];
    }

    var issues = [];

    var attrs = element.attribs;
    bannedAttrs.forEach(function (name) {
        if (attrs.hasOwnProperty(name)) {
            issues.push(new Issue('E001',
                attrs[name].nameLineCol, { attribute: name }));
        }
    });

    return issues;
};
<|endoftext|>


<commit_before>'use strict';

var helpers = require('../helpers');

var units = [
  'em',
  'ex',
  'ch',
  'rem',
  'vh',
  'vw',
  'vmin',
  'vmax',
  'px',
  'mm',
  'cm',
  'in',
  'pt',
  'pc'
];

module.exports = {
  'name': 'zero-unit',
  'defaults': {
    'include': false
  },
  'detect': function (ast, parser) {
    var result = [];

    ast.traverseByType('number', function (item, i, parent) {

      if (item.content === '0') {
        if (parent.type === 'dimension') {
          var next = parent.content[i + 1] || false;

          if (units.indexOf(next.content) !== -1) {
            if (!parser.options.include) {
              result = helpers.addUnique(result, {
                'ruleId': parser.rule.name,
                'severity': parser.severity,
                'line': item.end.line,
                'column': item.end.column,
                'message': 'No unit allowed for values of 0'
              });
            }
          }
        }
        else {
          if (parent.type === 'value') {
            if (parser.options.include) {
              result = helpers.addUnique(result, {
                'ruleId': parser.rule.name,
                'severity': parser.severity,
                'line': item.end.line,
                'column': item.end.column,
                'message': 'Unit required for values of 0'
              });
            }
          }
        }
      }
    });

    return result;
  }
};
<commit_msg>Percents added to units list of "zero-unit" rule<commit_after>'use strict';

var helpers = require('../helpers');

var units = [
  '%',
  'em',
  'ex',
  'ch',
  'rem',
  'vh',
  'vw',
  'vmin',
  'vmax',
  'px',
  'mm',
  'cm',
  'in',
  'pt',
  'pc'
];

module.exports = {
  'name': 'zero-unit',
  'defaults': {
    'include': false
  },
  'detect': function (ast, parser) {
    var result = [];

    ast.traverseByType('number', function (item, i, parent) {

      if (item.content === '0') {
        if (parent.type === 'dimension') {
          var next = parent.content[i + 1] || false;

          if (units.indexOf(next.content) !== -1) {
            if (!parser.options.include) {
              result = helpers.addUnique(result, {
                'ruleId': parser.rule.name,
                'severity': parser.severity,
                'line': item.end.line,
                'column': item.end.column,
                'message': 'No unit allowed for values of 0'
              });
            }
          }
        }
        else {
          if (parent.type === 'value') {
            if (parser.options.include) {
              result = helpers.addUnique(result, {
                'ruleId': parser.rule.name,
                'severity': parser.severity,
                'line': item.end.line,
                'column': item.end.column,
                'message': 'Unit required for values of 0'
              });
            }
          }
        }
      }
    });

    return result;
  }
};
<|endoftext|>


<commit_before>"use strict";

/**
 * @constructor
 * @param {Object=} wm
 * @param {Object=} codegen
 * @param {Object=} coverage_logger
 */
function v86(bus, wm, codegen, coverage_logger)
{
    /** @type {boolean} */
    this.running = false;

    /** @type {boolean} */
    this.stopped = false;

    /** @type {CPU} */
    this.cpu = new CPU(bus, wm, codegen, coverage_logger);

    this.bus = bus;
    bus.register("cpu-init", this.init, this);
    bus.register("cpu-run", this.run, this);
    bus.register("cpu-stop", this.stop, this);
    bus.register("cpu-restart", this.restart, this);

    this.register_tick();
}

v86.prototype.run = function()
{
    this.stopped = false;

    if(!this.running)
    {
        this.bus.send("emulator-started");
        this.fast_next_tick();
    }
};

v86.prototype.do_tick = function()
{
    if(this.stopped)
    {
        this.stopped = this.running = false;
        this.bus.send("emulator-stopped");
        return;
    }

    this.running = true;
    var dt = this.cpu.main_run();

    if(dt <= 0)
    {
        this.fast_next_tick();
    }
    else
    {
        this.next_tick(dt);
    }
};

v86.prototype.stop = function()
{
    if(this.running)
    {
        this.stopped = true;
    }
};

v86.prototype.restart = function()
{
    this.cpu.reset();
    this.cpu.load_bios();
};

v86.prototype.init = function(settings)
{
    this.cpu.init(settings, this.bus);
    this.bus.send("emulator-ready");
};

if(typeof setImmediate !== "undefined")
{
    /** @this {v86} */
    var fast_next_tick = function()
    {
        setImmediate(() => { this.do_tick(); });
    };

    /** @this {v86} */
    var register_tick = function() {};
}
else if(typeof window !== "undefined" && typeof postMessage !== "undefined")
{
    // setImmediate shim for the browser.
    // TODO: Make this deactivatable, for other applications
    //       using postMessage

    /** @const */
    let MAGIC_POST_MESSAGE = 0xAA55;

    /** @this {v86} */
    fast_next_tick = function()
    {
        window.postMessage(MAGIC_POST_MESSAGE, "*");
    };

    /** @this {v86} */
    register_tick = function()
    {
        window.addEventListener("message", (e) =>
        {
            if(e.source === window && e.data === MAGIC_POST_MESSAGE)
            {
                this.do_tick();
            }
        }, false);
    };
}
else
{
    /** @this {v86} */
    fast_next_tick = function()
    {
        setTimeout(() => { this.do_tick(); }, 0);
    };

    /** @this {v86} */
    register_tick = function() {};
}

v86.prototype.fast_next_tick = fast_next_tick;
v86.prototype.register_tick = register_tick;

if(typeof document !== "undefined" && typeof document.hidden === "boolean")
{
    /** @this {v86} */
    var next_tick = function(t)
    {
        if(t < 4 || document.hidden)
        {
            // Avoid sleeping for 1 second (happens if page is not
            // visible), it can break boot processes. Also don't try to
            // sleep for less than 4ms, since the value is clamped up
            this.fast_next_tick();
        }
        else
        {
            setTimeout(() => { this.do_tick(); }, t);
        }
    };
}
else
{
    // In environments that aren't browsers, we might as well use setTimeout
    /** @this {v86} */
    next_tick = function(t)
    {
        setTimeout(() => { this.do_tick(); }, t);
    };
}

v86.prototype.next_tick = next_tick;

v86.prototype.save_state = function()
{
    // TODO: Should be implemented here, not on cpu
    return this.cpu.save_state();
};

v86.prototype.restore_state = function(state)
{
    // TODO: Should be implemented here, not on cpu
    return this.cpu.restore_state(state);
};

if(typeof performance === "object" && performance.now)
{
    v86.microtick = performance.now.bind(performance);
}
else if(typeof process === "object" && process.hrtime)
{
    v86.microtick = function()
    {
        var t = process.hrtime();
        return t[0] * 1000 + t[1] / 1e6;
    };
}
else
{
    v86.microtick = Date.now;
}
<commit_msg>nodejs: Prefer perf_hooks module over custom shim for performance.now<commit_after>"use strict";

/**
 * @constructor
 * @param {Object=} wm
 * @param {Object=} codegen
 * @param {Object=} coverage_logger
 */
function v86(bus, wm, codegen, coverage_logger)
{
    /** @type {boolean} */
    this.running = false;

    /** @type {boolean} */
    this.stopped = false;

    /** @type {CPU} */
    this.cpu = new CPU(bus, wm, codegen, coverage_logger);

    this.bus = bus;
    bus.register("cpu-init", this.init, this);
    bus.register("cpu-run", this.run, this);
    bus.register("cpu-stop", this.stop, this);
    bus.register("cpu-restart", this.restart, this);

    this.register_tick();
}

v86.prototype.run = function()
{
    this.stopped = false;

    if(!this.running)
    {
        this.bus.send("emulator-started");
        this.fast_next_tick();
    }
};

v86.prototype.do_tick = function()
{
    if(this.stopped)
    {
        this.stopped = this.running = false;
        this.bus.send("emulator-stopped");
        return;
    }

    this.running = true;
    var dt = this.cpu.main_run();

    if(dt <= 0)
    {
        this.fast_next_tick();
    }
    else
    {
        this.next_tick(dt);
    }
};

v86.prototype.stop = function()
{
    if(this.running)
    {
        this.stopped = true;
    }
};

v86.prototype.restart = function()
{
    this.cpu.reset();
    this.cpu.load_bios();
};

v86.prototype.init = function(settings)
{
    this.cpu.init(settings, this.bus);
    this.bus.send("emulator-ready");
};

if(typeof setImmediate !== "undefined")
{
    /** @this {v86} */
    var fast_next_tick = function()
    {
        setImmediate(() => { this.do_tick(); });
    };

    /** @this {v86} */
    var register_tick = function() {};
}
else if(typeof window !== "undefined" && typeof postMessage !== "undefined")
{
    // setImmediate shim for the browser.
    // TODO: Make this deactivatable, for other applications
    //       using postMessage

    /** @const */
    let MAGIC_POST_MESSAGE = 0xAA55;

    /** @this {v86} */
    fast_next_tick = function()
    {
        window.postMessage(MAGIC_POST_MESSAGE, "*");
    };

    /** @this {v86} */
    register_tick = function()
    {
        window.addEventListener("message", (e) =>
        {
            if(e.source === window && e.data === MAGIC_POST_MESSAGE)
            {
                this.do_tick();
            }
        }, false);
    };
}
else
{
    /** @this {v86} */
    fast_next_tick = function()
    {
        setTimeout(() => { this.do_tick(); }, 0);
    };

    /** @this {v86} */
    register_tick = function() {};
}

v86.prototype.fast_next_tick = fast_next_tick;
v86.prototype.register_tick = register_tick;

if(typeof document !== "undefined" && typeof document.hidden === "boolean")
{
    /** @this {v86} */
    var next_tick = function(t)
    {
        if(t < 4 || document.hidden)
        {
            // Avoid sleeping for 1 second (happens if page is not
            // visible), it can break boot processes. Also don't try to
            // sleep for less than 4ms, since the value is clamped up
            this.fast_next_tick();
        }
        else
        {
            setTimeout(() => { this.do_tick(); }, t);
        }
    };
}
else
{
    // In environments that aren't browsers, we might as well use setTimeout
    /** @this {v86} */
    next_tick = function(t)
    {
        setTimeout(() => { this.do_tick(); }, t);
    };
}

v86.prototype.next_tick = next_tick;

v86.prototype.save_state = function()
{
    // TODO: Should be implemented here, not on cpu
    return this.cpu.save_state();
};

v86.prototype.restore_state = function(state)
{
    // TODO: Should be implemented here, not on cpu
    return this.cpu.restore_state(state);
};

if(typeof performance === "object" && performance.now)
{
    v86.microtick = performance.now.bind(performance);
}
else if(typeof require === "function")
{
    const { performance } = require("perf_hooks");
    v86.microtick = performance.now.bind(performance);
}
else if(typeof process === "object" && process.hrtime)
{
    v86.microtick = function()
    {
        var t = process.hrtime();
        return t[0] * 1000 + t[1] / 1e6;
    };
}
else
{
    v86.microtick = Date.now;
}
<|endoftext|>


<commit_before>import Cycle from '@cycle/core'
import {Observable} from 'rx'
import {div, ul, li, makeDOMDriver} from '@cycle/DOM'
import {intersection, difference, sortBy} from 'lodash'

function intent(keydownSource) {
  return keydownSource
    .map(ev => ev.code.replace('Key', ''))
    .filter(str => str.length === 1)
}

function model(action$) {
  const initialState = ['A']
  return action$.startWith(initialState).startWith([]).scan((acc, key) => {
    const index = acc.indexOf(key)
    if (index === -1) {
      return acc.concat(key).sort()
    }
    const newAcc = acc.slice()
    newAcc.splice(index, 1)
    return newAcc
  })
}

function determineDeltaPoints(state$) {
  return state$.pairwise().flatMap(([before, after]) => {
    const addedPoints = difference(after, before).map(key =>
      ({key, value: 0, target: 1})
    )
    const removedPoints = difference(before, after).map(key =>
      ({key, value: 1, target: 0})
    )
    const points = addedPoints.concat(removedPoints)
    return Observable.from(sortBy(points, 'key'))
  })
}

function expandAsRenderingFrames(point$) {
  return point$.flatMapLatest(point =>
    Observable.interval(10).map(point).take(100)
  )
}

function calculateAnimationSteps(point$) {
  function incorporateNewPoint(oldPoints, newPoint) {
    const index = oldPoints.findIndex(point => point.key === newPoint.key)
    let points
    if (index === -1 && newPoint.target === 1) {
      points = oldPoints.concat(newPoint)
    } else {
      points = oldPoints.slice()
      points[index] = newPoint
    }
    return points
  }

  function progressEachPoint(oldPoints, newPoints) {
    return newPoints.map(newPoint => {
      const target = newPoint.target
      const oldPoint = oldPoints.find(p => p.key === newPoint.key)
      const value = !!oldPoint ? oldPoint.value : newPoint.value
      return {
        ...newPoint,
        value: (Math.abs(target - value) < 0.01) ?
          target :
          value + (target - value) * 0.05
      }
    })
  }

  return point$.scan((acc, point) => {
    const newAcc = incorporateNewPoint(acc, point)
    const progressedAcc = progressEachPoint(acc, newAcc)
    const sanitizedAcc = progressedAcc.filter(point =>
      !(point.target === 0 && point.value === 0)
    )
    const sortedAcc = sortBy(sanitizedAcc, 'key')
    return sortedAcc
  }, [])
}

function animate(state$) {
  return state$
    .let(determineDeltaPoints)
    .let(expandAsRenderingFrames)
    .let(calculateAnimationSteps)
}

function view(state$) {
  const animatedState$ = animate(state$)
  const ulStyle = {padding: '0', listStyle: 'none', display: 'flex'}
  const liStyle = {fontSize: '50px'}
  return animatedState$.map(animStates =>
    ul({style: ulStyle}, animStates.map(animState =>
      li({style: {fontSize: `${animState.value * 50}px`}}, animState.key)
    ))
  )
}

function main(sources) {
  const key$ = intent(sources.Keydown)
  const state$ = model(key$)
  const vtree$ = view(state$)
  return {
    DOM: vtree$,
  }
}

Cycle.run(main, {
  Keydown: () => Observable.fromEvent(document, 'keydown'),
  DOM: makeDOMDriver('#app')
})
<commit_msg>Initial working prototype<commit_after>import Cycle from '@cycle/core'
import {Observable} from 'rx'
import {label, section, h1, div, input, makeDOMDriver} from '@cycle/DOM'

function main({DOM}) {
  let changeHourlyRate$ = DOM.select('.hourly-rate')
    .events('input')
    .map(ev => {
      let value = parseFloat(ev.target.value);
      if(isNaN(value)){
        return 0;
      } else {
        return value;
      }
    });
  let changeHoursWorked$ = DOM.select('.hours-worked')
    .events('input')
    .map(ev => {
      let value = parseFloat(ev.target.value);
      if(isNaN(value)){
        return 0;
      } else {
        return value;
      }
    });
  let minutesWorked$ = DOM.select('.minutes-worked')
    .events('input')
    .map(ev => {
      let value = parseFloat(ev.target.value);
      if(isNaN(value)){
        return 0;
      } else {
        return value;
      }
    });
  let secondsWorked$ = DOM.select('.seconds-worked')
    .events('input')
    .map(ev => {
      let value = parseFloat(ev.target.value);
      if(isNaN(value)){
        return 0;
      } else {
        return value;
      }
    });
  let state$ = Observable.combineLatest(
    changeHourlyRate$.startWith(50),
    changeHoursWorked$.startWith(40),
    minutesWorked$.startWith(0),
    secondsWorked$.startWith(0),
    (hourlyRate, hoursWorked, minutesWorked, secondsWorked) => {
      let secondsInMinutes = secondsWorked / 60;
      let minutesInHours = (secondsInMinutes + minutesWorked) / 60;
      let convertedHoursWorked = hoursWorked + minutesInHours;
      let totalSum = hourlyRate * convertedHoursWorked;
      let convertedTotalSum = Math.round(totalSum * 100) / 100;
      return {hourlyRate, hoursWorked, minutesWorked, secondsWorked, totalSum: convertedTotalSum};
    }
  );
  return {
    DOM: state$
      .map(({hourlyRate, hoursWorked, minutesWorked, secondsWorked, totalSum}) =>
        div('.container', [
          section([
            label('.hourly-rate-label', 'Hourly Rate'),
            input('.hourly-rate', {type: 'number', value: hourlyRate, min: 1, max: 10000})
          ]),
          section([
            label('.hours-worked-label', 'Hours Worked'),
            input('.hours-worked', {type: 'number', value: hoursWorked, min: 0, max: 10000})
          ]),
          section([
            label('.minutes-worked-label', 'Minutes Worked'),
            input('.minutes-worked', {type: 'number', value: minutesWorked, min: 0, max: 60})
          ]),
          section([
            label('.seconds-worked-label', 'Seconds Worked'),
            input('.seconds-worked', {type: 'number', value: secondsWorked, min: 0, max: 60})
          ]),
          h1('Total sum: ' + totalSum + '$')
      ])
    ),
  LOG: state$
  };
}

Cycle.run(main, {
  DOM: makeDOMDriver('#app'),
  LOG: msg$ => { msg$.subscribe(msg => console.log(msg)) }
})
<|endoftext|>


<commit_before>// @Compiler-Transpile "true"
// @Compiler-Output "../dist/main.js"
'use strict'

const Buffer = require('buffer').Buffer

class Proto {
  static Encode(Request) {
    if (Request === null || typeof Request === 'undefined') {
      return "$0\r\n\r\n"
    } else if (typeof Request === 'object' || (typeof Request !== 'string' && typeof Request.length === 'number')) {
      const toReturn = ['*' + Request.length]
      const length = Request.length
      for (let i = 0 ; i < length; ++i ) {
        toReturn[i + 1] = Proto.Encode(Request[i])
      }
      return toReturn.join("\r\n")
    } else if (typeof Request === 'number') {
      return `:${Request}`
    } else {
      if (typeof Request !== 'string') {
        Request = Request.toString('utf8')
      }
      return "$" + Request.length + "\r\n" + Request
    }
  }
  static Decode(Content) {
    if (!Buffer.isBuffer(Content)) {
      Content = new Buffer(Content)
    }
    const Buffers = []
    while(true){
      let Entry = Proto.DecodeEntry(Content)
      if(!Entry) break
      Buffers.push(Entry.value)
      Content = Content.slice(Entry.offset)
      if(!Content.length) break
    }
    return Buffer.concat(Buffers)
  }
  static *DecodeGen(Content) {
    if (!Buffer.isBuffer(Content)) {
      Content = new Buffer(Content)
    }
    while(true){
      let Entry = Proto.DecodeEntry(Content)
      if(!Entry) break
      yield Entry.value
      Content = Content.slice(Entry.offset)
      if(!Content.length) break
    }
  }
  static DecodeEntry(Content){
    const Type = Content.readInt8(0)
    const Index = Content.indexOf("\r\n")
    const Count = parseInt(Content.slice(1, Index).toString())

    if(Type === 42){ // *
      let ToReturn = []
      let Offset = Index + 2
      for(var i = 1; i <= Count; ++i){
        let Entry = Proto.DecodeEntry(Content.slice(Offset))
        ToReturn.push(Entry.value)
        Offset += Entry.offset
      }
      return {value: ToReturn, offset: Offset}
    } else if(Type === 36){ // 36 : $
      return (Count === -1) ? {value: null, offset: Index + 2} : {value: Content.slice(Index + 2, Index + 2 + Count), offset: Index + Count + 4}
    } else if(Type === 45){ // 45 : -
      throw new Error(Content.slice(1, Index))
    } else if(Type === 43){ // 43 : +
      return {value: Content.slice(1, Index), offset: Index + 2}
    } else if(Type === 58){ // 58 : :
      return {value: Content.slice(1, Index), offset: Index + 2}
    } else throw new Error('Error Decoding Redis Response')
  }
}
module.exports = Proto
<commit_msg>:new: Decode same buffer with startIndex<commit_after>// @Compiler-Transpile "true"
// @Compiler-Output "../dist/main.js"
'use strict'

const Buffer = require('buffer').Buffer

class Proto {
  static Encode(Request) {
    if (Request === null || typeof Request === 'undefined') {
      return "$0\r\n\r\n"
    } else if (typeof Request === 'object' || (typeof Request !== 'string' && typeof Request.length === 'number')) {
      const toReturn = ['*' + Request.length]
      const length = Request.length
      for (let i = 0 ; i < length; ++i ) {
        toReturn[i + 1] = Proto.Encode(Request[i])
      }
      return toReturn.join("\r\n")
    } else if (typeof Request === 'number') {
      return `:${Request}`
    } else {
      if (typeof Request !== 'string') {
        Request = Request.toString('utf8')
      }
      return "$" + Request.length + "\r\n" + Request
    }
  }
  static Decode(Content) {
    if (!Buffer.isBuffer(Content)) {
      Content = new Buffer(Content)
    }
    const Buffers = []
    let offset = 0
    while(true){
      let Entry = Proto.DecodeEntry(Content, offset)
      if(!Entry) break
      Buffers.push(Entry.value)
      offset += Entry.offset
      if(!Content.length) break
    }
    return Buffers
  }
  static *DecodeGen(Content) {
    if (!Buffer.isBuffer(Content)) {
      Content = new Buffer(Content)
    }
    while(true){
      let Entry = Proto.DecodeEntry(Content)
      if(!Entry) break
      yield Entry.value
      Content = Content.slice(Entry.offset)
      if(!Content.length) break
    }
  }
  static DecodeEntry(Content, startIndex){
    const Type = Content.readInt8(startIndex)
    const Index = Content.indexOf("\r\n", startIndex)
    const Count = parseInt(Content.toString('utf8', startIndex + 1, Index))

    if(Type === 42){ // *
      let ToReturn = []
      let Offset = Index + 2
      for(var i = 1; i <= Count; ++i){
        let Entry = Proto.DecodeEntry(Content.slice(Offset))
        ToReturn.push(Entry.value)
        Offset += Entry.offset
      }
      return {value: ToReturn, offset: Offset}
    } else if(Type === 36){ // 36 : $
      return (Count === -1) ? {value: null, offset: Index + 2} : {value: Content.slice(Index + 2, Index + 2 + Count), offset: Index + Count + 4}
    } else if(Type === 45){ // 45 : -
      throw new Error(Content.slice(1, Index))
    } else if(Type === 43){ // 43 : +
      return {value: Content.slice(1, Index), offset: Index + 2}
    } else if(Type === 58){ // 58 : :
      return {value: Content.slice(1, Index), offset: Index + 2}
    } else throw new Error('Error Decoding Redis Response')
  }
}
module.exports = Proto
<|endoftext|>


<commit_before>var idCounter=0;
function generateId() {
	return 'webgl-starter-id-'+(idCounter++);
}

var Options=require('./options.js');
var generateCode=require('./code.js');

function getHtmlDataUri(html) {
	// with base64: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/btoa
	//return "data:text/html;charset=utf-8;base64,"+window.btoa(unescape(encodeURIComponent(str)));
	// without base64: https://en.wikipedia.org/wiki/Data_URI_scheme
	return 'data:text/html;charset=utf-8,'+encodeURIComponent(html);
}

var i18n=function(id){ // fake temporary i18n
	return {
		'message.hljs': "highlight.js (hosted on cdnjs.cloudflare.com) is not loaded. Syntax highlighting is disabled.",

		'options.general': 'General options',
		'options.background': 'Background',
		'options.background.none': 'None (transparent)',
		'options.background.solid': 'Solid color',
		'options.shader': 'Shader',
		'options.shader.single': 'Single color',
		'options.shader.vertex': 'One color per vertex',
		'options.shader.face': 'One color per face',
		'options.shape': 'Shape to draw',
		'options.shape.square': 'Square',
		'options.shape.triangle': 'Triangle',
		'options.shape.gasket': 'Sierpinski gasket', // wp: Sierpinski triangle
		'options.shape.cube': 'Cube',
		'options.projection': 'Projection',
		'options.projection.ortho': 'Orthogonal',
		'options.projection.perspective': 'Perspective',

		'options.input': 'Input options',
		'options.canvas.width': 'Canvas width',
		'options.canvas.height': 'Canvas height',
		'options.background.solid.color.r': 'Background color red component',
		'options.background.solid.color.g': 'Background color green component',
		'options.background.solid.color.b': 'Background color blue component',
		'options.background.solid.color.a': 'Background color alpha component',
		'options.shader.single.color.r': 'Fragment color red component',
		'options.shader.single.color.g': 'Fragment color green component',
		'options.shader.single.color.b': 'Fragment color blue component',
		'options.shader.single.color.a': 'Fragment color alpha component',
		'options.shape.gasket.depth': 'Sierpinski gasket recursion depth',
		'options.animation.rotation.speed': 'Z axis rotation speed',
		'options.*.input': 'This value is',
		'options.*.input.constant': 'kept constant',
		'options.*.input.slider': 'updated with a slider',
		'options.*.input.mousemovex': 'updated by moving the mouse horizontally',
		'options.*.input.mousemovey': 'updated by moving the mouse vertically',
		'options.*.input.animated': 'animated',

		'options.transform': 'Transforms',
		'options.rotate.x': 'Angle of rotation around x axis',
		'options.rotate.x.speed': 'Speed of rotation around x axis',
		'options.rotate.y': 'Angle of rotation around y axis',
		'options.rotate.y.speed': 'Speed of rotation around y axis',
		'options.rotate.z': 'Angle of rotation around z axis',
		'options.rotate.z.speed': 'Speed of rotation around z axis',

		'options.debug': 'Debug options',
		'options.debugShader': 'Log shader compilation errors',
		'options.debugInputs': 'Log input values',

		'controls.type.mousemovex': 'Move the mouse pointer horizontally over the canvas',
		'controls.type.mousemovey': 'Move the mouse pointer vertically over the canvas',
		'controls.to': 'to update',
		/*
		// TODO
		'controls.value.background.solid.color.r': 'Background color red component',
		'controls.value.background.solid.color.g': 'Background color green component',
		'controls.value.background.solid.color.b': 'Background color blue component',
		'controls.value.background.solid.color.a': 'Background color alpha component',
		'controls.value.shader.single.color.r': 'Fragment color red component',
		'controls.value.shader.single.color.g': 'Fragment color green component',
		'controls.value.shader.single.color.b': 'Fragment color blue component',
		'controls.value.shader.single.color.a': 'Fragment color alpha component',
		'controls.value.shape.gasket.depth': 'Sierpinski gasket recursion depth',
		'controls.value.animation.rotation.speed': 'Z axis rotation speed',
		*/
	}[id];
};

$(function(){
	$('.webgl-starter').each(function(){
		var containerNode=$(this);
		var optionsNode;
		var codeNode;
		var options=new Options();
		var codeUpdateTimeoutId=null;
		var codeUpdateDelay=200;

		function showHideSuboptionInputs(optionName,optionValue) {
			// TODO sub-sub option support?
			optionsNode.find("[data-option^='"+optionName+".']").show()
				.not("[data-option^='"+optionName+"."+optionValue+".']").hide();
		}
		function updateCode() {
			clearTimeout(codeUpdateTimeoutId);
			codeUpdateTimeoutId=setTimeout(function(){
				codeNode.text(generateCode(options.cloneWithoutHidden(),i18n));
				if (window.hljs) hljs.highlightBlock(codeNode[0]);
			},codeUpdateDelay);
		}
		function writeGeneralOption(option) {
			var id=generateId();
			return $("
")
				.append(""+i18n('options.'+option.name)+":")
				.append(" ")
				.append(
					$("<select id='"+id+"'>").append(
						option.availableValues.map(function(availableValue){
							return $("<option>").val(availableValue).html(i18n('options.'+option.name+'.'+availableValue))
						})
					).val(options[option.name]).change(function(){
						options[option.name]=this.value;
						showHideSuboptionInputs(option.name,this.value);
						updateCode();
					})
				);
		}
		function writeInputOption(option) {
			var id=generateId();
			var inputId=generateId();
			var sliderInput,numberInput;
			function inputListener(that) {
				if (this.checkValidity()) {
					that.val(this.value);
					options[option.name]=parseFloat(this.value);
					updateCode();
				}
			}
			return $("
")
				.append(""+i18n('options.'+option.name)+":")
				.append(" "+option.getMinLabel()+" ")
				.append(
					sliderInput=$("<input type='range' id='"+id+"'>")
						.attr('min',option.getMin())
						.attr('max',option.getMax())
						.attr('step',option.getSetupStep())
						.val(options[option.name])
						.on('input change',function(){
							inputListener.call(this,numberInput);
						})
				)
				.append(" "+option.getMaxLabel()+" ")
				.append(
					numberInput=$("<input type='number' required>")
						.attr('min',option.getMin())
						.attr('max',option.getMax())
						.attr('step',option.getSetupStep())
						.val(options[option.name])
						.on('input change',function(){
							inputListener.call(this,sliderInput);
						})
				)
				.append(" ")
				.append(
					$("<button type='button'>Reset</button>").click(function(){
						sliderInput.val(option.defaultValue).change();
					})
				)
				.append(" ")
				.append(""+i18n('options.*.input')+" ")
				.append(
					$("<select id='"+inputId+"'>").append(
						option.availableInputTypes.map(function(availableInputType){
							return $("<option>").val(availableInputType).html(i18n('options.*.input.'+availableInputType))
						})
					).val(options[option.name+'.input']).change(function(){
						options[option.name+'.input']=this.value;
						updateCode();
					})
				);
		}
		function writeDebugOption(option) {
			var id=generateId();
			return $("
")
				.append(
					$("<input type='checkbox' id='"+id+"'>")
						.prop('checked',options[option.name])
						.change(function(){
							options[option.name]=$(this).prop('checked');
							updateCode();
						})
				)
				.append(" "+i18n('options.'+option.name)+"");
		}
		function writeOptions() {
			var $dragged=null;
			var isHandle=false; // https://github.com/farhadi/html5sortable/blob/master/jquery.sortable.js
			return $("
").append(
				$("<fieldset>").append("<legend>"+i18n('options.general')+"</legend>").append(
					options.generalOptions.map(writeGeneralOption)
				)
			).append(
				$("<fieldset>").append("<legend>"+i18n('options.input')+"</legend>").append(
					options.inputOptions.map(writeInputOption)
				)
			).append(
				$("<fieldset>").append("<legend>"+i18n('options.transform')+"</legend>").append(
					['rotate.x','rotate.y','rotate.z'].map(function(name,i){
						return $("
").append(
							$("
").mousedown(function(){
								isHandle=true;
							}).mouseup(function(){
								isHandle=false;
							})
						).on('dragstart',function(ev){
							if (!isHandle) {
								return false;
							}
							isHandle=false;
							$dragged=$(this);
							ev.originalEvent.dataTransfer.effectAllowed='move'; // http://stackoverflow.com/a/8286657
							ev.originalEvent.dataTransfer.setData('Text',name);
							setTimeout(function(){
								$dragged.addClass('ghost');
							},0);
						}).on('dragover',function(ev){
							ev.preventDefault();
							ev.originalEvent.dataTransfer.dropEffect='move';
							var $target=$(this);
							if ($dragged) {
								if ($target.nextAll().is($dragged)) {
									$target.before($dragged);
								} else if ($target.prevAll().is($dragged)) {
									$target.after($dragged);
								}
							}
						}).on('dragend',function(ev){
							ev.preventDefault();
							if ($dragged) {
								$dragged.removeClass('ghost');
								$dragged=null;
							}
						}).on('drop',function(ev){
							ev.preventDefault();
						}).append(
							writeInputOption(options.transformOptions[i*2])
						).append(
							writeInputOption(options.transformOptions[i*2+1])
						);
					})
				)
			).append(
				$("<fieldset>").append("<legend>"+i18n('options.debug')+"</legend>").append(
					options.debugOptions.map(writeDebugOption)
				)
			);
		}
		function hideSuboptionInputs() {
			options.generalOptions.forEach(function(option){
				showHideSuboptionInputs(option.name,options[option.name]);
			});
		}
		function writeButtons() {
			return $("
").append(
				$("<button type='button'>Save source code</button>").click(function(){
					// yes I want a button, but download attr is only available for links
					$(this).attr('href',getHtmlDataUri(codeNode.text()));
				})
			).append(
				" "
			).append(
				$("<button type='button'>Run in new window</button>").click(function(){
					window.open(getHtmlDataUri(codeNode.text()),"generatedCode");
				})
			).append(
				" these buttons don't work in Internet Explorer, copy-paste the code manually"
			)
		}

		containerNode.empty().append(optionsNode=writeOptions());
		hideSuboptionInputs();
		containerNode.append(writeButtons()).append(
			$("
").append(codeNode=$("").text(generateCode(options.cloneWithoutHidden(),i18n)))
		);
		if (window.hljs) {
			hljs.highlightBlock(codeNode[0]);
		} else {
			containerNode.append("
"+i18n('message.hljs')+"
");
		}
		containerNode.append(writeButtons());
	});
});
<commit_msg>keyboard controls for drag handles<commit_after>var idCounter=0;
function generateId() {
	return 'webgl-starter-id-'+(idCounter++);
}

var Options=require('./options.js');
var generateCode=require('./code.js');

function getHtmlDataUri(html) {
	// with base64: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/btoa
	//return "data:text/html;charset=utf-8;base64,"+window.btoa(unescape(encodeURIComponent(str)));
	// without base64: https://en.wikipedia.org/wiki/Data_URI_scheme
	return 'data:text/html;charset=utf-8,'+encodeURIComponent(html);
}

var i18n=function(id){ // fake temporary i18n
	return {
		'message.hljs': "highlight.js (hosted on cdnjs.cloudflare.com) is not loaded. Syntax highlighting is disabled.",

		'options.general': 'General options',
		'options.background': 'Background',
		'options.background.none': 'None (transparent)',
		'options.background.solid': 'Solid color',
		'options.shader': 'Shader',
		'options.shader.single': 'Single color',
		'options.shader.vertex': 'One color per vertex',
		'options.shader.face': 'One color per face',
		'options.shape': 'Shape to draw',
		'options.shape.square': 'Square',
		'options.shape.triangle': 'Triangle',
		'options.shape.gasket': 'Sierpinski gasket', // wp: Sierpinski triangle
		'options.shape.cube': 'Cube',
		'options.projection': 'Projection',
		'options.projection.ortho': 'Orthogonal',
		'options.projection.perspective': 'Perspective',

		'options.input': 'Input options',
		'options.canvas.width': 'Canvas width',
		'options.canvas.height': 'Canvas height',
		'options.background.solid.color.r': 'Background color red component',
		'options.background.solid.color.g': 'Background color green component',
		'options.background.solid.color.b': 'Background color blue component',
		'options.background.solid.color.a': 'Background color alpha component',
		'options.shader.single.color.r': 'Fragment color red component',
		'options.shader.single.color.g': 'Fragment color green component',
		'options.shader.single.color.b': 'Fragment color blue component',
		'options.shader.single.color.a': 'Fragment color alpha component',
		'options.shape.gasket.depth': 'Sierpinski gasket recursion depth',
		'options.animation.rotation.speed': 'Z axis rotation speed',
		'options.*.input': 'This value is',
		'options.*.input.constant': 'kept constant',
		'options.*.input.slider': 'updated with a slider',
		'options.*.input.mousemovex': 'updated by moving the mouse horizontally',
		'options.*.input.mousemovey': 'updated by moving the mouse vertically',
		'options.*.input.animated': 'animated',

		'options.transform': 'Transforms',
		'options.rotate.x': 'Angle of rotation around x axis',
		'options.rotate.x.speed': 'Speed of rotation around x axis',
		'options.rotate.y': 'Angle of rotation around y axis',
		'options.rotate.y.speed': 'Speed of rotation around y axis',
		'options.rotate.z': 'Angle of rotation around z axis',
		'options.rotate.z.speed': 'Speed of rotation around z axis',

		'options.debug': 'Debug options',
		'options.debugShader': 'Log shader compilation errors',
		'options.debugInputs': 'Log input values',

		'controls.type.mousemovex': 'Move the mouse pointer horizontally over the canvas',
		'controls.type.mousemovey': 'Move the mouse pointer vertically over the canvas',
		'controls.to': 'to update',
		/*
		// TODO
		'controls.value.background.solid.color.r': 'Background color red component',
		'controls.value.background.solid.color.g': 'Background color green component',
		'controls.value.background.solid.color.b': 'Background color blue component',
		'controls.value.background.solid.color.a': 'Background color alpha component',
		'controls.value.shader.single.color.r': 'Fragment color red component',
		'controls.value.shader.single.color.g': 'Fragment color green component',
		'controls.value.shader.single.color.b': 'Fragment color blue component',
		'controls.value.shader.single.color.a': 'Fragment color alpha component',
		'controls.value.shape.gasket.depth': 'Sierpinski gasket recursion depth',
		'controls.value.animation.rotation.speed': 'Z axis rotation speed',
		*/
	}[id];
};

$(function(){
	$('.webgl-starter').each(function(){
		var containerNode=$(this);
		var optionsNode;
		var codeNode;
		var options=new Options();
		var codeUpdateTimeoutId=null;
		var codeUpdateDelay=200;

		function showHideSuboptionInputs(optionName,optionValue) {
			// TODO sub-sub option support?
			optionsNode.find("[data-option^='"+optionName+".']").show()
				.not("[data-option^='"+optionName+"."+optionValue+".']").hide();
		}
		function updateCode() {
			clearTimeout(codeUpdateTimeoutId);
			codeUpdateTimeoutId=setTimeout(function(){
				codeNode.text(generateCode(options.cloneWithoutHidden(),i18n));
				if (window.hljs) hljs.highlightBlock(codeNode[0]);
			},codeUpdateDelay);
		}
		function writeGeneralOption(option) {
			var id=generateId();
			return $("
")
				.append(""+i18n('options.'+option.name)+":")
				.append(" ")
				.append(
					$("<select id='"+id+"'>").append(
						option.availableValues.map(function(availableValue){
							return $("<option>").val(availableValue).html(i18n('options.'+option.name+'.'+availableValue))
						})
					).val(options[option.name]).change(function(){
						options[option.name]=this.value;
						showHideSuboptionInputs(option.name,this.value);
						updateCode();
					})
				);
		}
		function writeInputOption(option) {
			var id=generateId();
			var inputId=generateId();
			var sliderInput,numberInput;
			function inputListener(that) {
				if (this.checkValidity()) {
					that.val(this.value);
					options[option.name]=parseFloat(this.value);
					updateCode();
				}
			}
			return $("
")
				.append(""+i18n('options.'+option.name)+":")
				.append(" "+option.getMinLabel()+" ")
				.append(
					sliderInput=$("<input type='range' id='"+id+"'>")
						.attr('min',option.getMin())
						.attr('max',option.getMax())
						.attr('step',option.getSetupStep())
						.val(options[option.name])
						.on('input change',function(){
							inputListener.call(this,numberInput);
						})
				)
				.append(" "+option.getMaxLabel()+" ")
				.append(
					numberInput=$("<input type='number' required>")
						.attr('min',option.getMin())
						.attr('max',option.getMax())
						.attr('step',option.getSetupStep())
						.val(options[option.name])
						.on('input change',function(){
							inputListener.call(this,sliderInput);
						})
				)
				.append(" ")
				.append(
					$("<button type='button'>Reset</button>").click(function(){
						sliderInput.val(option.defaultValue).change();
					})
				)
				.append(" ")
				.append(""+i18n('options.*.input')+" ")
				.append(
					$("<select id='"+inputId+"'>").append(
						option.availableInputTypes.map(function(availableInputType){
							return $("<option>").val(availableInputType).html(i18n('options.*.input.'+availableInputType))
						})
					).val(options[option.name+'.input']).change(function(){
						options[option.name+'.input']=this.value;
						updateCode();
					})
				);
		}
		function writeDebugOption(option) {
			var id=generateId();
			return $("
")
				.append(
					$("<input type='checkbox' id='"+id+"'>")
						.prop('checked',options[option.name])
						.change(function(){
							options[option.name]=$(this).prop('checked');
							updateCode();
						})
				)
				.append(" "+i18n('options.'+option.name)+"");
		}
		function writeOptions() {
			var $dragged=null;
			var isHandle=false; // https://github.com/farhadi/html5sortable/blob/master/jquery.sortable.js
			return $("
").append(
				$("<fieldset>").append("<legend>"+i18n('options.general')+"</legend>").append(
					options.generalOptions.map(writeGeneralOption)
				)
			).append(
				$("<fieldset>").append("<legend>"+i18n('options.input')+"</legend>").append(
					options.inputOptions.map(writeInputOption)
				)
			).append(
				$("<fieldset>").append("<legend>"+i18n('options.transform')+"</legend>").append(
					$("
").append(
						['rotate.x','rotate.y','rotate.z'].map(function(name,i){
							return $("
").append(
								$("
").mousedown(function(){
									isHandle=true;
								}).mouseup(function(){
									isHandle=false;
								}).keydown(function(ev){
									var $handle=$(this);
									var $sorted=$handle.closest('[draggable]');
									if (ev.keyCode==38) {
										$sorted.prev().before($sorted);
										$handle.focus();
										return false;
									} else if (ev.keyCode==40) {
										$sorted.next().after($sorted);
										$handle.focus();
										return false;
									}
								})
							).on('dragstart',function(ev){
								if (!isHandle) {
									return false;
								}
								isHandle=false;
								$dragged=$(this);
								ev.originalEvent.dataTransfer.effectAllowed='move'; // http://stackoverflow.com/a/8286657
								ev.originalEvent.dataTransfer.setData('Text',name);
								setTimeout(function(){
									$dragged.addClass('ghost');
								},0);
							}).on('dragover',function(ev){
								ev.preventDefault();
								ev.originalEvent.dataTransfer.dropEffect='move';
								var $target=$(this);
								if ($dragged) {
									if ($target.nextAll().is($dragged)) {
										$target.before($dragged);
									} else if ($target.prevAll().is($dragged)) {
										$target.after($dragged);
									}
								}
							}).on('dragend',function(ev){
								ev.preventDefault();
								if ($dragged) {
									$dragged.removeClass('ghost');
									$dragged=null;
								}
							}).on('drop',function(ev){
								ev.preventDefault();
							}).append(
								writeInputOption(options.transformOptions[i*2])
							).append(
								writeInputOption(options.transformOptions[i*2+1])
							);
						})
					)
				)
			).append(
				$("<fieldset>").append("<legend>"+i18n('options.debug')+"</legend>").append(
					options.debugOptions.map(writeDebugOption)
				)
			);
		}
		function hideSuboptionInputs() {
			options.generalOptions.forEach(function(option){
				showHideSuboptionInputs(option.name,options[option.name]);
			});
		}
		function writeButtons() {
			return $("
").append(
				$("<button type='button'>Save source code</button>").click(function(){
					// yes I want a button, but download attr is only available for links
					$(this).attr('href',getHtmlDataUri(codeNode.text()));
				})
			).append(
				" "
			).append(
				$("<button type='button'>Run in new window</button>").click(function(){
					window.open(getHtmlDataUri(codeNode.text()),"generatedCode");
				})
			).append(
				" these buttons don't work in Internet Explorer, copy-paste the code manually"
			)
		}

		containerNode.empty().append(optionsNode=writeOptions());
		hideSuboptionInputs();
		containerNode.append(writeButtons()).append(
			$("
").append(codeNode=$("").text(generateCode(options.cloneWithoutHidden(),i18n)))
		);
		if (window.hljs) {
			hljs.highlightBlock(codeNode[0]);
		} else {
			containerNode.append("
"+i18n('message.hljs')+"
");
		}
		containerNode.append(writeButtons());
	});
});
<|endoftext|>


<commit_before>import './polyfills';
import 'material-design-lite/material';
import '../styles/styles.scss';

import type {Aurelia} from 'aurelia-framework';

export async function configure(aurelia: Aurelia) {
  aurelia.use
    .standardConfiguration()
    .plugin('aurelia-mdl-plugin');

  if (process.env.NODE_ENV !== 'production') {
    aurelia.use.developmentLogging();
  }

  // Uncomment the line below to enable animation.
  // aurelia.use.plugin('aurelia-animator-css');
  // if the css animator is enabled, add swap-order="after" to all router-view elements

  // Anyone wanting to use HTMLImports to load views, will need to install the following plugin.
  // aurelia.use.plugin('aurelia-html-import-template-loader')

  // Conditionally Load in fetch polyfill
  if (!self.fetch) {
    await System.import('whatwg-fetch');
  }

  await aurelia.start();
  aurelia.setRoot();

  // if you would like your website to work offline (Service Worker),
  // install and enable the @easy-webpack/config-offline package in webpack.config.js and uncomment the following code:
  /*
  const offline = await System.import('offline-plugin/runtime');
  offline.install();
  */
}
<commit_msg>Use import() statement<commit_after>import './polyfills';
import 'material-design-lite/material';
import '../styles/styles.scss';

import type {Aurelia} from 'aurelia-framework';

export async function configure(aurelia: Aurelia) {
  aurelia.use
    .standardConfiguration()
    .plugin('aurelia-mdl-plugin');

  if (process.env.NODE_ENV !== 'production') {
    aurelia.use.developmentLogging();
  }

  // Uncomment the line below to enable animation.
  // aurelia.use.plugin('aurelia-animator-css');
  // if the css animator is enabled, add swap-order="after" to all router-view elements

  // Conditionally Load in fetch polyfill
  if (!self.fetch) {
    await System.import('whatwg-fetch');
    // Idea fails at parsing new import() statement.
    // await import('whatwg-fetch');
  }

  await aurelia.start();
  aurelia.setRoot();

  // if you would like your website to work offline (Service Worker),
  // install and enable the @easy-webpack/config-offline package in webpack.config.js and uncomment the following code:
  /*
  const offline = await import('offline-plugin/runtime');
  offline.install();
  */
}
<|endoftext|>


<commit_before>var fs = require('fs');

/* varible contain all watched file names
 * {name: true}
 */
var FileNames           = {},
    NamesList_s         = '';

/* function thet use for crossplatform
 * access to fs.watch or fs.watchFile function
 */
var fs_watch            = null;
var on_fs_watch         = null;
var firstFileRead_b     = true;
var Manifest = '';

setWatachFunctions();

exports.createManifest = function(){
    var lAllNames = cloudRequire(process.cwd() + '/hashes');
    if(lAllNames)
        for(var lName in lAllNames){
            if(lName.indexOf('min') > 0)
                lName = './min/' + lName;
            exports.watch(lName);
        }
    processManifest();
};

exports.watch = function(pFileName){
    console.log(pFileName + ' is watched');

    if(!FileNames[pFileName] &&
        pFileName !== './cloudcmd.appcache'){
        try{
            fs_watch(pFileName, on_fs_watch(pFileName));
        }catch(pError){}

        NamesList_s += pFileName + '\n';
        FileNames[pFileName] = true;
    }
    else if(firstFileRead_b){
        processManifest();
        firstFileRead_b = false;
    }
};

function setWatachFunctions(){
    if(process.platform === 'win32'){
        /* good on windows  */
        fs_watch    = fs.watch;
        on_fs_watch = onWatch;
    }
    else{
        /* good on linux    */
        fs_watch    = fs.watchFile;
        on_fs_watch = onWatchFile;
    }

}

function onWatch (pFileName){
    return function(pEvent, pFileName){
        console.log(pEvent);
        console.log('file ' + pFileName + ' is changed');

    };
}

function onWatchFile(pFileName){
    return function(pCurr, pPrev){
        console.log(pCurr);
        if(pCurr.mtime !== pPrev.mtime)
            console.log('file ' + pFileName + ' is changed');
    };
}

function processManifest(){
    Manifest = 'CACHE MANIFEST\n'   +
        '#' + new Date()   + '\n'   +
        'CACHE:\n'                  +
        NamesList_s                 +
        'NETWORK:\n'                +
        '*';

    console.log(Manifest);
        fs.writeFile('cloudcmd.appcache', Manifest, function(){
            console.log('cloudcmd.appcache refreshed');
        });
}

/* function do safe require of needed module */
function cloudRequire(pModule){
  try{
      return require(pModule);
  }
  catch(pError){
      return false;
  }
}<commit_msg>minor changes<commit_after>var fs = require('fs');

/* varible contain all watched file names
 * {name: true}
 */
var FileNames           = {},
    NamesList_s         = '';

/* function thet use for crossplatform
 * access to fs.watch or fs.watchFile function
 */
var fs_watch            = null;
var on_fs_watch         = null;
var firstFileRead_b     = true;
var Manifest = '';

setWatachFunctions();

exports.createManifest = function(){
    var lAllNames = cloudRequire(process.cwd() + '/hashes');
    if(lAllNames)
        for(var lName in lAllNames){
            if(lName.indexOf('min') > 0)
                lName = './min/' + lName;
            exports.watch(lName);
        }
    processManifest();
};

exports.watch = function(pFileName){
    console.log(pFileName + ' is watched');

    if(!FileNames[pFileName] &&
        pFileName !== './cloudcmd.appcache'){
        try{
            fs_watch(pFileName, on_fs_watch(pFileName));
        }catch(pError){}

        NamesList_s += pFileName + '\n';
        FileNames[pFileName] = true;
    }
    else if(firstFileRead_b){
        processManifest();
        firstFileRead_b = false;
    }
};

function setWatachFunctions(){
    if(process.platform === 'win32'){
        /* good on windows  */
        fs_watch    = fs.watch;
        on_fs_watch = onWatch;
    }
    else{
        /* good on linux    */
        fs_watch    = fs.watchFile;
        on_fs_watch = onWatchFile;
    }

}

function onWatch (pFileName){
    return function(pEvent, pFileName){
        console.log(pEvent);
        console.log('file ' + pFileName + ' is changed');
        processManifest();
    };
}

function onWatchFile(pFileName){
    return function(pCurr, pPrev){
        console.log(pCurr);
        if(pCurr.mtime !== pPrev.mtime){
            console.log('file ' + pFileName + ' is changed');
            processManifest();
        }
    };
}

function processManifest(){
    Manifest = 'CACHE MANIFEST\n'   +
        '#' + new Date()   + '\n'   +
        'CACHE:\n'                  +
        NamesList_s                 +
        'NETWORK:\n'                +
        '*';

    console.log(Manifest);
        fs.writeFile('cloudcmd.appcache', Manifest, function(){
            console.log('cloudcmd.appcache refreshed');
        });
}

/* function do safe require of needed module */
function cloudRequire(pModule){
  try{
      return require(pModule);
  }
  catch(pError){
      return false;
  }
}<|endoftext|>