<commit_before>import Vue       from 'vue'
import VueRouter from 'vue-router'
import VueMoment from 'vue-moment'
import Promise   from 'bluebird'

import Storage                   from './localstorage'
import connectSocket             from './socketio/connect'
import { setAuthorizationToken } from './api'

import App      from './views/App'
import Channel  from './views/Channel'
import Channels from './views/Channels'
import Login    from './views/Login'
import Register from './views/Register'

Vue.use(VueRouter)
Vue.use(VueMoment)

const routes = [
  { path: '/login', name: 'login', component: Login, meta: { title: 'Login' } },
  { path: '/register', name: 'register', component: Register, meta: { title: 'Register an account' } },
  { path: '/channels', name: 'channels', component: Channels, meta: { title: 'Channels' } },
  { path: '/channel/:id', name: 'channel', component: Channel, meta: { title: 'Channel' } }
]

const router = new VueRouter({
  routes
})

// Redirect to login if socket not connected
router.beforeEach((to, from, next) => {
  document.title = to.meta.title
  const isConnected = (window._socket && window._socket.connected)
  const goingToNonAuthView = (to.fullPath === '/login' || to.fullPath === '/register')

  if (goingToNonAuthView) {
    return next()
  }

  if (!isConnected) {
    return next('login')
  }

  next()
})

const possibleToken = Storage.getTokenIfValid()

if (possibleToken) {
  setAuthorizationToken(possibleToken)
}

const socketConnectPromise = (typeof possibleToken === 'undefined') ? Promise.resolve : connectSocket

socketConnectPromise(possibleToken)
.finally(() => {
  /* eslint-disable no-new */
  new Vue({
    router,
    render: h => h(App)
  }).$mount('#app')
})
<commit_msg>Fix redirect when connected and going to invalid route<commit_after>import Vue       from 'vue'
import VueRouter from 'vue-router'
import VueMoment from 'vue-moment'
import Promise   from 'bluebird'

import Storage                   from './localstorage'
import connectSocket             from './socketio/connect'
import { setAuthorizationToken } from './api'

import App      from './views/App'
import Channel  from './views/Channel'
import Channels from './views/Channels'
import Login    from './views/Login'
import Register from './views/Register'

Vue.use(VueRouter)
Vue.use(VueMoment)

const routes = [
  { path: '/login', name: 'login', component: Login, meta: { title: 'Login' } },
  { path: '/register', name: 'register', component: Register, meta: { title: 'Register an account' } },
  { path: '/channels', name: 'channels', component: Channels, meta: { title: 'Channels' } },
  { path: '/channel/:id', name: 'channel', component: Channel, meta: { title: 'Channel' } }
]

const router = new VueRouter({
  routes
})

// Redirect to login if socket not connected
router.beforeEach((to, from, next) => {
  document.title = to.meta.title

  const matchesAnyRoute = (router.match(to.fullPath).matched.length > 0)
  const isConnected = (window._socket && window._socket.connected)
  const goingToNonAuthView = (to.fullPath === '/login' || to.fullPath === '/register')

  if (goingToNonAuthView) {
    return next()
  }

  if (!isConnected) {
    return next('login')
  }

  if (isConnected && !matchesAnyRoute) {
    return next('channels')
  }

  next()
})

const possibleToken = Storage.getTokenIfValid()

if (possibleToken) {
  setAuthorizationToken(possibleToken)
}

const socketConnectPromise = (typeof possibleToken === 'undefined') ? Promise.resolve : connectSocket

socketConnectPromise(possibleToken)
.finally(() => {
  /* eslint-disable no-new */
  new Vue({
    router,
    render: h => h(App)
  }).$mount('#app')
})
<|endoftext|>


<commit_before>import "babel-polyfill"
// dom
var $grid = document.getElementById("grid")
var $play = document.getElementById("play")
var $step = document.getElementById("step")
var $park = document.getElementById("park")
var $slider = document.getElementById("slider")
var $colors = document.getElementById("colors")
var $storage = document.getElementById("storage")
var $load = document.getElementById("load")
var $save = document.getElementById("save")
var $clear = document.getElementById("clear")

document.addEventListener("DOMContentLoaded", () => {
    // hydrate state
    var savedData = window.localStorage.getItem(localStorageKey)
    if (savedData) {
        $storage.value = savedData
        load(savedData)
    }

    $grid.addEventListener("mousedown", (e) => {
        dispatch({
            type: DRAW,
            payload: {
                x: Math.floor(e.offsetX / resolution),
                y: Math.floor(e.offsetY / resolution),
            },
        })
    })

    $play.addEventListener("click", () => {
        dispatch({type: PLAY})
    })

    $step.addEventListener("click", () => {
        dispatch({type: STEP})
    })

    $park.addEventListener("click", () => {
        dispatch({type: PARK})
    })

    $slider.addEventListener("input", (e) => {
        dispatch({
            type: SEEK,
            payload: Number(e.target.value),
        })
    })

    $colors.addEventListener("change", (e) => {
        dispatch({
            type: SET_COLOR,
            payload: e.target.value,
        })
    })

    $load.addEventListener("click", (e) => {
        load($storage.value)
    })

    $save.addEventListener("click", (e) => {
        var stateJSON = JSON.stringify(_state.pixels)
        window.localStorage.setItem(localStorageKey, stateJSON)
        $storage.value = stateJSON
    })

    $clear.addEventListener("click", (e) => {
        window.localStorage.removeItem(localStorageKey)
        $storage.value = ""
        dispatch({type: RESET})
    })
})

// action creators
function load (text) {
    if (!text) {
        dispatch({type: RESET})
    }
    try {
        var state = JSON.parse(text)
        dispatch({type: LOAD, payload: state})
    } catch (e) {
        window.alert("Invalid saved state.")
    }
}

// constants
var ttl = 32
var width = 32
var height = 32
var maxSteps = 64
var resolution = 12 // CSS px per grid px
var localStorageKey = "pixquisite-v1"
var frameRateMs = 1000 / 12

// actions
var TICK = "TICK"
var PLAY = "PLAY"
var STEP = "STEP"
var PARK = "PARK"
var DRAW = "DRAW"
var SEEK = "SEEK"
var SET_COLOR = "SET_COLOR"
var LOAD = "LOAD"
var RESET = "RESET"

// state
var initState = {
    step: 0,
  // stored as `${x}-${y}`: { x, y, step }
    pixels: {},
    mode: STEP,
    color: "black",
}
var _state = initState

var actionLog = []

function reducer (state, action) {
    switch (action.type) {
    case TICK:
        return {...state, step: nextStep(state.step)}
    case PLAY:
    case STEP:
    case PARK:
        return state.mode === action.type
            ? state
            : { ...state, mode: action.type }
    case DRAW:
        return {
            ...state,
            pixels: {...state.pixels, ...nextPixel(state, action.payload)},
            step: state.mode === STEP
                ? nextStep(state.step)
                : state.step,
        }
    case SEEK:
        return {
            ...state,
            step: action.payload,
            mode: state.mode === PLAY ? STEP : state.mode,
        }
    case SET_COLOR:
        return { ...state, color: action.payload }
    case LOAD:
        return { ...initState, pixels: action.payload }
    case RESET:
        return initState
    }
    return state
}

// render
var ctx = $grid.getContext("2d")

function render (state) {
    ctx.clearRect(0, 0, width * resolution, height * resolution)
    for (var key in state.pixels) {
        let px = state.pixels[key]
        if (px.step <= state.step && // made before current step
            px.step + ttl > state.step) { // not older than ttl
            ctx.fillStyle = px.color
            ctx.fillRect(
                1 + px.x * resolution, 1 + px.y * resolution,
                resolution - 2, resolution - 2)
        }
    }
    $slider.value = state.step
    if (state.mode === PLAY) {
        window.setTimeout(nextTick, frameRateMs)
    }
}

function nextTick () { dispatch({ type: TICK }) }

function dispatch (action) {
    actionLog.push(action)
    var nextState = reducer(_state, action)
    // console.log(nextState,actionLog)
    if (nextState === _state) { return }
    render(nextState)
    _state = nextState
}

// helpers
function nextStep (step) {
    return (step + 1) % maxSteps
}

function nextPixel (state, pixel) {
    return {
        [`${pixel.x}-${pixel.y}`]: {
            ...pixel,
            color: state.color,
            step: state.step,
        },
    }
}
<commit_msg>fix tick acceleration<commit_after>import "babel-polyfill"
// dom
var $grid = document.getElementById("grid")
var $play = document.getElementById("play")
var $step = document.getElementById("step")
var $park = document.getElementById("park")
var $slider = document.getElementById("slider")
var $colors = document.getElementById("colors")
var $storage = document.getElementById("storage")
var $load = document.getElementById("load")
var $save = document.getElementById("save")
var $clear = document.getElementById("clear")

document.addEventListener("DOMContentLoaded", () => {
    // hydrate state
    var savedData = window.localStorage.getItem(localStorageKey)
    if (savedData) {
        $storage.value = savedData
        load(savedData)
    }

    $grid.addEventListener("mousedown", (e) => {
        dispatch({
            type: DRAW,
            payload: {
                x: Math.floor(e.offsetX / resolution),
                y: Math.floor(e.offsetY / resolution),
            },
        })
    })

    $play.addEventListener("click", () => {
        dispatch({type: PLAY})
        tick()
    })

    $step.addEventListener("click", () => {
        dispatch({type: STEP})
    })

    $park.addEventListener("click", () => {
        dispatch({type: PARK})
    })

    $slider.addEventListener("input", (e) => {
        dispatch({
            type: SEEK,
            payload: Number(e.target.value),
        })
    })

    $colors.addEventListener("change", (e) => {
        dispatch({
            type: SET_COLOR,
            payload: e.target.value,
        })
    })

    $load.addEventListener("click", (e) => {
        load($storage.value)
    })

    $save.addEventListener("click", (e) => {
        var stateJSON = JSON.stringify(_state.pixels)
        window.localStorage.setItem(localStorageKey, stateJSON)
        $storage.value = stateJSON
    })

    $clear.addEventListener("click", (e) => {
        window.localStorage.removeItem(localStorageKey)
        $storage.value = ""
        dispatch({type: RESET})
    })
})

// action creators
function load (text) {
    if (!text) {
        dispatch({type: RESET})
    }
    try {
        var state = JSON.parse(text)
        dispatch({type: LOAD, payload: state})
    } catch (e) {
        window.alert("Invalid saved state.")
    }
}

function tick () {
    if (_state.mode === PLAY) {
        dispatch({ type: TICK })
        window.setTimeout(tick, frameRateMs)
    }
}

// constants
var ttl = 32
var width = 32
var height = 32
var maxSteps = 64
var resolution = 12 // CSS px per grid px
var localStorageKey = "pixquisite-v1"
var frameRateMs = 1000 / 12

// actions
var TICK = "TICK"
var PLAY = "PLAY"
var STEP = "STEP"
var PARK = "PARK"
var DRAW = "DRAW"
var SEEK = "SEEK"
var SET_COLOR = "SET_COLOR"
var LOAD = "LOAD"
var RESET = "RESET"

// state
var initState = {
    step: 0,
  // stored as `${x}-${y}`: { x, y, step }
    pixels: {},
    mode: STEP,
    color: "black",
}
var _state = initState

var actionLog = []

function reducer (state, action) {
    switch (action.type) {
    case TICK:
        return {...state, step: nextStep(state.step)}
    case PLAY:
    case STEP:
    case PARK:
        return state.mode === action.type
            ? state
            : { ...state, mode: action.type }
    case DRAW:
        return {
            ...state,
            pixels: {...state.pixels, ...nextPixel(state, action.payload)},
            step: state.mode === STEP
                ? nextStep(state.step)
                : state.step,
        }
    case SEEK:
        return {
            ...state,
            step: action.payload,
            mode: state.mode === PLAY ? STEP : state.mode,
        }
    case SET_COLOR:
        return { ...state, color: action.payload }
    case LOAD:
        return { ...initState, pixels: action.payload }
    case RESET:
        return initState
    }
    return state
}

// render
var ctx = $grid.getContext("2d")

function render (state) {
    ctx.clearRect(0, 0, width * resolution, height * resolution)
    for (var key in state.pixels) {
        let px = state.pixels[key]
        if (px.step <= state.step && // made before current step
            px.step + ttl > state.step) { // not older than ttl
            ctx.fillStyle = px.color
            ctx.fillRect(
                1 + px.x * resolution, 1 + px.y * resolution,
                resolution - 2, resolution - 2)
        }
    }
    $slider.value = state.step
}

function dispatch (action) {
    actionLog.push(action)
    var nextState = reducer(_state, action)
    // console.log(nextState,actionLog)
    if (nextState === _state) { return }
    render(nextState)
    _state = nextState
}

// helpers
function nextStep (step) {
    return (step + 1) % maxSteps
}

function nextPixel (state, pixel) {
    return {
        [`${pixel.x}-${pixel.y}`]: {
            ...pixel,
            color: state.color,
            step: state.step,
        },
    }
}
<|endoftext|>


<commit_before>// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import axios from 'axios'
import VueAxios from 'vue-axios'
import moment from 'moment'
// import VueAnalytics from 'vue-analytics'
// import uaid from './utils/uaid'

Vue.use(VueAxios, axios, moment)

// Vue.config.productionTip = true

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App }
})

// Vue.use(VueAnalytics, {
//   id: uaid,
//   router,
//   debug: {
//     enabled: false,
//     trace: false,
//     sendHitTask: true
//   }
// })

<commit_msg>branch to refactor<commit_after>// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import axios from 'axios'
import VueAxios from 'vue-axios'
import moment from 'moment'
// import VueAnalytics from 'vue-analytics'
// import uaid from './utils/uaid'

// console.log('FBEvents\ncurrent_item[k].place cannot be found\n' + util.inspect(current_item[k], false, null) + '\n');

Vue.use(VueAxios, axios, moment)

// Vue.config.productionTip = true

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App }
})

// Vue.use(VueAnalytics, {
//   id: uaid,
//   router,
//   debug: {
//     enabled: false,
//     trace: false,
//     sendHitTask: true
//   }
// })

<|endoftext|>


<commit_before>'use strict';

const electron = require('electron');
// Module to control application life.
const app = electron.app;
const Menu = electron.Menu;
var menuTemplate = require('./menuTemplate');
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;

require('electron-reload')(__dirname.replace('src', 'build'));

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow, menu;

function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600});

  // and load the index.html of the app.
  mainWindow.loadURL('file://' + __dirname + '/index.html');

  // Open the DevTools.
  // mainWindow.webContents.openDevTools();

  // Emitted when the window is closed.
  mainWindow.on('closed', function() {
    menu.items[1].submenu.items[0].enabled = false;
    menu.items[1].submenu.items[1].enabled = false;
    menu.items[3].submenu.items[0].enabled = true;

    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });

  if (!menu) setMenu();

  setDock();

  menu.items[1].submenu.items[0].enabled = true;
  menu.items[1].submenu.items[1].enabled = true;
  menu.items[3].submenu.items[0].enabled = false;
}

function setMenu() {
  menuTemplate[1].submenu[0].click = function () {
    mainWindow.webContents.send('open-file');
  }

  menuTemplate[1].submenu[1].click = function () {
    mainWindow.webContents.send('save-file');
  }

  menuTemplate[3].submenu[0].click = function() {
    if (!mainWindow)
      createWindow();
  }

  menu = Menu.buildFromTemplate(menuTemplate);
  Menu.setApplicationMenu(menu);
}

function setDock() {
  var dockMenu = Menu.buildFromTemplate([
    { label: 'New Window', click:  menu.items[3].submenu.items[0].click }
  ]);
  app.dock.setMenu(dockMenu);
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
app.on('ready', createWindow);

// 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
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', function () {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow();
  }
});
<commit_msg>improve app menu code + es6-ify main.js<commit_after>'use strict';

const electron = require('electron');
// Module to control application life.
const app = electron.app;
const Menu = electron.Menu;
let menuTemplate = require('./menuTemplate');
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;

// Allows for live-reload while developing the app
require('electron-reload')(__dirname.replace('src', 'build'));

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow, menu, dockMenu;

let createWindow = () => {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600});

  // and load the index.html of the app.
  mainWindow.loadURL('file://' + __dirname + '/index.html');

  // Open the DevTools.
  // mainWindow.webContents.openDevTools();

  // Emitted when the window is closed.
  mainWindow.on('closed', () => {
    toggleFileTasks(false);
    toggleNewWindowTask(true);

    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });

  if (!menu) setMenu();
  if (!dockMenu) setDock();

  toggleFileTasks(true);
  toggleNewWindowTask(false);
}

let toggleFileTasks = isEnabled => {
  // The 'File' menu should only be available if there is an open window
  menu.items
    .find(item => item.label === 'File')
    .submenu.items
    .forEach(subItem => subItem.enabled = isEnabled);
}

let toggleNewWindowTask = isEnabled => {
  // The 'New Window' task in the main menu and dock menu
  // should only be available if there are no open windows
  let newWindowMenu = menu.items
    .find(item => item.label === 'Window')
    .submenu.items
    .find(subItem => subItem.label === 'New');

  let dockWindowMenu = dockMenu.items
    .find(item => item.label === 'New Window');

  newWindowMenu.enabled = isEnabled;
  dockWindowMenu.enabled = isEnabled;
}

let setMenu = () => {
  // Set custom click handlers for menu tasks
  let fileMenu = menuTemplate
    .find(item => item.label === 'File');

  fileMenu.submenu
    .find(item => item.label === 'Open')
    .click = () => mainWindow.webContents.send('open-file')

  fileMenu.submenu
    .find(item => item.label === 'Save As...')
    .click = () => mainWindow.webContents.send('save-file')

  menuTemplate
    .find(item => item.label === 'Window')
    .submenu
    .find(subItem => subItem.label === 'New')
    .click = () => createWindow()

  menu = Menu.buildFromTemplate(menuTemplate);
  Menu.setApplicationMenu(menu);
}

let setDock = () => {
  // Create a 'New Window' task in the dock menu (OSX only)
  dockMenu = Menu.buildFromTemplate([
    { label: 'New Window', click: createWindow }
  ]);
  app.dock.setMenu(dockMenu);
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
app.on('ready', createWindow);

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

app.on('activate', () => {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) createWindow();
});
<|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';

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

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

// 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) {
  return word;

  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 (lineCount === (line === 1 ? 7 : 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 {
        lineAdjustment = adjustment > maxLineAdjustment ? maxLineAdjustment : adjustment;
        lineAdjustment -= lineCount;
      }

      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>dread-bolted car hat // paper-faced automobile // warped beslubbering<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';

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

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

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);
  }
}

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) {
  return word;

  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 (lineCount === (line === 1 ? 7 : 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 {
        lineAdjustment = adjustment > maxLineAdjustment ? maxLineAdjustment : adjustment;
        lineAdjustment -= lineCount;
      }

      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;
};

 export function makeHaiku(msg) {
  let syllables = countSyllables(msg);
  let difference = HAIKU_LENGTH - syllables;

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


<commit_before>window.addEventListener('load', main);

function initialWorld(width, height) {
    var sheet = new SpriteSheet(document.getElementById('pasi'), 4);
    var world = {
        keys: {left: false, right: false},
        gamma: 0,

        width: width,
        height: height,
        g: 1,

        pasiSheet: sheet,

        cameraRatio: 0.3,

    };

    restart(world);
    return world;
}

function restart(world) {
    world.pasi = new Pasi({
        spriteSheet: world.pasiSheet,
        x: world.width / 2,
        y: 0,
        nLeapTicks: 3,
        speed: 4,
        jumpSpeed: 13,
        tiltFactor: 0.6
    });
    // Give Pasi an initial kick.
    world.pasi.vy = -world.pasi.jumpSpeed;
    world.yCamera = 0;
    world.platformGenerator = new PlatformGenerator(world.width,
        world.width / 2, -2);
}

function calculateGameDimensions(preferredHeight, minAspect, maxAspect) {
    var vwWidth = window.innerWidth,
        vwHeight = window.innerHeight;

    var scale = Math.max(Math.floor(vwHeight / preferredHeight), 1),
        actualHeight = Math.floor(vwHeight / scale);

    var minWidth = Math.round(actualHeight * minAspect),
        maxWidth = Math.round(actualHeight * maxAspect),
        actualWidth = Math.min(Math.max(Math.floor(vwWidth / scale),
            minWidth), maxWidth);

    return {width: actualWidth, height: actualHeight};
}

function main() {
    var dimensions = calculateGameDimensions(320, 9/16, 3/4);
    console.log(dimensions.width);
    console.log(dimensions.height);
    var config = {
        width: dimensions.width,
        height: dimensions.height,
        fps: 20
    };

    var initWorld = initialWorld(config.width, config.height);

    startGame(document.getElementById('mainCanvas'), config, draw, update,
        [
            { name: 'keydown', fn: keydown },
            { name: 'keyup', fn: keyup },
            { name: 'deviceorientation', fn: orientation },
            { name: 'click', fn: click }
        ], [], initWorld);
}

function draw(ctx, world) {
    ctx.clearRect(0, 0, world.width, world.height);

    ctx.save();
    ctx.translate(0, world.height - world.yCamera);

    world.platformGenerator.platforms.forEach(function(platform) {
        platform.draw(ctx);
    });

    world.pasi.draw(ctx);

    ctx.restore();
}

function update(world) {
    if (world.keys.right) {
        world.pasi.vx = world.pasi.speed;
    } else if (world.keys.left) {
        world.pasi.vx = -world.pasi.speed;
    } else {
        world.pasi.vx = world.pasi.tiltFactor * world.gamma;
    }
    world.pasi.vy += world.g;

    world.pasi.update(world.g);
    world.pasi.wrap(world.width);

    if (world.yCamera - world.pasi.y > world.cameraRatio * world.height) {
        world.yCamera = world.pasi.y + world.cameraRatio * world.height;
    }

    world.platformGenerator.generatePlatforms(world.yCamera,
        world.yCamera - world.height);

    var collidingPlatform =
        world.pasi.getCollidingPlatform(world.platformGenerator.platforms);
    if (collidingPlatform !== null) {
        world.pasi.y = collidingPlatform.y;
        world.pasi.leap();
    }
}

function keydown(e, world) {
    if (e.keyCode === 39) {
        world.keys.right = true;
    } else if (e.keyCode === 37) {
        world.keys.left = true;
    }
}

// Return, space
var restartKeys = [13, 32];
function keyup(e, world) {
    if (e.keyCode === 39) {
        world.keys.right = false;
    } else if (e.keyCode === 37) {
        world.keys.left = false;
    } else if (restartKeys.indexOf(e.keyCode) !== -1) {
        restart(world);
    }
}

function orientation(e, world) {
    world.gamma = e.gamma;
}

function click(e, world) {
    restart(world);
}

<commit_msg>Remove console.logs.<commit_after>window.addEventListener('load', main);

function initialWorld(width, height) {
    var sheet = new SpriteSheet(document.getElementById('pasi'), 4);
    var world = {
        keys: {left: false, right: false},
        gamma: 0,

        width: width,
        height: height,
        g: 1,

        pasiSheet: sheet,

        cameraRatio: 0.3,

    };

    restart(world);
    return world;
}

function restart(world) {
    world.pasi = new Pasi({
        spriteSheet: world.pasiSheet,
        x: world.width / 2,
        y: 0,
        nLeapTicks: 3,
        speed: 4,
        jumpSpeed: 13,
        tiltFactor: 0.6
    });
    // Give Pasi an initial kick.
    world.pasi.vy = -world.pasi.jumpSpeed;
    world.yCamera = 0;
    world.platformGenerator = new PlatformGenerator(world.width,
        world.width / 2, -2);
}

function calculateGameDimensions(preferredHeight, minAspect, maxAspect) {
    var vwWidth = window.innerWidth,
        vwHeight = window.innerHeight;

    var scale = Math.max(Math.floor(vwHeight / preferredHeight), 1),
        actualHeight = Math.floor(vwHeight / scale);

    var minWidth = Math.round(actualHeight * minAspect),
        maxWidth = Math.round(actualHeight * maxAspect),
        actualWidth = Math.min(Math.max(Math.floor(vwWidth / scale),
            minWidth), maxWidth);

    return {width: actualWidth, height: actualHeight};
}

function main() {
    var dimensions = calculateGameDimensions(320, 9/16, 3/4);
    var config = {
        width: dimensions.width,
        height: dimensions.height,
        fps: 20
    };

    var initWorld = initialWorld(config.width, config.height);

    startGame(document.getElementById('mainCanvas'), config, draw, update,
        [
            { name: 'keydown', fn: keydown },
            { name: 'keyup', fn: keyup },
            { name: 'deviceorientation', fn: orientation },
            { name: 'click', fn: click }
        ], [], initWorld);
}

function draw(ctx, world) {
    ctx.clearRect(0, 0, world.width, world.height);

    ctx.save();
    ctx.translate(0, world.height - world.yCamera);

    world.platformGenerator.platforms.forEach(function(platform) {
        platform.draw(ctx);
    });

    world.pasi.draw(ctx);

    ctx.restore();
}

function update(world) {
    if (world.keys.right) {
        world.pasi.vx = world.pasi.speed;
    } else if (world.keys.left) {
        world.pasi.vx = -world.pasi.speed;
    } else {
        world.pasi.vx = world.pasi.tiltFactor * world.gamma;
    }
    world.pasi.vy += world.g;

    world.pasi.update(world.g);
    world.pasi.wrap(world.width);

    if (world.yCamera - world.pasi.y > world.cameraRatio * world.height) {
        world.yCamera = world.pasi.y + world.cameraRatio * world.height;
    }

    world.platformGenerator.generatePlatforms(world.yCamera,
        world.yCamera - world.height);

    var collidingPlatform =
        world.pasi.getCollidingPlatform(world.platformGenerator.platforms);
    if (collidingPlatform !== null) {
        world.pasi.y = collidingPlatform.y;
        world.pasi.leap();
    }
}

function keydown(e, world) {
    if (e.keyCode === 39) {
        world.keys.right = true;
    } else if (e.keyCode === 37) {
        world.keys.left = true;
    }
}

// Return, space
var restartKeys = [13, 32];
function keyup(e, world) {
    if (e.keyCode === 39) {
        world.keys.right = false;
    } else if (e.keyCode === 37) {
        world.keys.left = false;
    } else if (restartKeys.indexOf(e.keyCode) !== -1) {
        restart(world);
    }
}

function orientation(e, world) {
    world.gamma = e.gamma;
}

function click(e, world) {
    restart(world);
}

<|endoftext|>


<commit_before>window.onload = init;

function init () {
  // check for URL query parameters
  if (window.location.search) {
    var queryString = window.location.search.substring(1); // remove prefixing '?'
    queryString = decodeURI(queryString);
    handleOrder(function () {
      return parseQueryStringInput(queryString);
    });
  }
}

function onPercentageCheckboxClick () {
  var isTipPercentage = document.getElementById('percentageCheckbox').checked;
  document.getElementById('fixedSpan').hidden = isTipPercentage;
  document.getElementById('percentageSpan').hidden = !isTipPercentage;
}

function onSplitButtonClick () {
  var text = document.getElementById('textarea').value;
  var tax = Number(document.getElementById('taxes').value);
  var fee = Number(document.getElementById('fees').value);
  var tip = Number(document.getElementById('tip').value);
  var isTipPercentage = document.getElementById('percentageCheckbox').checked;

  handleOrder(function () {
    return parseOrderUpInput(text, fee, tax, tip, isTipPercentage);
  });
}

function handleOrder (parserFunction) {
  var order = parserFunction();
  order.split();
  display(order);
}

function display (order) {

  var calculationsTable = '
' +
      '
Subtotal:	$' + prettifyNumber(order.subtotal) + '	(user input; sum of item costs)
' +
      '
Tax:	$' + prettifyNumber(order.tax) + '	(user input)
' +
      '
Fees:	$' + prettifyNumber(order.fee) + '	(user input)
' +
      '
Tip:	$' + prettifyNumber(order.tip) + '	(' + (order.isTipPercentage ? 'tip percent * subtotal' : 'user input') + ')
' +
      '
Total:	$' + prettifyNumber(order.total) + '	(subtotal + tax + fees + tip)
' +
      '
Fees per Person:	$' + prettifyNumber(order.feesPerPerson) + '	(fees / number of people)
' +
      '
Tax (Percent):	' + order.taxPercent + '%	(tax / subtotal)
' +
      '
Tip (Percent):	' + order.tipPercent + '%	(' + (order.isTipPercentage ? 'user input' : 'tip / subtotal') + ')
' +
      '
';

  var html =
      '
' +
      calculationsTable + '
' +
      makeBreakdownDisplay(order) + '
' +
      'Publish the following:
' +
      '
' + makeTotalsDisplay(order.totals) + '
' +
      makeHyperlink(order.tax, order.fee, order.tip, order.costs);

  document.getElementById('result').innerHTML = html;
}

/**
 * Returns a string of a number in the format "#.##"
 * @example
 * prettifyNumber(12); // returns "12.00"
 * @param {number} n - The number to prettify
 * @returns {string} A string of a number rounded and padded to 2 decimal places
 */
function prettifyNumber (n) {
  n = Math.round(n * 100) / 100; // round to 2 decimal places

  // pad to 2 decimal places if necessary
  var s = n.toString();

  if (s.indexOf('.') === -1) {
    s += '.';
  }

  while (s.length < s.indexOf('.') + 3) {
    s += '0';
  }

  return s;
}

/**
 * Returns a listing of names to split costs
 * @param {object} totals - The totals property from the Order
 * @returns {string} A view mapping names to split costs
 */
function makeTotalsDisplay (totals) {
  // get length of longest name
  var longestName = -1;
  for (var p in totals) {
    longestName = Math.max(p.length, longestName);
  }

  // add 1 to longest name for a space after name
  longestName += 1;

  var output = '';
  var name;
  for (p in totals) {
    name = p;
    for (var i = p.length; i < longestName; i++) {
      name += ' ';
    }
    output += name + '$' + prettifyNumber(totals[p]) + '
';
  }

  return output;
}

/**
 * Returns a hyperlink to this split order.
 * @param {number} tax - amount of taxes
 * @param {fee} fee - amount of fees
 * @param {number} tip - tip
 * @param {Object} personItemCosts - map of person name to item costs
 * @return {string} The hyperlink to this order
 */
function makeHyperlink (tax, fee, tip, personItemCosts) {
  var link = window.location.origin + window.location.pathname;
  if (link.indexOf('index.html') === -1) {
    link += 'index.html';
  }

  link += '?tax=' + tax + '&fee=' + fee + '&tip=' + tip;

  for (var p in personItemCosts) {
    link += '&' + p + '=' + prettifyNumber(personItemCosts[p]);
  }

  link = encodeURI(link);

  return '' + link + '';
}

/**
 * Returns a display breaking down the Order split calculations
 * @param {Order} order - the Order to breakdown
 * @returns {string} A view of the Order breakdown
 */
function makeBreakdownDisplay (order) {
  var breakdown = '
';
  breakdown += '
Person	Item Costs	Tax	Tip	Fees Per Person	Person Total
';
  for (var person in order.costs) {
    var personItemCosts = prettifyNumber(order.costs[person]);
    breakdown += '
' + person + '	' +
        personItemCosts + '	 + ' + // item costs
        personItemCosts + ' * ' + order.taxPercent / 100 + '	 + ' + // taxes
        personItemCosts + ' * ' + order.tipPercent / 100 + '	 + ' + // tip
        order.feesPerPerson + '	 = ' +
        prettifyNumber(order.totals[person]) + '
';
  }

  breakdown += '
';
  return breakdown;
}
<commit_msg>Load user preferences from localStorage and update tip being percentage accordingly<commit_after>window.onload = init;

function init () {
  // check for URL query parameters
  if (window.location.search) {
    var queryString = window.location.search.substring(1); // remove prefixing '?'
    queryString = decodeURI(queryString);
    handleOrder(function () {
      return parseQueryStringInput(queryString);
    });
  }

  loadPreferences();
}

/**
 * Loads user preferences from localStorage.
 */
function loadPreferences () {
  if (Storage) {
    if (localStorage.getItem('isTipPercentage') === 'false') {
      // tip is a percentage by default, update if user prefs is 'false'
      updateTipComponents(false);
      document.getElementById('percentageCheckbox').checked = false;
    }
  }
}

function onPercentageCheckboxClick () {
  updateTipComponents(document.getElementById('percentageCheckbox').checked);
}

/**
 * Updates the tip components according to the tip being a percentage.
 * @param {boolean} isTipPercentage
 */
function updateTipComponents (isTipPercentage) {
  document.getElementById('fixedSpan').hidden = isTipPercentage;
  document.getElementById('percentageSpan').hidden = !isTipPercentage;
}

function onSplitButtonClick () {
  var text = document.getElementById('textarea').value;
  var tax = Number(document.getElementById('taxes').value);
  var fee = Number(document.getElementById('fees').value);
  var tip = Number(document.getElementById('tip').value);
  var isTipPercentage = document.getElementById('percentageCheckbox').checked;

  handleOrder(function () {
    return parseOrderUpInput(text, fee, tax, tip, isTipPercentage);
  });
}

function handleOrder (parserFunction) {
  var order = parserFunction();
  order.split();
  display(order);
}

function display (order) {

  var calculationsTable = '
' +
      '
Subtotal:	$' + prettifyNumber(order.subtotal) + '	(user input; sum of item costs)
' +
      '
Tax:	$' + prettifyNumber(order.tax) + '	(user input)
' +
      '
Fees:	$' + prettifyNumber(order.fee) + '	(user input)
' +
      '
Tip:	$' + prettifyNumber(order.tip) + '	(' + (order.isTipPercentage ? 'tip percent * subtotal' : 'user input') + ')
' +
      '
Total:	$' + prettifyNumber(order.total) + '	(subtotal + tax + fees + tip)
' +
      '
Fees per Person:	$' + prettifyNumber(order.feesPerPerson) + '	(fees / number of people)
' +
      '
Tax (Percent):	' + order.taxPercent + '%	(tax / subtotal)
' +
      '
Tip (Percent):	' + order.tipPercent + '%	(' + (order.isTipPercentage ? 'user input' : 'tip / subtotal') + ')
' +
      '
';

  var html =
      '
' +
      calculationsTable + '
' +
      makeBreakdownDisplay(order) + '
' +
      'Publish the following:
' +
      '
' + makeTotalsDisplay(order.totals) + '
' +
      makeHyperlink(order.tax, order.fee, order.tip, order.costs);

  document.getElementById('result').innerHTML = html;
}

/**
 * Returns a string of a number in the format "#.##"
 * @example
 * prettifyNumber(12); // returns "12.00"
 * @param {number} n - The number to prettify
 * @returns {string} A string of a number rounded and padded to 2 decimal places
 */
function prettifyNumber (n) {
  n = Math.round(n * 100) / 100; // round to 2 decimal places

  // pad to 2 decimal places if necessary
  var s = n.toString();

  if (s.indexOf('.') === -1) {
    s += '.';
  }

  while (s.length < s.indexOf('.') + 3) {
    s += '0';
  }

  return s;
}

/**
 * Returns a listing of names to split costs
 * @param {object} totals - The totals property from the Order
 * @returns {string} A view mapping names to split costs
 */
function makeTotalsDisplay (totals) {
  // get length of longest name
  var longestName = -1;
  for (var p in totals) {
    longestName = Math.max(p.length, longestName);
  }

  // add 1 to longest name for a space after name
  longestName += 1;

  var output = '';
  var name;
  for (p in totals) {
    name = p;
    for (var i = p.length; i < longestName; i++) {
      name += ' ';
    }
    output += name + '$' + prettifyNumber(totals[p]) + '
';
  }

  return output;
}

/**
 * Returns a hyperlink to this split order.
 * @param {number} tax - amount of taxes
 * @param {fee} fee - amount of fees
 * @param {number} tip - tip
 * @param {Object} personItemCosts - map of person name to item costs
 * @return {string} The hyperlink to this order
 */
function makeHyperlink (tax, fee, tip, personItemCosts) {
  var link = window.location.origin + window.location.pathname;
  if (link.indexOf('index.html') === -1) {
    link += 'index.html';
  }

  link += '?tax=' + tax + '&fee=' + fee + '&tip=' + tip;

  for (var p in personItemCosts) {
    link += '&' + p + '=' + prettifyNumber(personItemCosts[p]);
  }

  link = encodeURI(link);

  return '' + link + '';
}

/**
 * Returns a display breaking down the Order split calculations
 * @param {Order} order - the Order to breakdown
 * @returns {string} A view of the Order breakdown
 */
function makeBreakdownDisplay (order) {
  var breakdown = '
';
  breakdown += '
Person	Item Costs	Tax	Tip	Fees Per Person	Person Total
';
  for (var person in order.costs) {
    var personItemCosts = prettifyNumber(order.costs[person]);
    breakdown += '
' + person + '	' +
        personItemCosts + '	 + ' + // item costs
        personItemCosts + ' * ' + order.taxPercent / 100 + '	 + ' + // taxes
        personItemCosts + ' * ' + order.tipPercent / 100 + '	 + ' + // tip
        order.feesPerPerson + '	 = ' +
        prettifyNumber(order.totals[person]) + '
';
  }

  breakdown += '
';
  return breakdown;
}
<|endoftext|>


<commit_before>
var FC = $.fullCalendar = {
	version: "<%= meta.version %>",
	internalApiVersion: 4
};
var fcViews = FC.views = {};

$.fn.fullCalendar = function(options) {
	var args = Array.prototype.slice.call(arguments, 1); // for a possible method call
	var res = this; // what this function will return (this jQuery object by default)

	this.each(function(i, _element) { // loop each DOM element involved
		var element = $(_element);
		var calendar = element.data('fullCalendar'); // get the existing calendar object (if any)
		var singleRes; // the returned value of this single method call

		// a method call
		if (typeof options === 'string') {
			if (calendar && $.isFunction(calendar[options])) {
				singleRes = calendar[options].apply(calendar, args);
				if (!i) {
					res = singleRes; // record the first method call result
				}
				if (options === 'destroy') { // for the destroy method, must remove Calendar object data
					element.removeData('fullCalendar');
				}
			}
		}
		// a new calendar initialization
		else if (!calendar) { // don't initialize twice
			calendar = new Calendar(element, options);
			element.data('fullCalendar', calendar);
			calendar.render();
		}
	});

	return res;
};

var complexOptions = [ // names of options that are objects whose properties should be combined
	'header',
	'buttonText',
	'buttonIcons',
	'themeButtonIcons'
];

// Merges an array of option objects into a single object
function mergeOptions(optionObjs) {
	return mergeProps(optionObjs, complexOptions);
}

// Given options specified for the calendar's constructor, massages any legacy options into a non-legacy form.
// Converts View-Option-Hashes into the View-Specific-Options format.
function massageOverrides(input) {
	var overrides = { views: input.views || {} }; // the output. ensure a `views` hash
	var subObj;

	// iterate through all option override properties (except `views`)
	$.each(input, function(name, val) {
		if (name != 'views') {

			// could the value be a legacy View-Option-Hash?
			if (
				$.isPlainObject(val) &&
				!/(time|duration|interval)$/i.test(name) && // exclude duration options. might be given as objects
				$.inArray(name, complexOptions) == -1 // complex options aren't allowed to be View-Option-Hashes
			) {
				subObj = null;

				// iterate through the properties of this possible View-Option-Hash value
				$.each(val, function(subName, subVal) {

					// is the property targeting a view?
					if (/^(month|week|day|default|basic(Week|Day)?|agenda(Week|Day)?)$/.test(subName)) {
						if (!overrides.views[subName]) { // ensure the view-target entry exists
							overrides.views[subName] = {};
						}
						overrides.views[subName][name] = subVal; // record the value in the `views` object
					}
					else { // a non-View-Option-Hash property
						if (!subObj) {
							subObj = {};
						}
						subObj[subName] = subVal; // accumulate these unrelated values for later
					}
				});

				if (subObj) { // non-View-Option-Hash properties? transfer them as-is
					overrides[name] = subObj;
				}
			}
			else {
				overrides[name] = val; // transfer normal options as-is
			}
		}
	});

	return overrides;
}
<commit_msg>Added error message for unknown method.<commit_after>
var FC = $.fullCalendar = {
	version: "<%= meta.version %>",
	internalApiVersion: 4
};
var fcViews = FC.views = {};

$.fn.fullCalendar = function(options) {
	var args = Array.prototype.slice.call(arguments, 1); // for a possible method call
	var res = this; // what this function will return (this jQuery object by default)

	this.each(function(i, _element) { // loop each DOM element involved
		var element = $(_element);
		var calendar = element.data('fullCalendar'); // get the existing calendar object (if any)
		var singleRes; // the returned value of this single method call

		// a method call
		if (typeof options === 'string') {
			if (calendar && $.isFunction(calendar[options])) {
				singleRes = calendar[options].apply(calendar, args);
				if (!i) {
					res = singleRes; // record the first method call result
				}
				if (options === 'destroy') { // for the destroy method, must remove Calendar object data
					element.removeData('fullCalendar');
				}
			}
			else {
				console.error("'" + options +"' is an unknown FullCalendar method.");
			}
		}
		// a new calendar initialization
		else if (!calendar) { // don't initialize twice
			calendar = new Calendar(element, options);
			element.data('fullCalendar', calendar);
			calendar.render();
		}
	});

	return res;
};

var complexOptions = [ // names of options that are objects whose properties should be combined
	'header',
	'buttonText',
	'buttonIcons',
	'themeButtonIcons'
];

// Merges an array of option objects into a single object
function mergeOptions(optionObjs) {
	return mergeProps(optionObjs, complexOptions);
}

// Given options specified for the calendar's constructor, massages any legacy options into a non-legacy form.
// Converts View-Option-Hashes into the View-Specific-Options format.
function massageOverrides(input) {
	var overrides = { views: input.views || {} }; // the output. ensure a `views` hash
	var subObj;

	// iterate through all option override properties (except `views`)
	$.each(input, function(name, val) {
		if (name != 'views') {

			// could the value be a legacy View-Option-Hash?
			if (
				$.isPlainObject(val) &&
				!/(time|duration|interval)$/i.test(name) && // exclude duration options. might be given as objects
				$.inArray(name, complexOptions) == -1 // complex options aren't allowed to be View-Option-Hashes
			) {
				subObj = null;

				// iterate through the properties of this possible View-Option-Hash value
				$.each(val, function(subName, subVal) {

					// is the property targeting a view?
					if (/^(month|week|day|default|basic(Week|Day)?|agenda(Week|Day)?)$/.test(subName)) {
						if (!overrides.views[subName]) { // ensure the view-target entry exists
							overrides.views[subName] = {};
						}
						overrides.views[subName][name] = subVal; // record the value in the `views` object
					}
					else { // a non-View-Option-Hash property
						if (!subObj) {
							subObj = {};
						}
						subObj[subName] = subVal; // accumulate these unrelated values for later
					}
				});

				if (subObj) { // non-View-Option-Hash properties? transfer them as-is
					overrides[name] = subObj;
				}
			}
			else {
				overrides[name] = val; // transfer normal options as-is
			}
		}
	});

	return overrides;
}
<|endoftext|>


<commit_before>'use strict'

/**
 * plugin.js
 *
 * Released under LGPL License.
 * Copyright (c) 2017 SIRAP Group All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * plugin.js Tinymce plugin headersfooters
 * @file plugin.js
 * @module
 * @name tinycmce-plugin-headersfooters
 * @description
 * A plugin for tinymce WYSIWYG HTML editor that allow to insert headers and footers
 * @see https://github.com/sirap-group/tinymce-plugin-headersfooters
 * @author Rémi Becheras
 * @author Groupe SIRAP
 * @license GNU GPL-v2 http://www.tinymce.com/license
 */

/**
 * Tinymce library - injected by the plugin loader.
 * @external tinymce
 * @see {@link https://www.tinymce.com/docs/api/class/tinymce/|Tinymce API Reference}
 */
var tinymce = window.tinymce

var menuItems = require('./components/menu-items')

var units = require('./utils/units')
var events = require('./utils/events')
var uiUtils = require('./utils/ui')

var eventHandlers = require('./event-handlers')

// Add the plugin to the tinymce PluginManager
tinymce.PluginManager.add('headersfooters', tinymcePluginHeadersFooters)

/**
 * Tinymce plugin headers/footers
 * @function
 * @global
 * @param {tinymce.Editor} editor - The injected tinymce editor.
 * @returns void
 */
function tinymcePluginHeadersFooters (editor, url) {
  // var thisPlugin = this
  this.type = editor.settings.headersfooters_type
  this.headerFooterFactory = null
  this.units = units
  this.editor = editor
  this.documentBodies = {
    app: null,
    mce: {
      header: null,
      body: null,
      footer: null
    }
  }

  this.menuItemsList = menuItems.create(editor)
  uiUtils.autoAddMenuItems.call(this)

  editor.addCommand('insertPageNumberCmd', function () {
    editor.insertContent('{{page}}')
  })
  editor.addCommand('insertNumberOfPagesCmd', function () {
    editor.insertContent('{{pages}}')
  })

  events.autoBindImplementedEventCallbacks.call(this, editor, eventHandlers)
}
<commit_msg>set this.bodyClass from plugin.settings.body_class in constructor<commit_after>'use strict'

/**
 * plugin.js
 *
 * Released under LGPL License.
 * Copyright (c) 2017 SIRAP Group All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * plugin.js Tinymce plugin headersfooters
 * @file plugin.js
 * @module
 * @name tinycmce-plugin-headersfooters
 * @description
 * A plugin for tinymce WYSIWYG HTML editor that allow to insert headers and footers
 * @see https://github.com/sirap-group/tinymce-plugin-headersfooters
 * @author Rémi Becheras
 * @author Groupe SIRAP
 * @license GNU GPL-v2 http://www.tinymce.com/license
 */

/**
 * Tinymce library - injected by the plugin loader.
 * @external tinymce
 * @see {@link https://www.tinymce.com/docs/api/class/tinymce/|Tinymce API Reference}
 */
var tinymce = window.tinymce

var menuItems = require('./components/menu-items')

var units = require('./utils/units')
var events = require('./utils/events')
var uiUtils = require('./utils/ui')

var eventHandlers = require('./event-handlers')

// Add the plugin to the tinymce PluginManager
tinymce.PluginManager.add('headersfooters', tinymcePluginHeadersFooters)

/**
 * Tinymce plugin headers/footers
 * @function
 * @global
 * @param {tinymce.Editor} editor - The injected tinymce editor.
 * @returns void
 */
function tinymcePluginHeadersFooters (editor, url) {
  // var thisPlugin = this
  this.type = editor.settings.headersfooters_type
  this.bodyClass = editor.settings.body_class

  this.headerFooterFactory = null

  this.units = units
  this.editor = editor

  this.documentBodies = {
    app: null,
    mce: {
      header: null,
      body: null,
      footer: null
    }
  }

  this.menuItemsList = menuItems.create(editor)
  uiUtils.autoAddMenuItems.call(this)

  editor.addCommand('insertPageNumberCmd', function () {
    editor.insertContent('{{page}}')
  })
  editor.addCommand('insertNumberOfPagesCmd', function () {
    editor.insertContent('{{pages}}')
  })

  events.autoBindImplementedEventCallbacks.call(this, editor, eventHandlers)
}
<|endoftext|>


<commit_before>import Vue from 'vue'
import Router from 'vue-router'
import Resource from 'vue-resource'
// import { domain, fromNow } from './filters'
import App from './components/App.vue'
import Homepage from './components/Homepage.vue'
import EUMatches from './components/EUMatches.vue'
import Map from './components/Map.vue'
import Leaderboard from './components/Leaderboard.vue'
import Match from './components/Match.vue'

// install router
Vue.use(Router)
// install resource, for http requests
Vue.use(Resource)

// register filters globally
// Vue.filter('fromNow', fromNow)
// Vue.filter('domain', domain)

Vue.directive('progress', {
  bind: function () {},
  update: function (value, old) {
    // The directive may be called before the element have been upgraded
    window.componentHandler.upgradeElement(this.el)
    this.el.MaterialProgress.setProgress(value)
  }
})

Vue.directive('mdl', {
  bind: function () {
    window.componentHandler.upgradeElement(this.el)
  }
})

// routing
var router = new Router({hashbang: false})

router.map({
  '/na': {
    component: Homepage,
    pageTitle: 'North American Matches',
    region: '1-'
  },
  '/eu': {
    component: EUMatches,
    pageTitle: 'European Matches',
    region: '2-'
  },
  '/map': {
    component: Map,
    pageTitle: 'Live Map'
  },
  '/map/:server': {
    component: Map,
    pageTitle: 'Live Map'
  },
  '/leaderboard': {
    component: Leaderboard,
    pageTitle: 'Leaderboard'
  },
  '/match/:matchid': {
    component: Match,
    pageTitle: 'Match Details'
  }
})

/**
 * uncomment if want page to go back to top..
 * TODO: Maybe animate this?
 */

/*router.afterEach(function () {
  console.log('hi')
  var _router_el = document.getElementById('router_view')
  _router_el.scrollTop = 0
})*/

router.redirect({
  '*': '/na'
})

router.start(App, '#app')
<commit_msg>Add grapher route and add the google charts loader<commit_after>import Vue from 'vue'
import Router from 'vue-router'
import Resource from 'vue-resource'
// import { domain, fromNow } from './filters'
import App from './components/App.vue'
import Homepage from './components/Homepage.vue'
import EUMatches from './components/EUMatches.vue'
import Map from './components/Map.vue'
import Leaderboard from './components/Leaderboard.vue'
import Match from './components/Match.vue'
import Grapher from './components/Grapher.vue'

// Google charts
window.google.charts.load('current', {
  'packages': ['corechart', 'line']
});

// install router
Vue.use(Router)
// install resource, for http requests
Vue.use(Resource)

// register filters globally
// Vue.filter('fromNow', fromNow)
// Vue.filter('domain', domain)

Vue.directive('progress', {
  bind: function () {},
  update: function (value, old) {
    // The directive may be called before the element have been upgraded
    window.componentHandler.upgradeElement(this.el)
    this.el.MaterialProgress.setProgress(value)
  }
})

Vue.directive('mdl', {
  bind: function () {
    window.componentHandler.upgradeElement(this.el)
  }
})

// routing
var router = new Router({hashbang: false})

router.map({
  '/na': {
    component: Homepage,
    pageTitle: 'North American Matches',
    region: '1-'
  },
  '/eu': {
    component: EUMatches,
    pageTitle: 'European Matches',
    region: '2-'
  },
  '/map': {
    component: Map,
    pageTitle: 'Live Map'
  },
  '/map/:server': {
    component: Map,
    pageTitle: 'Live Map'
  },
  '/leaderboard': {
    component: Leaderboard,
    pageTitle: 'Leaderboard'
  },
  '/match/:matchid': {
    component: Match,
    pageTitle: 'Match Details'
  },
  '/grapher': {
    component: Grapher,
    pageTitle: 'Grapher'
  }
})

/**
 * uncomment if want page to go back to top..
 * TODO: Maybe animate this?
 */

/*router.afterEach(function () {
  console.log('hi')
  var _router_el = document.getElementById('router_view')
  _router_el.scrollTop = 0
})*/

router.redirect({
  '*': '/na'
})

router.start(App, '#app')
<|endoftext|>


<commit_before>requirejs.config({
//    baseUrl: '/',
    paths: {
        lodash: '//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min',
        react: '//fb.me/react-with-addons-0.12.2'
    },
    shim: {
        lodash: {exports: '_'},
        react: {exports: 'React'}
    },
    map: {
        '*': {
            'react/addons': 'react'
        }
    }
});

requirejs(['react', './hello'], function (React, hello) {
    'use strict';
    React.render(React.createElement(hello), document.getElementById('container'));
});
<commit_msg>add zepto<commit_after>requirejs.config({
//    baseUrl: '/',
    paths: {
        lodash: '//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.0.1/lodash.min',
        react: '//fb.me/react-with-addons-0.12.2',
        zepto: '//cdnjs.cloudflare.com/ajax/libs/zepto/1.1.4/zepto.min.js'
    },
    shim: {
        lodash: {exports: '_'},
        react: {exports: 'React'},
        zepto: {exports: '$'}
    },
    map: {
        '*': {
            'react/addons': 'react'
        }
    }
});

requirejs(['react', './hello'], function (React, hello) {
    'use strict';
    React.render(React.createElement(hello), document.getElementById('container'));
});
<|endoftext|>


<commit_before>var app = require('app');
var BrowserWindow = require('browser-window');
var ipc = require('ipc');
var fs = require('fs');
var jason = require('JASON');

require('crash-reporter').start();

var mainWindow = null;

app.on('window-all-closed', function() {
  //TODO: exit when computer restart, to see what node service should do when system down?
  //app.quit();
});

app.on('ready', function() {
  mainWindow = new BrowserWindow({
	width: 1366,
	height: 768,
	show: false,
	frame: false,
	'node-integration': false,
	preload: __dirname + '/preload.js'
  });

  mainWindow.loadUrl('file://' + __dirname + '/index.html');

  //mainWindow.openDevTools();

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

ipc.on('WriteFile', function(event, filename){
  console.log("going to capture in main: "+Date.now());
  mainWindow.capturePage(function(buf) {
    console.log("capture finished in main: "+Date.now());
    var mybuffer = jason.stringify(buf);
	console.log("serialization finished in main: "+Date.now());
  };
  /*console.log("got message to write file: "+filename+", time is "Date.now());
  fs.writeFile(filename, buf, function(err) {
    console.log("write file finished: "+Date.now());
    if(err){
      console.log(err);
    }
  });*/
});<commit_msg>test for jason<commit_after>var app = require('app');
var BrowserWindow = require('browser-window');
var ipc = require('ipc');
var fs = require('fs');
var jason = require('JASON');

require('crash-reporter').start();

var mainWindow = null;

app.on('window-all-closed', function() {
  //TODO: exit when computer restart, to see what node service should do when system down?
  //app.quit();
});

app.on('ready', function() {
  mainWindow = new BrowserWindow({
	width: 1366,
	height: 768,
	show: false,
	frame: false,
	'node-integration': false,
	preload: __dirname + '/preload.js'
  });

  mainWindow.loadUrl('file://' + __dirname + '/index.html');

  //mainWindow.openDevTools();

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

ipc.on('WriteFile', function(event, filename){
  console.log("going to capture in main: "+Date.now());
  mainWindow.capturePage(function(buf) {
    console.log("capture finished in main: "+Date.now());
    var mybuffer = jason.stringify(buf);
	console.log("serialization finished in main: "+Date.now());
  });
  /*console.log("got message to write file: "+filename+", time is "Date.now());
  fs.writeFile(filename, buf, function(err) {
    console.log("write file finished: "+Date.now());
    if(err){
      console.log(err);
    }
  });*/
});<|endoftext|>


<commit_before>// Copyright 2014 Flávio Ribeiro <flavio@bem.tv>.
// All rights reserved.
// Use of this source code is governed by Apache
// license that can be found in the LICENSE file.

var UIPlugin = require('ui_plugin');
var JST = require('.././jst');
var Styler = require('./styler');
var Mousetrap = require('mousetrap');
var Settings = require('./settings')
var $ = require('jquery');

class P2PHLSStats extends UIPlugin {
  get name() { return 'p2phlsstats' }
  get tagName() { return 'div' }
  get type() { return "ui" }
  get template() { return JST.p2phlsstats }
  get attributes() {
    return {'data-p2phlsstats': '',
            'class': 'p2phlsstats'}
  }

  initialize(options) {
    super(options)
    this.render()
    this.addListeners()
    this.metrics = {
      status: "off",
      chunksFromCDN: 0,
      chunksFromP2P: 0,
      chunksSent: '-',
      swarmSize: 0,
      currentBitrate: 0,
      state: "IDLE",
      bufferLength: 0,
      startupTime: 0,
      watchingTime: 0,
      rebufferingTime: 0,
      rebuffers: 0
    }
    this.updateMetrics()
    setInterval(this.sendStats.bind(this), Settings.period)
  }

  addListeners() {
    Mousetrap.bind(['command+shift+s', 'ctrl+shift+s'], () => this.showOrHide())
    this.listenTo(this.container.playback, 'playback:p2phlsstats:add', (metric) => this.statsAdd(metric))
    this.listenTo(this.container, 'container:stats:report', (metrics) => this.onStatsReport(metrics))
  }

  onStatsReport(metrics) {
    this.metrics.startupTime = metrics['startupTime'] / 1000
    this.metrics.watchingTime = metrics['watchingTime'] / 1000
    this.metrics.rebufferingTime = metrics['rebufferingTime'] / 1000
    this.metrics.rebuffers = metrics['rebuffers']
    this.updateMetrics()
  }

  statsAdd(metric) {
    $.extend(this.metrics, metric)
    this.updateMetrics()
  }

  showOrHide() {
    if (this.showing) {
      this.hide()
    } else {
      this.show()
    }
  }

  show() {
    this.$el.show()
    this.showing = true
  }

  hide() {
    this.$el.hide()
    this.showing = false
  }

  updateMetrics() {
    this.$el.html(this.template(this.metrics))
    if (this.metrics.status === "off") {
      this.$el.find("span.stats-status").css({'color': '#FF0000'})
    } else {
      this.$el.find("span.stats-status").css({'color': '#7CFC00'})
    }
  }

  render() {
    var style = Styler.getStyleFor(this.name)
    this.container.$el.append(style)
    this.container.$el.append(this.$el)
    return this
  }

  sendStats() {
    var queryString = "?id=" + Settings.statsId + "&" + $.param(this.metrics)
    var url = Settings.URL + queryString
    $.ajax({url: url})
  }
}

module.exports = window.P2PHLSStats = P2PHLSStats;
<commit_msg>main: avoid NaN on watchingTime and startupTime (fixes #10)<commit_after>// Copyright 2014 Flávio Ribeiro <flavio@bem.tv>.
// All rights reserved.
// Use of this source code is governed by Apache
// license that can be found in the LICENSE file.

var UIPlugin = require('ui_plugin');
var JST = require('.././jst');
var Styler = require('./styler');
var Mousetrap = require('mousetrap');
var Settings = require('./settings')
var $ = require('jquery');

class P2PHLSStats extends UIPlugin {
  get name() { return 'p2phlsstats' }
  get tagName() { return 'div' }
  get type() { return "ui" }
  get template() { return JST.p2phlsstats }
  get attributes() {
    return {'data-p2phlsstats': '',
            'class': 'p2phlsstats'}
  }

  initialize(options) {
    super(options)
    this.render()
    this.addListeners()
    this.metrics = {
      status: "off",
      chunksFromCDN: 0,
      chunksFromP2P: 0,
      chunksSent: '-',
      swarmSize: 0,
      currentBitrate: 0,
      state: "IDLE",
      bufferLength: 0,
      startupTime: 0,
      watchingTime: 0,
      rebufferingTime: 0,
      rebuffers: 0
    }
    this.updateMetrics()
    setInterval(this.sendStats.bind(this), Settings.period)
  }

  addListeners() {
    Mousetrap.bind(['command+shift+s', 'ctrl+shift+s'], () => this.showOrHide())
    this.listenTo(this.container.playback, 'playback:p2phlsstats:add', (metric) => this.statsAdd(metric))
    this.listenTo(this.container, 'container:stats:report', (metrics) => this.onStatsReport(metrics))
  }

  onStatsReport(metrics) {
    if (metrics['startupTime'] > 0) {
      this.metrics.startupTime = metrics['startupTime'] / 1000
    }
    if (metrics['watchingTime'] > 0) {
      this.metrics.watchingTime = metrics['watchingTime'] / 1000
    }
    if (metrics['rebufferingTime'] > 0) {
      this.metrics.rebufferingTime = metrics['rebufferingTime'] / 1000
    }
    this.metrics.rebuffers = metrics['rebuffers']
    this.updateMetrics()
  }

  statsAdd(metric) {
    $.extend(this.metrics, metric)
    this.updateMetrics()
  }

  showOrHide() {
    if (this.showing) {
      this.hide()
    } else {
      this.show()
    }
  }

  show() {
    this.$el.show()
    this.showing = true
  }

  hide() {
    this.$el.hide()
    this.showing = false
  }

  updateMetrics() {
    this.$el.html(this.template(this.metrics))
    if (this.metrics.status === "off") {
      this.$el.find("span.stats-status").css({'color': '#FF0000'})
    } else {
      this.$el.find("span.stats-status").css({'color': '#7CFC00'})
    }
  }

  render() {
    var style = Styler.getStyleFor(this.name)
    this.container.$el.append(style)
    this.container.$el.append(this.$el)
    return this
  }

  sendStats() {
    var queryString = "?id=" + Settings.statsId + "&" + $.param(this.metrics)
    var url = Settings.URL + queryString
    $.ajax({url: url})
  }
}

module.exports = window.P2PHLSStats = P2PHLSStats;
<|endoftext|>


<commit_before>/*!
 * Inline SVG Polyfill v.1.0.1
 * ----------------------------------------------------------------------------
 * Find inline SVG elements and replace them with a fallback image set via
 * the `data-fallback` attribute.
 *
 * @author David Street
 * @license MIT
 */

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['exports'], factory);
    } else if (typeof exports === 'object') {
        // CommonJS
        factory(exports);
    } else {
        // Browser globals
        var exports = {};
		factory(exports);
		root.InlineSVG = exports.InlineSVG;
    }
}(this, function (exports) {

	exports.InlineSVG = function() {
		var svgList = null
			, removeEl = [];

		/**
		 * Create a replacement element with the fallback image
		 */
		function _replaceSVG() {
			svgList = document.getElementsByTagName('svg');

			for (var i = 0, len = svgList.length; i < len; i += 1) {
				var fallback = svgList[i].getAttribute('data-fallback')
					, parent = null
					, useEl = null
					, ref = null
					, replacement = null
					, viewBox;

				// Go to next element if no fallback was given
				if (!fallback) continue;

				useEl = svgList[i].querySelector('use');

				// Go to next element if the svg does not have a `use` child
				if (!useEl) continue;

				ref = document.getElementById(useEl.getAttribute('xlink:href').replace('#', ''));

				// Go to next element if the svg doc we are referencing doesn't exist
				if (!ref) continue;

				viewBox = _getViewBox(ref);
				parent = svgList[i].parentElement;

				replacement = _createReplacement(viewBox, fallback, svgList[i]);

				// Add new replacement element to the parent
				parent.insertBefore(replacement, svgList[i]);
				removeEl.push(svgList[i]);
			}

			_hideSVG();
		}

		/**
		 * Create a viewBox object for an element
		 *
		 * @param Object The element
		 *
		 * @return Object The viewBox
		 */
		function _getViewBox(el) {
			var attArray = []
				, viewBox = {};

			attArray = el.getAttribute('viewBox').split(' ');
			viewBox.x = attArray[0];
			viewBox.y = attArray[1];
			viewBox.width = attArray[2];
			viewBox.height = attArray[3];

			return viewBox;
		}

		/**
		 * Create new element with fallback background
		 *
		 * @param Object The viewBox object
		 * @param String The path to the fallback image
		 * @param Object The reference element
		 *
		 * @return Object The replacement element
		 */
		function _createReplacement(viewBox, fallback, ref) {
			var replacement;

			replacement = document.createElement('div');
			replacement.setAttribute('class', ref.getAttribute('class'));
			replacement.style.width = viewBox.width + 'px';
			replacement.style.height = viewBox.height + 'px';
			replacement.style.background = 'transparent url(' + fallback + ') no-repeat -' + viewBox.x + 'px -' + viewBox.y + 'px';

			return replacement
		}

		/**
		 * Hide all elements that have been replaced
		 */
		function _hideSVG() {
			for (var i = 0, len = removeEl.length; i < len; i += 1) {
				removeEl[i].style.display = 'none';
			}
		}

		/**
		 * Check support for inline SVGs.
		 *
		 * Courtesy of Modernizr: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/svg/inline.js
		 *
		 * @return Boolean
		 */
		function _checkSupport() {
			var div = createElement('div');
	    	div.innerHTML = '<svg/>';
	    	return (div.firstChild && div.firstChild.namespaceURI) == 'http://www.w3.org/2000/svg';
		}

		return {
			init: function() {
				// Exit if inline svg is supported by the browser
				if (_checkSupport()) {
					return false
				} else {
					_replaceSVG();
				}
			}
		}
	};

}));
<commit_msg>Use tabs over spaces<commit_after>/*!
 * Inline SVG Polyfill v.1.0.1
 * ----------------------------------------------------------------------------
 * Find inline SVG elements and replace them with a fallback image set via
 * the `data-fallback` attribute.
 *
 * @author David Street
 * @license MIT
 */

(function (root, factory) {
	if (typeof define === 'function' && define.amd) {
		// AMD. Register as an anonymous module.
		define(['exports'], factory);
	} else if (typeof exports === 'object') {
		// CommonJS
		factory(exports);
	} else {
		// Browser globals
		var exports = {};
		factory(exports);
		root.InlineSVG = exports.InlineSVG;
	}
}(this, function (exports) {

	exports.InlineSVG = function() {
		var svgList = null
			, removeEl = [];

		/**
		 * Create a replacement element with the fallback image
		 */
		function _replaceSVG() {
			svgList = document.getElementsByTagName('svg');

			for (var i = 0, len = svgList.length; i < len; i += 1) {
				var fallback = svgList[i].getAttribute('data-fallback')
					, parent = null
					, useEl = null
					, ref = null
					, replacement = null
					, viewBox;

				// Go to next element if no fallback was given
				if (!fallback) continue;

				useEl = svgList[i].querySelector('use');

				// Go to next element if the svg does not have a `use` child
				if (!useEl) continue;

				ref = document.getElementById(useEl.getAttribute('xlink:href').replace('#', ''));

				// Go to next element if the svg doc we are referencing doesn't exist
				if (!ref) continue;

				viewBox = _getViewBox(ref);
				parent = svgList[i].parentElement;

				replacement = _createReplacement(viewBox, fallback, svgList[i]);

				// Add new replacement element to the parent
				parent.insertBefore(replacement, svgList[i]);
				removeEl.push(svgList[i]);
			}

			_hideSVG();
		}

		/**
		 * Create a viewBox object for an element
		 *
		 * @param Object The element
		 *
		 * @return Object The viewBox
		 */
		function _getViewBox(el) {
			var attArray = []
				, viewBox = {};

			attArray = el.getAttribute('viewBox').split(' ');
			viewBox.x = attArray[0];
			viewBox.y = attArray[1];
			viewBox.width = attArray[2];
			viewBox.height = attArray[3];

			return viewBox;
		}

		/**
		 * Create new element with fallback background
		 *
		 * @param Object The viewBox object
		 * @param String The path to the fallback image
		 * @param Object The reference element
		 *
		 * @return Object The replacement element
		 */
		function _createReplacement(viewBox, fallback, ref) {
			var replacement;

			replacement = document.createElement('div');
			replacement.setAttribute('class', ref.getAttribute('class'));
			replacement.style.width = viewBox.width + 'px';
			replacement.style.height = viewBox.height + 'px';
			replacement.style.background = 'transparent url(' + fallback + ') no-repeat -' + viewBox.x + 'px -' + viewBox.y + 'px';

			return replacement
		}

		/**
		 * Hide all elements that have been replaced
		 */
		function _hideSVG() {
			for (var i = 0, len = removeEl.length; i < len; i += 1) {
				removeEl[i].style.display = 'none';
			}
		}

		/**
		 * Check support for inline SVGs.
		 *
		 * Courtesy of Modernizr: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/svg/inline.js
		 *
		 * @return Boolean
		 */
		function _checkSupport() {
			var div = createElement('div');
			div.innerHTML = '<svg/>';
			return (div.firstChild && div.firstChild.namespaceURI) == 'http://www.w3.org/2000/svg';
		}

		return {
			init: function() {
				// Exit if inline svg is supported by the browser
				if (_checkSupport()) {
					return false
				} else {
					_replaceSVG();
				}
			}
		}
	};

}));
<|endoftext|>


<commit_before>require([
    'require',
    'lib/jquery',
    'lib/domReady!',
    'core/init',
    'patterns/toggle',
    'patterns/tooltip'
], function(require) {
    var mapal = require('core/init');
    mapal.registerWidthClass("narrow", 0, 780);
    mapal.registerWidthClass("medium", 0, 1109);
    mapal.registerWidthClass("wide", 1110, null);

    // register our patterns
    // rethink naming once all patterns are migrated to this style
    mapal.passivePatterns.toggle = require('patterns/toggle');
    mapal.passivePatterns.tooltip = require('patterns/tooltip');

    // Register as active pattern to prevent errors on clicks.
    // XXX: hack, what does this do?
    mapal.patterns.tooltip = { execute: function() {} };

    // wait for the DOM to be ready and initialize
    var doc = require('lib/domReady');
    mapal.init();
    mapal.initContent(doc.body);
    $(doc).trigger("setupFinished", doc);
});
<commit_msg>fix domReady require to get document instead of domReady function<commit_after>require([
    'require',
    'lib/jquery',
    'lib/domReady!',
    'core/init',
    'patterns/toggle',
    'patterns/tooltip'
], function(require) {
    var mapal = require('core/init');
    mapal.registerWidthClass("narrow", 0, 780);
    mapal.registerWidthClass("medium", 0, 1109);
    mapal.registerWidthClass("wide", 1110, null);

    // register our patterns
    // rethink naming once all patterns are migrated to this style
    mapal.passivePatterns.toggle = require('patterns/toggle');
    mapal.passivePatterns.tooltip = require('patterns/tooltip');

    // Register as active pattern to prevent errors on clicks.
    // XXX: hack, what does this do?
    mapal.patterns.tooltip = { execute: function() {} };

    // wait for the DOM to be ready and initialize
    var doc = require('lib/domReady!');
    mapal.init();
    mapal.initContent(doc.body);
    $(doc).trigger("setupFinished", doc);
});
<|endoftext|>


<commit_before>import 'whatwg-fetch'

let globalOption = {
    headers: new Headers(),
    mode: "same-origin",
    credentials: "include",
    cache: "reload",
    redirect: "follow",
    referrer: "client",
    timeout: 30000
}
let setOptions = (options) => {
    globalOption = Object.assign({}, globalOption, options)
}

let parseJSON = (response) => {
    try {
        return response.json()
    } catch (e) {
        throw new Error("JSON Parse Error")
    }
}

let checkStatus = (response) => {
    if ((response.status >= 200 && response.status < 300) || response.status == 304) {
        return response
    } else {
        throw new Error(response.statusText)
    }
}

let setGetURL = (url, data = {}) => {
    if (Object.prototype.toString.call(data) !== "[object Object]" || Object.keys(data).length === 0) {
        return url
    }

    let list = []
    for (let key in data) {
        list.push(encodeURIComponent(key) + "=" + encodeURIComponent(data[key]))
    }
    return url + (url.indexOf("?") === -1 ? "?" : "") + list.join("&")
}

let getJSON = (url, data = {}, option = {}) => {
    let fetchOption = Object.assign({}, globalOption, { method: "GET" }, option)
    let fetchURL = setGetURL(url, data)

    return _fetch(fetchURL, fetchOption)
        .then(parseJSON).then(handleFetchPass, handleFetchError)
}

let postJSON = (url, data = {}, option = {}) => {
    let fetchOption = Object.assign({}, globalOption, { method: "POST", body: JSON.stringify(data) }, option)
    let fetchURL = url

    return _fetch(fetchURL, fetchOption)
        .then(parseJSON).then(handleFetchPass, handleFetchError)
}

let putJSON = (url, data = {}, option = {}) => {
    let fetchOption = Object.assign({}, globalOption, { method: "PUT", body: JSON.stringify(data) }, option)
    let fetchURL = url

    return _fetch(fetchURL, fetchOption)
        .then(parseJSON).then(handleFetchPass, handleFetchError)
}

let handleFetchPass = (data) => {
    typeof globalOption.fetchSuccess === "function" && globalOption.fetchSuccess(data)

    return data
}

let handleFetchError = (error) => {
    typeof globalOption.fetchError === "function" && globalOption.fetchError(error)

    throw new Error(error.message)
}

let _fetch = (url, fetchOption) => {
    return new Promise((resolve, reject) => {
        let timer = 0
        let myRequest = new Request(url, fetchOption);

        timer = setTimeout(() => {
            let error = new Error(`${url} timeout`)
            error.fetchOption = fetchOption
            reject(error)
        }, fetchOption.timeout)

        typeof fetchOption.fetchStart === "function" && fetchOption.fetchStart()

        fetch(myRequest).then((response) => {
            clearTimeout(timer)
            response.fetchOption = fetchOption
            resolve(response)
        }, (error) => {
            clearTimeout(timer)
            error.fetchOption = fetchOption
            reject(error)
        })
    })
    .then(checkStatus)
}
// todo
// head delete
// unit test
// global setup bug
// https://zh.wikipedia.org/wiki/%E8%B6%85%E6%96%87%E6%9C%AC%E4%BC%A0%E8%BE%93%E5%8D%8F%E8%AE%AE

export default {
    setOptions,
    getJSON,
    postJSON,
    putJSON
}
<commit_msg>add todo<commit_after>import 'whatwg-fetch'

let globalOption = {
    headers: new Headers(),
    mode: "same-origin",
    credentials: "include",
    cache: "reload",
    redirect: "follow",
    referrer: "client",
    timeout: 30000
}
let setOptions = (options) => {
    globalOption = Object.assign({}, globalOption, options)
}

let parseJSON = (response) => {
    try {
        return response.json()
    } catch (e) {
        throw new Error("JSON Parse Error")
    }
}

let checkStatus = (response) => {
    if ((response.status >= 200 && response.status < 300) || response.status == 304) {
        return response
    } else {
        throw new Error(response.statusText)
    }
}

let setGetURL = (url, data = {}) => {
    if (Object.prototype.toString.call(data) !== "[object Object]" || Object.keys(data).length === 0) {
        return url
    }

    let list = []
    for (let key in data) {
        list.push(encodeURIComponent(key) + "=" + encodeURIComponent(data[key]))
    }
    return url + (url.indexOf("?") === -1 ? "?" : "") + list.join("&")
}

let getJSON = (url, data = {}, option = {}) => {
    let fetchOption = Object.assign({}, globalOption, { method: "GET" }, option)
    let fetchURL = setGetURL(url, data)

    return _fetch(fetchURL, fetchOption)
        .then(parseJSON).then(handleFetchPass, handleFetchError)
}

let postJSON = (url, data = {}, option = {}) => {
    let fetchOption = Object.assign({}, globalOption, { method: "POST", body: JSON.stringify(data) }, option)
    let fetchURL = url

    return _fetch(fetchURL, fetchOption)
        .then(parseJSON).then(handleFetchPass, handleFetchError)
}

let putJSON = (url, data = {}, option = {}) => {
    let fetchOption = Object.assign({}, globalOption, { method: "PUT", body: JSON.stringify(data) }, option)
    let fetchURL = url

    return _fetch(fetchURL, fetchOption)
        .then(parseJSON).then(handleFetchPass, handleFetchError)
}

let handleFetchPass = (data) => {
    typeof globalOption.fetchSuccess === "function" && globalOption.fetchSuccess(data)

    return data
}

let handleFetchError = (error) => {
    typeof globalOption.fetchError === "function" && globalOption.fetchError(error)

    throw new Error(error.message)
}

let _fetch = (url, fetchOption) => {
    return new Promise((resolve, reject) => {
        let timer = 0
        let myRequest = new Request(url, fetchOption);

        timer = setTimeout(() => {
            let error = new Error(`${url} timeout`)
            error.fetchOption = fetchOption
            reject(error)
        }, fetchOption.timeout)

        typeof fetchOption.fetchStart === "function" && fetchOption.fetchStart()

        fetch(myRequest).then((response) => {
            clearTimeout(timer)
            response.fetchOption = fetchOption
            resolve(response)
        }, (error) => {
            clearTimeout(timer)
            error.fetchOption = fetchOption
            reject(error)
        })
    })
    .then(checkStatus)
}
// todo
// head delete jsonp
// unit test
// global setup bug
// https://zh.wikipedia.org/wiki/%E8%B6%85%E6%96%87%E6%9C%AC%E4%BC%A0%E8%BE%93%E5%8D%8F%E8%AE%AE

export default {
    setOptions,
    getJSON,
    postJSON,
    putJSON
}
<|endoftext|>


<commit_before>/* light-i18n main */
/* jshint browser: true */

// Base function.
var i18n = (function(global) {
	"use strict";
	var language = window.navigator.userLanguage || window.navigator.language,
			searchTerms = window.location.search.slice(1).split("&");

	function loadTranslations(language) {
		var url = window.location.protocol + "//" + window.location.host + window.location.pathname + "locales/" + language + "/translation.json",
				xhr;

		console.log("loading translations from: " + url);
		xhr = new XMLHttpRequest();
		xhr.open("GET", url, true);
		xhr.setRequestHeader("Accept", "application/json");
		xhr.setRequestHeader("Accept-Encoding", "UTF-8");

		// TODO add event listeners for error cases
		xhr.onreadystatechange = function() {
			var translationJson;

			if (xhr.readyState === 4) {
				if (xhr.status === 200) {
					try {
						console.log("successfully loaded translations");
						translationJson = JSON.parse(xhr.responseText);
					} catch (e) {
						console.error("could not parse JSON translations", e);
					}

					if (translationJson) {
						searchForTranslationElements(translationJson);
					}

				} else {
					console.log("failed loading translations");
				}
			}
		};
		xhr.send();
	}

	function getTranslation(key, json) {
		var nodes = key.split("."),
				translation = json;

		nodes.forEach(function(node) {
			translation = translation[node];
		});

		return translation;
	}

	function applyTranslation(ele, key, json) {
		if (json !== null) {
			ele.innerHTML = getTranslation(key, json);
		} else {
			console.log("Could not translate website because JSON wasn't loaded yet.");
		}
	}

	function searchForTranslationElements(translationJson) {
		var translationElements = document.querySelectorAll("[i18n]");

		[].forEach.call(translationElements, function(ele) {
			applyTranslation(ele, ele.getAttribute("i18n"), translationJson);
		});
	}

	searchTerms.some(function(searchTerm) {
		if (searchTerm.indexOf("lang=") === 0) {
			language = searchTerm.split("=")[1];
			return true;
		}
	});

	language = language.split("-")[0];
	loadTranslations(language.toLowerCase());

	return true;
})(self);

<commit_msg>Replace XHR with fetch<commit_after>/* light-i18n main */
/* jshint browser: true */

// Base function.
var i18n = (function(global) {
	"use strict";
	var language = window.navigator.userLanguage || window.navigator.language,
			searchTerms = window.location.search.slice(1).split("&");

	function loadTranslations(language) {
		var url = window.location.protocol + "//" + window.location.host + window.location.pathname + "locales/" + language + "/translation.json",
				xhr;

		console.log("loading translations from: " + url);
		return fetch(url, {
            headers: {
                "Accept": "application/json",
                "Accept-Encoding": "UTF-8"
            }
        }).then(function(res) {
            if(res.ok) {
                return res.json();
            }
            // TODO add error object instead of false
            return Promise.reject(false);
        }).then(function(obj) {
			console.log("successfully loaded translations");
			searchForTranslationElements(obj);
		}).catch(function(err) {
            console.error("Error loading translations: %o", err);
        });
	}

	function getTranslation(key, json) {
		var nodes = key.split("."),
				translation = json;

		nodes.forEach(function(node) {
			translation = translation[node];
		});

		return translation;
	}

	function applyTranslation(ele, key, json) {
		if (json !== null) {
			ele.innerHTML = getTranslation(key, json);
		} else {
			console.log("Could not translate website because JSON wasn't loaded yet.");
		}
	}

	function searchForTranslationElements(translationJson) {
		var translationElements = document.querySelectorAll("[i18n]");

		[].forEach.call(translationElements, function(ele) {
			applyTranslation(ele, ele.getAttribute("i18n"), translationJson);
		});
	}

	searchTerms.some(function(searchTerm) {
		if (searchTerm.indexOf("lang=") === 0) {
			language = searchTerm.split("=")[1];
			return true;
		}
	});

	language = language.split("-")[0];
	loadTranslations(language.toLowerCase());

	return true;
})(self);

<|endoftext|>


<commit_before>
export default {
  code: "fa",
  week: {
    dow: 6, // Saturday is the first day of the week.
    doy: 12 // The week that contains Jan 1st is the first week of the year.
  },
  dir: 'rtl',
  buttonText: {
    prev: "قبلی",
    nex: "بعدی",
    today: "امروز",
    month: "ماه",
    week: "هفته",
    day: "روز",
    list: "برنامه"
  },
  weekLabel: "هف",
  allDayText: "تمام روز",
  eventLimitText: function(n) {
    return "بیش از " + n;
  },
  noEventsMessage: "هیچ رویدادی به نمایش"
};
<commit_msg>Update fa.js<commit_after>
export default {
  code: "fa",
  week: {
    dow: 6, // Saturday is the first day of the week.
    doy: 12 // The week that contains Jan 1st is the first week of the year.
  },
  dir: 'rtl',
  buttonText: {
    prev: "قبلی",
    next: "بعدی",
    today: "امروز",
    month: "ماه",
    week: "هفته",
    day: "روز",
    list: "برنامه"
  },
  weekLabel: "هف",
  allDayText: "تمام روز",
  eventLimitText: function(n) {
    return "بیش از " + n;
  },
  noEventsMessage: "هیچ رویدادی به نمایش"
};
<|endoftext|>