<commit_before>import { kea } from 'kea'
import { put, fork } from 'redux-saga/effects'
import { message } from 'antd'
import { LOCATION_CHANGE, push } from 'connected-react-router'

import download from 'downloadjs'

import explorerLogic from 'scenes/explorer/logic'
import connectionsLogic from 'scenes/explorer/connection/logic'

import getMeta from 'lib/explorer/get-meta'
import urlToState from 'lib/explorer/url-to-state'

import delay from 'lib/utils/delay'

import client from 'lib/client'

const resultsService = client.service('results')
const favouritesService = client.service('favourites')

function fetchBlob (params) {
  var qs = document.querySelector('meta[name=csrf-token]')

  const requestParams = {
    endpoint: 'Explorer::Controller',
    method: 'get_results',
    params: params
  }

  return window.fetch('/_kea.json', {
    method: 'post',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      'X-CSRF-Token': qs && qs.content
    },
    body: JSON.stringify(requestParams).replace(/[\u007F-\uFFFF]/g, function (c) { return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).substr(-4) }),
    credentials: 'same-origin'
  })
}

function fetchSvg () {
  // get svg element.
  var svg = document.getElementsByClassName('recharts-surface')[0]

  // get svg source.
  var serializer = new window.XMLSerializer()
  var source = serializer.serializeToString(svg)

  // // add name spaces.
  // if (!source.match(/^<svg[^>]+xmlns="http\:\/\/www\.w3\.org\/2000\/svg"/)){
  //   source = source.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg"')
  // }
  // if (!source.match(/^<svg[^>]+"http\:\/\/www\.w3\.org\/1999\/xlink"/)){
  //   source = source.replace(/^<svg/, '<svg xmlns:xlink="http://www.w3.org/1999/xlink"')
  // }

  // // add xml declaration
  // source = '<?xml version="1.0" standalone="no"?>\r\n' + source

  // convert svg source to URI data scheme.
  return source // 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(source)
}

// function downloadUrl (url) {
//   var downloadLink = document.createElement("a")
//   downloadLink.href = url
//   downloadLink.download = "newesttree.svg"
//   document.body.appendChild(downloadLink)
//   downloadLink.click()
//   document.body.removeChild(downloadLink)
// }

export default kea({
  path: () => ['scenes', 'explorer', 'saga'],

  connect: {
    props: [
      connectionsLogic, [
        'connectionString',
        'connections',
        'structure'
      ]
    ],
    actions: [
      connectionsLogic, [
        'setConnectionId',
      ],
      explorerLogic, [
        'refreshData',
        'setResults',
        'setColumns',
        'addColumn',
        'removeColumnWithIndex',
        'removeColumnsWithPath',
        'setLoading',
        'clearLoading',
        'setFilter',
        'addFilter',
        'addEmptyFilter',
        'removeFilter',
        'removeFiltersByKey',
        'setPagination',
        'setSort',
        'setTransform',
        'openTreeNode',
        'closeTreeNode',
        'urlChanged',
        'clear',
        'digDeeper',
        'setColumnsAndFilter',
        'setGraphTimeFilter',
        'setFacetsColumn',
        'setFacetsCount',
        'setGraphControls',
        'requestExport',
        'setExpandedKeys',

        'addFavouriteRequest',
        'addFavouriteSuccess',
        'removeFavouriteRequest',
        'removeFavouriteSuccess',
        'favouritesLoaded',

        'setGraphTimeGroup'
      ]
    ]
  },

  takeEvery: ({ actions, workers }) => ({
    [LOCATION_CHANGE]: workers.urlToState,
    [actions.digDeeper]: workers.digDeeper
  }),

  takeLatest: ({ actions, workers }) => ({
    [actions.addColumn]: workers.addColumn,

    [actions.clear]: workers.refreshData,
    [actions.urlChanged]: workers.refreshData,
    [actions.setConnectionId]: workers.refreshData,
    [actions.setColumnsAndFilter]: workers.refreshData,
    [actions.setColumns]: workers.refreshData,
    [actions.removeColumnWithIndex]: workers.refreshData,
    [actions.removeColumnsWithPath]: workers.refreshData,
    [actions.refreshData]: workers.refreshData,
    [actions.setFilter]: workers.refreshData,
    [actions.addFilter]: workers.refreshData,
    [actions.addEmptyFilter]: workers.refreshData,
    [actions.removeFilter]: workers.refreshData,
    [actions.removeFiltersByKey]: workers.refreshData,
    [actions.setPagination]: workers.refreshData,
    [actions.setSort]: workers.refreshData,
    [actions.setTransform]: workers.refreshData,
    [actions.setGraphTimeFilter]: workers.refreshData,
    [actions.setFacetsColumn]: workers.refreshData,
    [actions.setFacetsCount]: workers.refreshData,
    [actions.setGraphControls]: workers.refreshData,
    [actions.requestExport]: workers.refreshData,
    [actions.openTreeNode]: workers.refreshData,
    [actions.closeTreeNode]: workers.refreshData,
    [actions.setExpandedKeys]: workers.refreshData,

    [actions.addFavouriteRequest]: workers.addFavouriteRequest,
    [actions.removeFavouriteRequest]: workers.removeFavouriteRequest,

    [actions.setGraphTimeGroup]: workers.setGraphTimeGroup
  }),

  events: ({ actions }) => ({
    beforeMount: () => {
      window.document.title = 'Insights Explorer'
    },
    afterMount: () => {
      actions.urlChanged(urlToState(window.location.search), true)
    }
  }),

  listeners: ({ actions, values }) => ({
    [actions.urlChanged]: ({ connection }) => {
      const { connectionString } = values

      if (connectionString !== connection) {
        const [connectionId, subsetId] = (connection || '').split('--', 2)
        actions.setConnectionId(connectionId, subsetId)
      }

      actions.refreshData(true)
    }
  }),

  start: function * () {
    yield fork(this.workers.loadFavourites)
  },

  workers: {
    loadFavourites: function * (action) {
      const { favouritesLoaded } = this.actions

      const response = yield favouritesService.find()
      yield put(favouritesLoaded(response.data))
    },

    refreshData: function * (action) {
      const { setResults, setPagination, setLoading, clearLoading, openTreeNode, closeTreeNode, setExpandedKeys, requestExport } = this.actions

      if (!action.payload.fromUrl) {
        yield delay(50) // throttle unless coming from an url change
      }

      const {
        url, columns, offsetTarget, offset, limitTarget, limit, sort, filter, graphTimeFilter,
        facetsCount, facetsColumn, exportTitle, graphControls, graph
      } = yield explorerLogic.fetch('url', 'columns', 'offset', 'limit', 'offsetTarget', 'limitTarget', 'sort', 'filter', 'graphTimeFilter', 'facetsCount', 'facetsColumn', 'exportTitle', 'graphControls', 'graph')

      const { connectionString } = yield connectionsLogic.fetch('connectionString')

      // if paginating and fetching what is currently there (horizontal scroll)
      if (action.type === setPagination.toString() && action.payload.offset === offset && action.payload.limit === limit) {
        return
      }

      if (!action.payload.fromUrl && `${window.location.pathname}${window.location.search}` !== url) {
        yield put(push(url))
      }

      if (columns.length > 0) {
        const model = columns[0].split('.')[0].split('!')[0]
        window.document.title = `${model} - Insights Explorer`
      } else {
        window.document.title = 'Insights Explorer'
      }

      if (action.type === openTreeNode.toString() || action.type === closeTreeNode.toString() || action.type === setExpandedKeys.toString()) {
        return // nothing to reload
      }

      if (columns.length > 0) {
        try {
          const params = {
            connection: connectionString || '',

            columns,
            sort,
            filter,

            facetsColumn,
            facetsCount,

            graphTimeFilter,
            graphControls,

            offset: offsetTarget,
            limit: limitTarget
          }

          yield put(setLoading())

          let response = null

          if (action.type === requestExport.toString()) {
            const { format } = action.payload
            response = yield fetchBlob({
              ...params,
              ...(format === 'pdf' && graph.results ? { svg: fetchSvg() } : {}),
              export: format,
              exportTitle: exportTitle
            })

            if (response.ok) {
              const blob = yield response.blob()
              const disposition = response.headers.get('content-disposition') || ''
              const match = disposition.match(/filename="([^"]+)"/)
              download(blob, match[1] || `export.${format}`)
            } else {
              message.error(response.error)
            }
            yield put(clearLoading())
          } else {
            response = yield resultsService.find({ query: params })

            if (response.success) {
              // not asking because of a pagination update
              const resetScrolling = action.type !== setPagination.toString()

              yield put(setResults(response, resetScrolling))
            } else {
              yield put(clearLoading())
              message.error(response.error)
            }
          }
        } catch (e) {
          console.error(e)
          yield put(clearLoading())
          message.error(`Error: ${e.message}`)
        }
      }
    },

    urlToState: function * (action) {
      const { urlChanged } = this.actions
      const { search } = action.payload.location || action.payload

      const urlValues = urlToState(search)

      yield put(urlChanged(urlValues))
    },

    digDeeper: function * (action) {
      const { setColumnsAndFilter } = this.actions

      const { row } = action.payload
      const { results, columns } = yield explorerLogic.fetch('results', 'columns')

      const resultRow = results[row]

      let newFilter = []

      let newColumns = []
      let i = 0

      columns.forEach(column => {
        const [ path, transform, aggregate ] = column.split('!')

        if (aggregate) {
          newColumns.push(path + (transform ? `!${transform}` : ''))
        } else {
          newColumns.push(column)
          if (resultRow[i] === null) {
            newFilter.push({ key: column, value: 'null' })
          } else {
            newFilter.push({ key: column, value: `equals:${resultRow[i]}` })
          }
        }
        i += 1
      })

      yield put(setColumnsAndFilter(newColumns, newFilter))
    },

    addFavouriteRequest: function * (action) {
      const { addFavouriteSuccess } = this.actions
      const { path } = action.payload

      const connectionId = yield explorerLogic.get('connectionId')
      const subsetId = yield explorerLogic.get('subsetId')
      const favourite = yield favouritesService.create({ model: path.split('.')[0], path, connectionId, subsetId })

      if (favourite) {
        yield put(addFavouriteSuccess(path, favourite))
      }
    },

    removeFavouriteRequest: function * (action) {
      const { removeFavouriteSuccess } = this.actions
      const { path } = action.payload

      const favourites = yield explorerLogic.get('favourites')
      const favourite = favourites[path]

      yield favouritesService.remove(favourite._id)

      yield put(removeFavouriteSuccess(path))
    },

    setGraphTimeGroup: function * (action) {
      const { graphTimeGroup } = action.payload
      const { setTransform } = this.actions

      const columns = yield explorerLogic.get('columns')
      const { meta } = yield explorerLogic.get('graph')
      const timeMeta = meta.filter(m => m.type === 'time')[0]

      if (timeMeta) {
        const index = columns.indexOf(timeMeta.column)

        if (index >= 0) {
          yield put(setTransform(index, graphTimeGroup, null))
        }
      }
    },

    addColumn: function * (action) {
      const { refreshData, setFacetsColumn } = this.actions
      const { column } = action.payload

      const columns = yield explorerLogic.get('columns')
      const facetsColumn = yield explorerLogic.get('facetsColumn')

      if (!facetsColumn || columns.indexOf(facetsColumn) < 0) {
        const structure = yield explorerLogic.get('structure')
        const columnMeta = getMeta(column, structure)

        if (columnMeta && columnMeta.type === 'string') {
          yield put(setFacetsColumn(column)) // will trigger refreshData via takeLatest
          return
        }
      }

      yield put(refreshData())
    }
  }
})
<commit_msg>drilldown fix<commit_after>import { kea } from 'kea'
import { put, fork } from 'redux-saga/effects'
import { message } from 'antd'
import { LOCATION_CHANGE, push } from 'connected-react-router'

import download from 'downloadjs'

import explorerLogic from 'scenes/explorer/logic'
import connectionsLogic from 'scenes/explorer/connection/logic'

import getMeta from 'lib/explorer/get-meta'
import urlToState from 'lib/explorer/url-to-state'

import delay from 'lib/utils/delay'

import client from 'lib/client'
import moment from 'moment'

const resultsService = client.service('results')
const favouritesService = client.service('favourites')

function fetchBlob (params) {
  var qs = document.querySelector('meta[name=csrf-token]')

  const requestParams = {
    endpoint: 'Explorer::Controller',
    method: 'get_results',
    params: params
  }

  return window.fetch('/_kea.json', {
    method: 'post',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      'X-CSRF-Token': qs && qs.content
    },
    body: JSON.stringify(requestParams).replace(/[\u007F-\uFFFF]/g, function (c) { return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).substr(-4) }),
    credentials: 'same-origin'
  })
}

function fetchSvg () {
  // get svg element.
  var svg = document.getElementsByClassName('recharts-surface')[0]

  // get svg source.
  var serializer = new window.XMLSerializer()
  var source = serializer.serializeToString(svg)

  // // add name spaces.
  // if (!source.match(/^<svg[^>]+xmlns="http\:\/\/www\.w3\.org\/2000\/svg"/)){
  //   source = source.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg"')
  // }
  // if (!source.match(/^<svg[^>]+"http\:\/\/www\.w3\.org\/1999\/xlink"/)){
  //   source = source.replace(/^<svg/, '<svg xmlns:xlink="http://www.w3.org/1999/xlink"')
  // }

  // // add xml declaration
  // source = '<?xml version="1.0" standalone="no"?>\r\n' + source

  // convert svg source to URI data scheme.
  return source // 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(source)
}

// function downloadUrl (url) {
//   var downloadLink = document.createElement("a")
//   downloadLink.href = url
//   downloadLink.download = "newesttree.svg"
//   document.body.appendChild(downloadLink)
//   downloadLink.click()
//   document.body.removeChild(downloadLink)
// }

export default kea({
  path: () => ['scenes', 'explorer', 'saga'],

  connect: {
    props: [
      connectionsLogic, [
        'connectionString',
        'connections',
        'structure'
      ]
    ],
    actions: [
      connectionsLogic, [
        'setConnectionId',
      ],
      explorerLogic, [
        'refreshData',
        'setResults',
        'setColumns',
        'addColumn',
        'removeColumnWithIndex',
        'removeColumnsWithPath',
        'setLoading',
        'clearLoading',
        'setFilter',
        'addFilter',
        'addEmptyFilter',
        'removeFilter',
        'removeFiltersByKey',
        'setPagination',
        'setSort',
        'setTransform',
        'openTreeNode',
        'closeTreeNode',
        'urlChanged',
        'clear',
        'digDeeper',
        'setColumnsAndFilter',
        'setGraphTimeFilter',
        'setFacetsColumn',
        'setFacetsCount',
        'setGraphControls',
        'requestExport',
        'setExpandedKeys',

        'addFavouriteRequest',
        'addFavouriteSuccess',
        'removeFavouriteRequest',
        'removeFavouriteSuccess',
        'favouritesLoaded',

        'setGraphTimeGroup'
      ]
    ]
  },

  takeEvery: ({ actions, workers }) => ({
    [LOCATION_CHANGE]: workers.urlToState,
    [actions.digDeeper]: workers.digDeeper
  }),

  takeLatest: ({ actions, workers }) => ({
    [actions.addColumn]: workers.addColumn,

    [actions.clear]: workers.refreshData,
    [actions.urlChanged]: workers.refreshData,
    [actions.setConnectionId]: workers.refreshData,
    [actions.setColumnsAndFilter]: workers.refreshData,
    [actions.setColumns]: workers.refreshData,
    [actions.removeColumnWithIndex]: workers.refreshData,
    [actions.removeColumnsWithPath]: workers.refreshData,
    [actions.refreshData]: workers.refreshData,
    [actions.setFilter]: workers.refreshData,
    [actions.addFilter]: workers.refreshData,
    [actions.addEmptyFilter]: workers.refreshData,
    [actions.removeFilter]: workers.refreshData,
    [actions.removeFiltersByKey]: workers.refreshData,
    [actions.setPagination]: workers.refreshData,
    [actions.setSort]: workers.refreshData,
    [actions.setTransform]: workers.refreshData,
    [actions.setGraphTimeFilter]: workers.refreshData,
    [actions.setFacetsColumn]: workers.refreshData,
    [actions.setFacetsCount]: workers.refreshData,
    [actions.setGraphControls]: workers.refreshData,
    [actions.requestExport]: workers.refreshData,
    [actions.openTreeNode]: workers.refreshData,
    [actions.closeTreeNode]: workers.refreshData,
    [actions.setExpandedKeys]: workers.refreshData,

    [actions.addFavouriteRequest]: workers.addFavouriteRequest,
    [actions.removeFavouriteRequest]: workers.removeFavouriteRequest,

    [actions.setGraphTimeGroup]: workers.setGraphTimeGroup
  }),

  events: ({ actions }) => ({
    beforeMount: () => {
      window.document.title = 'Insights Explorer'
    },
    afterMount: () => {
      actions.urlChanged(urlToState(window.location.search), true)
    }
  }),

  listeners: ({ actions, values }) => ({
    [actions.urlChanged]: ({ connection }) => {
      const { connectionString } = values

      if (connectionString !== connection) {
        const [connectionId, subsetId] = (connection || '').split('--', 2)
        actions.setConnectionId(connectionId, subsetId)
      }

      actions.refreshData(true)
    }
  }),

  start: function * () {
    yield fork(this.workers.loadFavourites)
  },

  workers: {
    loadFavourites: function * (action) {
      const { favouritesLoaded } = this.actions

      const response = yield favouritesService.find()
      yield put(favouritesLoaded(response.data))
    },

    refreshData: function * (action) {
      const { setResults, setPagination, setLoading, clearLoading, openTreeNode, closeTreeNode, setExpandedKeys, requestExport } = this.actions

      if (!action.payload.fromUrl) {
        yield delay(50) // throttle unless coming from an url change
      }

      const {
        url, columns, offsetTarget, offset, limitTarget, limit, sort, filter, graphTimeFilter,
        facetsCount, facetsColumn, exportTitle, graphControls, graph
      } = yield explorerLogic.fetch('url', 'columns', 'offset', 'limit', 'offsetTarget', 'limitTarget', 'sort', 'filter', 'graphTimeFilter', 'facetsCount', 'facetsColumn', 'exportTitle', 'graphControls', 'graph')

      const { connectionString } = yield connectionsLogic.fetch('connectionString')

      // if paginating and fetching what is currently there (horizontal scroll)
      if (action.type === setPagination.toString() && action.payload.offset === offset && action.payload.limit === limit) {
        return
      }

      if (!action.payload.fromUrl && `${window.location.pathname}${window.location.search}` !== url) {
        yield put(push(url))
      }

      if (columns.length > 0) {
        const model = columns[0].split('.')[0].split('!')[0]
        window.document.title = `${model} - Insights Explorer`
      } else {
        window.document.title = 'Insights Explorer'
      }

      if (action.type === openTreeNode.toString() || action.type === closeTreeNode.toString() || action.type === setExpandedKeys.toString()) {
        return // nothing to reload
      }

      if (columns.length > 0) {
        try {
          const params = {
            connection: connectionString || '',

            columns,
            sort,
            filter,

            facetsColumn,
            facetsCount,

            graphTimeFilter,
            graphControls,

            offset: offsetTarget,
            limit: limitTarget
          }

          yield put(setLoading())

          let response = null

          if (action.type === requestExport.toString()) {
            const { format } = action.payload
            response = yield fetchBlob({
              ...params,
              ...(format === 'pdf' && graph.results ? { svg: fetchSvg() } : {}),
              export: format,
              exportTitle: exportTitle
            })

            if (response.ok) {
              const blob = yield response.blob()
              const disposition = response.headers.get('content-disposition') || ''
              const match = disposition.match(/filename="([^"]+)"/)
              download(blob, match[1] || `export.${format}`)
            } else {
              message.error(response.error)
            }
            yield put(clearLoading())
          } else {
            response = yield resultsService.find({ query: params })

            if (response.success) {
              // not asking because of a pagination update
              const resetScrolling = action.type !== setPagination.toString()

              yield put(setResults(response, resetScrolling))
            } else {
              yield put(clearLoading())
              message.error(response.error)
            }
          }
        } catch (e) {
          console.error(e)
          yield put(clearLoading())
          message.error(`Error: ${e.message}`)
        }
      }
    },

    urlToState: function * (action) {
      const { urlChanged } = this.actions
      const { search } = action.payload.location || action.payload

      const urlValues = urlToState(search)

      yield put(urlChanged(urlValues))
    },

    digDeeper: function * (action) {
      const { setColumnsAndFilter } = this.actions

      const { row } = action.payload
      const { results, columns, structure } = yield explorerLogic.fetch('results', 'columns', 'structure')

      const resultRow = results[row]

      let newFilter = []

      let newColumns = []
      let i = 0

      columns.forEach(column => {
        const [ path, transform, aggregate ] = column.split('!')

        if (aggregate) {
          newColumns.push(path + (transform ? `!${transform}` : ''))
        } else {
          newColumns.push(column)
          if (resultRow[i] === null || resultRow[i] === undefined) {
            newFilter.push({ key: column, value: 'null' })
          } else {
            const columnMeta = getMeta(column, structure)
            if (resultRow[i] && columnMeta && columnMeta.type === 'time' && transform) {
              const date = moment(resultRow[i]).startOf(transform === 'week' ? 'isoWeek' : transform).format('YYYY-MM-DD')
              newFilter.push({key: column, value: `equals:${date}`})
            } else {
              newFilter.push({key: column, value: `equals:${resultRow[i]}`})
            }
          }
        }
        i += 1
      })

      yield put(setColumnsAndFilter(newColumns, newFilter))
    },

    addFavouriteRequest: function * (action) {
      const { addFavouriteSuccess } = this.actions
      const { path } = action.payload

      const connectionId = yield explorerLogic.get('connectionId')
      const subsetId = yield explorerLogic.get('subsetId')
      const favourite = yield favouritesService.create({ model: path.split('.')[0], path, connectionId, subsetId })

      if (favourite) {
        yield put(addFavouriteSuccess(path, favourite))
      }
    },

    removeFavouriteRequest: function * (action) {
      const { removeFavouriteSuccess } = this.actions
      const { path } = action.payload

      const favourites = yield explorerLogic.get('favourites')
      const favourite = favourites[path]

      yield favouritesService.remove(favourite._id)

      yield put(removeFavouriteSuccess(path))
    },

    setGraphTimeGroup: function * (action) {
      const { graphTimeGroup } = action.payload
      const { setTransform } = this.actions

      const columns = yield explorerLogic.get('columns')
      const { meta } = yield explorerLogic.get('graph')
      const timeMeta = meta.filter(m => m.type === 'time')[0]

      if (timeMeta) {
        const index = columns.indexOf(timeMeta.column)

        if (index >= 0) {
          yield put(setTransform(index, graphTimeGroup, null))
        }
      }
    },

    addColumn: function * (action) {
      const { refreshData, setFacetsColumn } = this.actions
      const { column } = action.payload

      const columns = yield explorerLogic.get('columns')
      const facetsColumn = yield explorerLogic.get('facetsColumn')

      if (!facetsColumn || columns.indexOf(facetsColumn) < 0) {
        const structure = yield explorerLogic.get('structure')
        const columnMeta = getMeta(column, structure)

        if (columnMeta && columnMeta.type === 'string') {
          yield put(setFacetsColumn(column)) // will trigger refreshData via takeLatest
          return
        }
      }

      yield put(refreshData())
    }
  }
})
<|endoftext|>


<commit_before>var mycanvas = document.getElementById('mycanvas');
var ctx = mycanvas.getContext('2d');
var ball = {x:10,y:10}
var gravity = 5;
var force = 30;
var width = 900;
var height = 500;
var gravityModifier = 15;
var gravityMin = .05;
var gravityMax = 20;
var forceModifier = 40;
var reverseGravity;

ctx.fillStyle = 'lightgrey';
ctx.fillRect(0,0,width,height);
ctx.fillStyle = 'black';

var draw = function(){
	ctx.lineTo(ball.x, ball.y);
	ctx.stroke()

	if(ball.x > width){
		ball.x = width;
		force *= -1;
	}
	if(ball.x < 0){
		ball.x = 0
		force *= -1;
	}
	if(ball.y > height - gravity/2){
		ball.y = height;
		gravity *= -.6;
	}
	if(ball.y < 0 + gravity/2){
		ball.y = 0;
		gravity *= -.6;
	}

	force -= force/forceModifier;
	// console.log(force);

	if(force > 0){
		force -= .5;
	} else {
		force += .5;
	}
	ball.x += force;

	console.log(gravity)

	// gravity += 1
	gravity += Math.abs(gravity/gravityModifier) + .1;

	ball.y += gravity;

	// ctx.fillRect(ball.x*ballSize, ball.y*ballSize, ballSize, ballSize);
}

ctx.beginPath();
gameloop = setInterval(draw, 40);

<commit_msg>Smoothed out<commit_after>var mycanvas = document.getElementById('mycanvas');
var ctx = mycanvas.getContext('2d');
var ball = {x:10,y:10}
var gravity = .04;
var force = 2;

var speedX = 0;
var speedY = 0;

var width = 900;
var height = 500;

var gravityModifier = 15;
var gravityMin = .05;
var gravityMax = 20;
var forceModifier = 40;
var reverseGravity;

ctx.fillStyle = 'lightgrey';
ctx.fillRect(0,0,width,height);
ctx.fillStyle = 'black';

var draw = function(){

	if(force != 0){
		speedX += force;
		force = 0;
	}

	if(speedX > 0){
		speedX -= .001;
	} else {
		speedX += .001;
	}

	speedX += force;
	speedY += gravity;

	ball.x += speedX;
	ball.y += speedY;

	if(ball.x > width){
		ball.x = width;
		speedX *= -1;
	}
	if(ball.x < 0){
		ball.x = 0
		speedX *= -1;
	}
	if(ball.y > height){
		ball.y = height;
		speedY *= -.75;
	}
	if(ball.y < 0){
		ball.y = 0;
		speedY *= -.75;
	}

	ctx.lineTo(ball.x, ball.y);
	ctx.stroke()

	// ctx.fillRect(ball.x*ballSize, ball.y*ballSize, ballSize, ballSize);
}

ctx.beginPath();
ctx.lineTo(ball.x, ball.y);
ctx.stroke()
gameloop = setInterval(draw, 5);

<|endoftext|>


<commit_before>var mbaasApi = require('fh-mbaas-api');
var express = require('express');
var mbaasExpress = mbaasApi.mbaasExpress();
var cors = require('cors');

// list the endpoints which you want to make securable here
var securableEndpoints;
// fhlint-begin: securable-endpoints
securableEndpoints = [];
// fhlint-end

var app = express();

// Enable CORS for all requests
app.use(cors());

// Note: the order which we add middleware to Express here is important!
app.use('/sys', mbaasExpress.sys(securableEndpoints));
app.use('/mbaas', mbaasExpress.mbaas);

// allow serving of static files from the public directory
app.use(express.static(__dirname + '/public'));

// Note: important that this is added just before your own Routes
app.use(mbaasExpress.fhmiddleware());

// fhlint-begin: custom-routes
app.use('/cloud', mbaasExpress.cloud(require('./main.js')));
// fhlint-end

// Important that this is last!
app.use(mbaasExpress.errorHandler());

var port = process.env.FH_PORT || process.env.OPENSHIFT_NODEJS_PORT || 8001;
var host = process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1';
var server = app.listen(port, host, function() {
  console.log("App started at: " + new Date() + " on port: " + port);
});
<commit_msg>127.0.0.1 -> 0.0.0.0<commit_after>var mbaasApi = require('fh-mbaas-api');
var express = require('express');
var mbaasExpress = mbaasApi.mbaasExpress();
var cors = require('cors');

// list the endpoints which you want to make securable here
var securableEndpoints;
// fhlint-begin: securable-endpoints
securableEndpoints = [];
// fhlint-end

var app = express();

// Enable CORS for all requests
app.use(cors());

// Note: the order which we add middleware to Express here is important!
app.use('/sys', mbaasExpress.sys(securableEndpoints));
app.use('/mbaas', mbaasExpress.mbaas);

// allow serving of static files from the public directory
app.use(express.static(__dirname + '/public'));

// Note: important that this is added just before your own Routes
app.use(mbaasExpress.fhmiddleware());

// fhlint-begin: custom-routes
app.use('/cloud', mbaasExpress.cloud(require('./main.js')));
// fhlint-end

// Important that this is last!
app.use(mbaasExpress.errorHandler());

var port = process.env.FH_PORT || process.env.OPENSHIFT_NODEJS_PORT || 8001;
var host = process.env.OPENSHIFT_NODEJS_IP || '0.0.0.0';
var server = app.listen(port, host, function() {
  console.log("App started at: " + new Date() + " on port: " + port);
});
<|endoftext|>


<commit_before>// @inheritedComponent ButtonBase

import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import withStyles from '../styles/withStyles';
import ButtonBase from '../ButtonBase';
import StepLabel from '../StepLabel';
import { isMuiElement } from '../utils/reactHelpers';

export const styles = theme => ({
  root: {
    width: '100%',
    padding: `${theme.spacing.unit * 3}px ${theme.spacing.unit * 2}px`,
    margin: `${-theme.spacing.unit * 3}px ${-theme.spacing.unit * 2}px`,
    boxSizing: 'content-box',
  },
  vertical: {
    justifyContent: 'left',
  },
  touchRipple: {
    color: 'rgba(0, 0, 0, 0.3)',
  },
});

function StepButton(props) {
  const {
    active,
    alternativeLabel,
    children,
    classes,
    className: classNameProp,
    completed,
    disabled,
    icon,
    last,
    optional,
    orientation,
    ...other
  } = props;

  const childProps = {
    active,
    alternativeLabel,
    completed,
    disabled,
    icon,
    optional,
    orientation,
  };
  const child = isMuiElement(children, ['StepLabel']) ? (
    React.cloneElement(children, childProps)
  ) : (
    <StepLabel {...childProps}>{children}</StepLabel>
  );

  return (
    <ButtonBase
      disabled={disabled}
      TouchRippleProps={{ className: classes.touchRipple }}
      className={classNames(
        classes.root,
        {
          [classes.vertical]: orientation === 'vertical',
        },
        classNameProp,
      )}
      {...other}
    >
      {child}
    </ButtonBase>
  );
}

StepButton.propTypes = {
  /**
   * @ignore
   * Passed in via `Step` - passed through to `StepLabel`.
   */
  active: PropTypes.bool,
  /**
   * @ignore
   * Set internally by Stepper when it's supplied with the alternativeLabel property.
   */
  alternativeLabel: PropTypes.bool,
  /**
   * Can be a `StepLabel` or a node to place inside `StepLabel` as children.
   */
  children: PropTypes.node,
  /**
   * Override or extend the styles applied to the component.
   * See [CSS API](#css-api) below for more details.
   */
  classes: PropTypes.object.isRequired,
  /**
   * @ignore
   */
  className: PropTypes.string,
  /**
   * @ignore
   * Sets completed styling. Is passed to StepLabel.
   */
  completed: PropTypes.bool,
  /**
   * @ignore
   * Disables the button and sets disabled styling. Is passed to StepLabel.
   */
  disabled: PropTypes.bool,
  /**
   * The icon displayed by the step label.
   */
  icon: PropTypes.node,
  /**
   * @ignore
   */
  last: PropTypes.bool,
  /**
   * The optional node to display.
   */
  optional: PropTypes.node,
  /**
   * @ignore
   */
  orientation: PropTypes.oneOf(['horizontal', 'vertical']),
};

export default withStyles(styles, { name: 'MuiStepButton' })(StepButton);
<commit_msg>[StepButton] Fix IE 11 flexbox (#11814)<commit_after>// @inheritedComponent ButtonBase

import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import withStyles from '../styles/withStyles';
import ButtonBase from '../ButtonBase';
import StepLabel from '../StepLabel';
import { isMuiElement } from '../utils/reactHelpers';

export const styles = theme => ({
  root: {
    width: '100%',
    padding: `${theme.spacing.unit * 3}px ${theme.spacing.unit * 2}px`,
    margin: `${-theme.spacing.unit * 3}px ${-theme.spacing.unit * 2}px`,
    boxSizing: 'content-box',
  },
  vertical: {
    justifyContent: 'flex-start',
  },
  touchRipple: {
    color: 'rgba(0, 0, 0, 0.3)',
  },
});

function StepButton(props) {
  const {
    active,
    alternativeLabel,
    children,
    classes,
    className: classNameProp,
    completed,
    disabled,
    icon,
    last,
    optional,
    orientation,
    ...other
  } = props;

  const childProps = {
    active,
    alternativeLabel,
    completed,
    disabled,
    icon,
    optional,
    orientation,
  };
  const child = isMuiElement(children, ['StepLabel']) ? (
    React.cloneElement(children, childProps)
  ) : (
    <StepLabel {...childProps}>{children}</StepLabel>
  );

  return (
    <ButtonBase
      disabled={disabled}
      TouchRippleProps={{ className: classes.touchRipple }}
      className={classNames(
        classes.root,
        {
          [classes.vertical]: orientation === 'vertical',
        },
        classNameProp,
      )}
      {...other}
    >
      {child}
    </ButtonBase>
  );
}

StepButton.propTypes = {
  /**
   * @ignore
   * Passed in via `Step` - passed through to `StepLabel`.
   */
  active: PropTypes.bool,
  /**
   * @ignore
   * Set internally by Stepper when it's supplied with the alternativeLabel property.
   */
  alternativeLabel: PropTypes.bool,
  /**
   * Can be a `StepLabel` or a node to place inside `StepLabel` as children.
   */
  children: PropTypes.node,
  /**
   * Override or extend the styles applied to the component.
   * See [CSS API](#css-api) below for more details.
   */
  classes: PropTypes.object.isRequired,
  /**
   * @ignore
   */
  className: PropTypes.string,
  /**
   * @ignore
   * Sets completed styling. Is passed to StepLabel.
   */
  completed: PropTypes.bool,
  /**
   * @ignore
   * Disables the button and sets disabled styling. Is passed to StepLabel.
   */
  disabled: PropTypes.bool,
  /**
   * The icon displayed by the step label.
   */
  icon: PropTypes.node,
  /**
   * @ignore
   */
  last: PropTypes.bool,
  /**
   * The optional node to display.
   */
  optional: PropTypes.node,
  /**
   * @ignore
   */
  orientation: PropTypes.oneOf(['horizontal', 'vertical']),
};

export default withStyles(styles, { name: 'MuiStepButton' })(StepButton);
<|endoftext|>


<commit_before>const EventEmitter = require('events').EventEmitter;
const verbose = require('debug')('verbose:mendel:registry');

class MendelRegistry extends EventEmitter {
    constructor(config, cache) {
        super();

        this._mendelCache = cache;

        // Parser can map a type to another type
        this._parserTypeConversion = new Map();

        const {types, transforms} = config;
        this._transforms = transforms;
        this._types = types;
        this._types.forEach(type => {
            if (!type.parser || !type.parserToType) return;
            // TODO better cycle detection: cannot have cycle
            if (type.parserToType === type.name) return;
            this._parserTypeConversion.set(type.name, type.parserToType);
        });
    }

    emit(eventName, entry) {
        if (entry && entry.id) {
            verbose(eventName, entry.id);
        } else if(entry) {
            verbose(eventName, entry);
        } else {
            verbose(eventName);
        }
        super.emit.apply(this, arguments);
    }

    addEntry(filePath) {
        this._mendelCache.addEntry(filePath);
    }

    removeEntry(filePath) {
        if (!this._mendelCache.hasEntry(filePath)) return;
        this._mendelCache.removeEntry(filePath);
    }

    getEntry(filePath) {
        return this._mendelCache.getEntry(filePath);
    }

    hasEntry(filePath) {
        return this._mendelCache.hasEntry(filePath);
    }

    addSource({id, source, deps, map}) {
        if (!this._mendelCache.hasEntry(id)) this._mendelCache.addEntry(id);
        this._mendelCache.setSource(id, source, deps, map);
    }

    addTransformedSource(obj) {
        this.addSource(obj);
    }

    invalidateDepedencies(filePath) {
        // TODO modify entries and its deps recursively
        if (!this._mendelCache.hasEntry(filePath)) return;
    }

    doneEntry(filePath, environment) {
        if (!this._mendelCache.hasEntry(filePath)) return;
        this._mendelCache.doneEntry(filePath, environment);
    }

    setEntryType(entryId, newType) {
        return this._mendelCache.setEntryType(entryId, newType);
    }

    /**
     * @param {String} norm normalizedId
     * @param {Function} dependencyGetter has to return correct normalizedId of dependency
     *     based on environemnt, transform ids, and settings (browser/main).
     * @returns {Array<Entry[]>} In case a dependency have more than one variation
     *   the Entry[] will have length greater than 1.
     */
    getDependencyGraph(norm, dependencyGetter) {
        const visitedEntries = new Map();
        const unvisitedNorms = [norm];

        while (unvisitedNorms.length) {
            const normId = unvisitedNorms.shift();
            if (visitedEntries.has(normId)) continue;
            const entryIds = this._mendelCache.getEntriesByNormId(normId);

            if (!entryIds) continue;

            const entries = entryIds.map(entryId => this.getEntry(entryId));
            entries.forEach(entry => {
                const depNorms = dependencyGetter(entry);
                Array.prototype.push.apply(unvisitedNorms, depNorms);
            });

            visitedEntries.set(normId, entries);
        }

        return Array.from(visitedEntries.values());
    }
}

module.exports = MendelRegistry;
<commit_msg>Defensive code against FS change and removed entries<commit_after>const EventEmitter = require('events').EventEmitter;
const verbose = require('debug')('verbose:mendel:registry');

class MendelRegistry extends EventEmitter {
    constructor(config, cache) {
        super();

        this._mendelCache = cache;

        // Parser can map a type to another type
        this._parserTypeConversion = new Map();

        const {types, transforms} = config;
        this._transforms = transforms;
        this._types = types;
        this._types.forEach(type => {
            if (!type.parser || !type.parserToType) return;
            // TODO better cycle detection: cannot have cycle
            if (type.parserToType === type.name) return;
            this._parserTypeConversion.set(type.name, type.parserToType);
        });
    }

    emit(eventName, entry) {
        if (entry && entry.id) {
            verbose(eventName, entry.id);
        } else if(entry) {
            verbose(eventName, entry);
        } else {
            verbose(eventName);
        }
        super.emit.apply(this, arguments);
    }

    addEntry(filePath) {
        this._mendelCache.addEntry(filePath);
    }

    removeEntry(filePath) {
        if (!this._mendelCache.hasEntry(filePath)) return;
        this._mendelCache.removeEntry(filePath);
    }

    getEntry(filePath) {
        return this._mendelCache.getEntry(filePath);
    }

    hasEntry(filePath) {
        return this._mendelCache.hasEntry(filePath);
    }

    addSource({id, source, deps, map}) {
        if (!this._mendelCache.hasEntry(id)) this._mendelCache.addEntry(id);
        this._mendelCache.setSource(id, source, deps, map);
    }

    addTransformedSource(obj) {
        this.addSource(obj);
    }

    invalidateDepedencies(filePath) {
        // TODO modify entries and its deps recursively
        if (!this._mendelCache.hasEntry(filePath)) return;
    }

    doneEntry(filePath, environment) {
        if (!this._mendelCache.hasEntry(filePath)) return;
        this._mendelCache.doneEntry(filePath, environment);
    }

    setEntryType(entryId, newType) {
        return this._mendelCache.setEntryType(entryId, newType);
    }

    /**
     * @param {String} norm normalizedId
     * @param {Function} dependencyGetter has to return correct normalizedId of dependency
     *     based on environemnt, transform ids, and settings (browser/main).
     * @returns {Array<Entry[]>} In case a dependency have more than one variation
     *   the Entry[] will have length greater than 1.
     */
    getDependencyGraph(norm, dependencyGetter) {
        const visitedEntries = new Map();
        const unvisitedNorms = [norm];

        while (unvisitedNorms.length) {
            const normId = unvisitedNorms.shift();
            if (visitedEntries.has(normId)) continue;
            const entryIds = this._mendelCache.getEntriesByNormId(normId);

            if (!entryIds) continue;

            const entries = entryIds.map(entryId => this.getEntry(entryId));
            entries.filter(Boolean).forEach(entry => {
                const depNorms = dependencyGetter(entry);
                Array.prototype.push.apply(unvisitedNorms, depNorms);
            });

            visitedEntries.set(normId, entries);
        }

        return Array.from(visitedEntries.values());
    }
}

module.exports = MendelRegistry;
<|endoftext|>


<commit_before>/* @flow */

import yaml from 'js-yaml'
import bluebird from 'bluebird'

import {createComposeClient, getDockerHost} from './client'
import {Navy} from '../../navy'
import {execAsync} from '../../util/exec-async'
import {Status as ServiceStatus} from '../../service'

import type {Driver} from '../../driver'
import type {ServiceList} from '../../service'

const fs = bluebird.promisifyAll(require('fs'))

const debug = require('debug')('navy:docker-compose')

function getArgsFromOptions(opts: Object, argMap: Object): Array<string> {
  return Object.keys(opts)
    .map(key => argMap[key])
    .filter(arg => arg)
}

const launchArgMap = {
  noDeps: '--no-deps',
  forceRecreate: '--force-recreate',
}

export default function createDockerComposeDriver(navy: Navy): Driver {
  const {
    exec,
    getCompiledDockerComposePath,
  } = createComposeClient(navy)

  const driver = {
    async launch(services: Array<string>, opts: ?Object = {}): Promise<void> {
      const additionalArgs = []

      debug('Got launch', services, opts)

      if (opts) {
        additionalArgs.push(...getArgsFromOptions(opts, launchArgMap))
        debug('Resolve opts to args', additionalArgs)
      }

      if (!services) {
        services = []
      }

      await exec('up', ['-d', ...additionalArgs, ...services])
    },

    async destroy(): Promise<void> {
      await exec('kill')
      await exec('down', ['-v'])
    },

    async ps(): Promise<ServiceList> {
      const ids = (await exec('ps', ['-q'])).trim().split('\n')

      if (ids.length === 1 && ids[0] === '') return []

      const inspectRaw = await execAsync('docker', ['inspect', ...ids])
      const inspectResult = JSON.parse(inspectRaw)

      return inspectResult.map(service => ({
        id: service.Id,
        name: service.Config.Labels['com.docker.compose.service'],
        image: service.Config.Image,
        status: service.State.Running === true ? ServiceStatus.RUNNING : ServiceStatus.EXITED,
        raw: service,
      }))
    },

    async start(services: ?Array<string>): Promise<void> {
      await exec('start', services)
    },

    async stop(services: ?Array<string>): Promise<void> {
      await exec('stop', services)
    },

    async restart(services: ?Array<string>): Promise<void> {
      await exec('restart', services)
    },

    async kill(services: ?Array<string>): Promise<void> {
      await exec('kill', services)
    },

    async rm(services: ?Array<string>): Promise<void> {
      if (!services) {
        services = []
      }

      await exec('rm', ['-f', '-v', ...services])
    },

    async pull(services: ?Array<string>): Promise<void> {
      await exec('pull', services)
    },

    async host(service: string, index: number = 1): Promise<string> {
      // at the moment, we do not support things like Docker Swarm which might have a
      // different host for different services.
      return getDockerHost()
    },

    async port(service: string, privatePort: number, index: ?number): Promise {
      if (index == null) index = 1

      const output = await exec('port', ['--index=' + index, service, privatePort])

      const port = output.substring(output.lastIndexOf(':') + 1).trim()

      if (port === '') {
        return null
      }

      return Number(port)
    },

    async writeConfig(config: Object): Promise<void> {
      const yamlOut = yaml.dump(config)
      await fs.writeFileAsync(getCompiledDockerComposePath(), yamlOut)

      debug('Wrote docker-compose.tmp.yml', yamlOut)
    },

    async getConfig(): Promise<Object> {
      const output = await exec('config', [], { useOriginalDockerComposeFiles: true, noLog: true })
      const config = yaml.safeLoad(output)

      return config
    },

    async getLaunchedServiceNames(): Promise<Array<string>> {
      const projectName = 'navy' + navy.normalisedName

      const psRaw = await execAsync('docker', [
        'ps',
        '-a',
        `--filter="label=com.docker.compose.project=${projectName}"`,
        '--format',
        '"{{.Label \\"com.docker.compose.service\\"}}"',
      ])

      const names = psRaw.trim().split('\n')

      if (names.length === 1 && names[0].length === 0) return []

      return names
    },

    async getAvailableServiceNames(): Promise<Array<string>> {
      const config = await driver.getConfig()

      return Object.keys(config.services)
    },
  }

  return driver
}
<commit_msg>Stop driver logging on ps<commit_after>/* @flow */

import yaml from 'js-yaml'
import bluebird from 'bluebird'

import {createComposeClient, getDockerHost} from './client'
import {Navy} from '../../navy'
import {execAsync} from '../../util/exec-async'
import {Status as ServiceStatus} from '../../service'

import type {Driver} from '../../driver'
import type {ServiceList} from '../../service'

const fs = bluebird.promisifyAll(require('fs'))

const debug = require('debug')('navy:docker-compose')

function getArgsFromOptions(opts: Object, argMap: Object): Array<string> {
  return Object.keys(opts)
    .map(key => argMap[key])
    .filter(arg => arg)
}

const launchArgMap = {
  noDeps: '--no-deps',
  forceRecreate: '--force-recreate',
}

export default function createDockerComposeDriver(navy: Navy): Driver {
  const {
    exec,
    getCompiledDockerComposePath,
  } = createComposeClient(navy)

  const driver = {
    async launch(services: Array<string>, opts: ?Object = {}): Promise<void> {
      const additionalArgs = []

      debug('Got launch', services, opts)

      if (opts) {
        additionalArgs.push(...getArgsFromOptions(opts, launchArgMap))
        debug('Resolve opts to args', additionalArgs)
      }

      if (!services) {
        services = []
      }

      await exec('up', ['-d', ...additionalArgs, ...services])
    },

    async destroy(): Promise<void> {
      await exec('kill')
      await exec('down', ['-v'])
    },

    async ps(): Promise<ServiceList> {
      const ids = (await exec('ps', ['-q'], { noLog: true })).trim().split('\n')

      if (ids.length === 1 && ids[0] === '') return []

      const inspectRaw = await execAsync('docker', ['inspect', ...ids])
      const inspectResult = JSON.parse(inspectRaw)

      return inspectResult.map(service => ({
        id: service.Id,
        name: service.Config.Labels['com.docker.compose.service'],
        image: service.Config.Image,
        status: service.State.Running === true ? ServiceStatus.RUNNING : ServiceStatus.EXITED,
        raw: service,
      }))
    },

    async start(services: ?Array<string>): Promise<void> {
      await exec('start', services)
    },

    async stop(services: ?Array<string>): Promise<void> {
      await exec('stop', services)
    },

    async restart(services: ?Array<string>): Promise<void> {
      await exec('restart', services)
    },

    async kill(services: ?Array<string>): Promise<void> {
      await exec('kill', services)
    },

    async rm(services: ?Array<string>): Promise<void> {
      if (!services) {
        services = []
      }

      await exec('rm', ['-f', '-v', ...services])
    },

    async pull(services: ?Array<string>): Promise<void> {
      await exec('pull', services)
    },

    async host(service: string, index: number = 1): Promise<string> {
      // at the moment, we do not support things like Docker Swarm which might have a
      // different host for different services.
      return getDockerHost()
    },

    async port(service: string, privatePort: number, index: ?number): Promise {
      if (index == null) index = 1

      const output = await exec('port', ['--index=' + index, service, privatePort])

      const port = output.substring(output.lastIndexOf(':') + 1).trim()

      if (port === '') {
        return null
      }

      return Number(port)
    },

    async writeConfig(config: Object): Promise<void> {
      const yamlOut = yaml.dump(config)
      await fs.writeFileAsync(getCompiledDockerComposePath(), yamlOut)

      debug('Wrote docker-compose.tmp.yml', yamlOut)
    },

    async getConfig(): Promise<Object> {
      const output = await exec('config', [], { useOriginalDockerComposeFiles: true, noLog: true })
      const config = yaml.safeLoad(output)

      return config
    },

    async getLaunchedServiceNames(): Promise<Array<string>> {
      const projectName = 'navy' + navy.normalisedName

      const psRaw = await execAsync('docker', [
        'ps',
        '-a',
        `--filter="label=com.docker.compose.project=${projectName}"`,
        '--format',
        '"{{.Label \\"com.docker.compose.service\\"}}"',
      ])

      const names = psRaw.trim().split('\n')

      if (names.length === 1 && names[0].length === 0) return []

      return names
    },

    async getAvailableServiceNames(): Promise<Array<string>> {
      const config = await driver.getConfig()

      return Object.keys(config.services)
    },
  }

  return driver
}
<|endoftext|>


<commit_before>"use strict";

var assert = require('assert');
var api = require('../api');
var parser = require('../parser');
var fs = require('fs');
var request = require('request');

describe('Api', function(){

  before(function () {
    api.startApi();
  });

  after(function () {
    api.stopApi();
  });

  it('api should be defined', function() {
    assert.notEqual(typeof api, 'undefined');
  });

  it('startApi should be a function', function() {
    assert.equal(typeof api.startApi, 'function');
  });

  /*it('/ should return 200', function(done) {
    this.timeout(20000);
    request("http://localhost:8088/api/v0/", function(error, response, html) {
      assert.equal(response.statusCode, 200);
      done();
    });
  });*/

  it('/deadlines should return 200', function(done) {
    this.timeout(20000);
    request("http://localhost:8088/api/v0/deadlines/", function(error, response, html) {
      assert.equal(response.statusCode, 200);
      done();
    });
  });

  it('/lectures should return 200', function(done) {
    this.timeout(20000);
    request("http://localhost:8088/api/v0/lectures", function(error, response, html) {
      assert.equal(response.statusCode, 200);
      done();
    });
  });
});
<commit_msg>remove timouts<commit_after>"use strict";

var assert = require('assert');
var api = require('../api');
var parser = require('../parser');
var fs = require('fs');
var request = require('request');

describe('Api', function(){

  before(function () {
    api.startApi();
  });

  after(function () {
    api.stopApi();
  });

  it('api should be defined', function() {
    assert.notEqual(typeof api, 'undefined');
  });

  it('startApi should be a function', function() {
    assert.equal(typeof api.startApi, 'function');
  });

  it('/ should return 200', function(done) {
    request("http://localhost:8088/api/v0/", function(error, response, html) {
      assert.equal(response.statusCode, 200);
      done();
    });
  });

  it('/deadlines should return 200', function(done) {
    request("http://localhost:8088/api/v0/deadlines/", function(error, response, html) {
      assert.equal(response.statusCode, 200);
      done();
    });
  });

  it('/lectures should return 200', function(done) {
    request("http://localhost:8088/api/v0/lectures", function(error, response, html) {
      assert.equal(response.statusCode, 200);
      done();
    });
  });
});
<|endoftext|>


<commit_before>var assert = require('assert'),
    when = require('when'),
    Api = require('./../src/api');

describe.only('Api', function(){

  describe('chain', function(){

    var api;

    beforeEach(function(){
      api = new Api();
    });

    it('should push two calls to the stack', function(){
      api.thenGetClipboardContents().then(function(){});
      assert.equal(api.stack.length, 2);
    });

    it('should solve the stack (async)', function(done){
      api
      .then(function(){
        var deferred = when.defer();
        setTimeout(function(){
          deferred.resolve('done');
        }, 500);
        return deferred.promise;
      })
      .then(function(value){
        assert.equal(value, 'done');
        return 1;
      })
      .force(function( one ){
        assert.equal(one, 1);
      })
      .then(done, done);
    });

    it('should solve the stack twice', function(done){
      var i = 0;
      var promise = api
      .then(function(){
        var deferred = when.defer();
        setTimeout(function(){
          deferred.resolve('done');
          i += 1;
        }, 200);
        return deferred.promise;
      });
      promise.force(function(){})
      setTimeout(function(){
        promise.force(function(){
          assert.equal(i, 2)
        }).then(done, done);
      }, 800);
    });

  });

  describe('endpoints', function(){

    var api;

    var dispatcher = function(){
      var stack = [];

      this.replyWith = function(/* args */){
        stack.push( [].slice.call(arguments) );
        return this;
      };

      this.once = function(){
        return this;
      };

      this.then = function( callback ){
        if (callback && stack.length) callback.apply(null, stack.shift());
        return this;
      };

    };

    it('should get the clipboard content', function(done){
      var client = new dispatcher();
      api = new Api( client.replyWith('This is my clipboard') );
      api.thenGetClipboardContents().force(function(clipboard){
        assert.equal('This is my clipboard', clipboard);
      }).then(done, done);
    });

    it('should get the focused window', function(done){
      var client = new dispatcher();
      api = new Api( client.replyWith(99) );
      api.thenGetFocusedWindow().force(function(window){
        assert.equal(window.id, 99);
      }).then(done, done);
    });

    it('should get the window frame', function(done){
      var client = new dispatcher();
      api = new Api( client.replyWith({x: 1, y: 2, w: 3, h: 4}) );
      api
      .then(function(){ return { id: 67 }; })
      .thenGetWindowFrame().force(function(window){
        assert.equal(window.id, 67);
        assert.equal(window.frame.x, 1);
      })
      .then(done, done);
    });

  });

});
<commit_msg>test for set window frame<commit_after>var assert = require('assert'),
    when = require('when'),
    Api = require('./../src/api');

require('when/monitor/console');
describe.only('Api', function(){

  describe('chain', function(){

    var api;

    beforeEach(function(){
      api = new Api();
    });

    it('should push two calls to the stack', function(){
      api.thenGetClipboardContents().then(function(){});
      assert.equal(api.stack.length, 2);
    });

    it('should solve the stack (async)', function(done){
      api
      .then(function(){
        var deferred = when.defer();
        setTimeout(function(){
          deferred.resolve('done');
        }, 500);
        return deferred.promise;
      })
      .then(function(value){
        assert.equal(value, 'done');
        return 1;
      })
      .force(function( one ){
        assert.equal(one, 1);
      })
      .then(done, done);
    });

    it('should solve the stack twice', function(done){
      var i = 0;
      var promise = api
      .then(function(){
        var deferred = when.defer();
        setTimeout(function(){
          deferred.resolve('done');
          i += 1;
        }, 200);
        return deferred.promise;
      });
      promise.force(function(){})
      setTimeout(function(){
        promise.force(function(){
          assert.equal(i, 2)
        }).then(done, done);
      }, 800);
    });

  });

  describe('endpoints', function(){

    var api,
        client;

    var Dispatcher = function(){
      var stack = [];
      var beforeSendCallback;

      this.replyWith = function(/* args */){
        stack.push( [].slice.call(arguments) );
        return this;
      };

      this.interceptMessage = function( func ){
        beforeSendCallback = func;
        return this;
      }

      this.once = function(){
        if (beforeSendCallback) beforeSendCallback.apply(null, arguments);
        return this;
      };

      this.then = function( callback ){
        if (callback && stack.length) callback.apply(null, stack.shift());
        return this;
      };

    };

    beforeEach(function(){
      client = new Dispatcher();
    });

    it('should get the clipboard content', function(done){
      api = new Api( client.replyWith('This is my clipboard') );
      api.thenGetClipboardContents().force(function(clipboard){
        assert.equal('This is my clipboard', clipboard);
      }).then(done, done);
    });

    it('should get the focused window', function(done){
      api = new Api( client.replyWith(99) );
      api.thenGetFocusedWindow().force(function(window){
        assert.equal(window.id, 99);
      }).then(done, done);
    });

    it('should get the window frame', function(done){
      api = new Api( client.replyWith({x: 1, y: 2, w: 3, h: 4}) );
      api
      .then(function(){ return { id: 67 }; })
      .thenGetWindowFrame().force(function(window){
        assert.equal(window.id, 67);
        assert.equal(window.frame.x, 1);
      })
      .then(done, done);
    });

    it('should set the window frame', function(done){
      client.replyWith('OK').interceptMessage(function(id, command, frame){
        assert.equal(id, 78);
        assert.equal(frame.h, 4);
      });
      api = new Api( client );
      api
      .thenSetWindowFrame(function(){
        return {
          id: 78,
          frame: {x: 1, y: 2, w: 3, h: 4}
        };
      })
      .force(done, done);
    });

  });

});
<|endoftext|>


<commit_before>import callOrValue from './callOrValue';

export default function additionalProps(restProps, data) {
  return Object.keys(restProps).reduce((ret, cur) => {
    ret[cur] = callOrValue(restProps[cur], data);
    return ret;
  }, {});
}
<commit_msg>[radial-chart][lint] fix re-assign error in reduce<commit_after>/* eslint no-param-reassign: 0*/
import callOrValue from './callOrValue';

export default function additionalProps(restProps, data) {
  return Object.keys(restProps).reduce((ret, cur) => {
    ret[cur] = callOrValue(restProps[cur], data);
    return ret;
  }, {});
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import themed from 'react-themed'
import autobind from 'autobind-decorator'
import { Button } from '../Button'

@themed(/^ToggleButton/)

export default class ToggleButton extends Component {
  static propTypes = {
    className: PropTypes.string,
    theme: PropTypes.object,
    children: PropTypes.node,
    value: PropTypes.bool,
    onClick: PropTypes.func,
  }

  static defaultProps = {
    theme: {},
    value: false,
  }

  constructor(props) {
    super(props)

    this.state = {
      value: props.value,
    }
  }

  componentWillReceiveProps(nextProps) {
    if (!(this.props.value === nextProps.value)) {
      this.setState({
        value: nextProps.value,
      })
    }
  }

  @autobind
  toggle() {
    const { onClick } = this.props
    const value = !this.state.value
    this.setState({
      value,
    })
    if (onClick) onClick(value)
  }

  render() {
    const {
      className,
      theme,
      children,
      onClick,
      value,
      ...props
    } = this.props

    return (
      <Button
        onClick={this.toggle}
        className={classnames(
          theme.ToggleButton,
          className,
          theme[this.state.value ? 'ToggleButton-on' : 'ToggleButton-off'],
        )}
        data-tid="toggle-button"
        {...props}
      >
        {children}
      </Button>
    )
  }
}
<commit_msg>Fix circular dependency in ToggleButton<commit_after>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import themed from 'react-themed'
import autobind from 'autobind-decorator'
import Button from './Button'

@themed(/^ToggleButton/)

export default class ToggleButton extends Component {
  static propTypes = {
    className: PropTypes.string,
    theme: PropTypes.object,
    children: PropTypes.node,
    value: PropTypes.bool,
    onClick: PropTypes.func,
  }

  static defaultProps = {
    theme: {},
    value: false,
  }

  constructor(props) {
    super(props)

    this.state = {
      value: props.value,
    }
  }

  componentWillReceiveProps(nextProps) {
    if (!(this.props.value === nextProps.value)) {
      this.setState({
        value: nextProps.value,
      })
    }
  }

  @autobind
  toggle() {
    const { onClick } = this.props
    const value = !this.state.value
    this.setState({
      value,
    })
    if (onClick) onClick(value)
  }

  render() {
    const {
      className,
      theme,
      children,
      onClick,
      value,
      ...props
    } = this.props

    return (
      <Button
        onClick={this.toggle}
        className={classnames(
          theme.ToggleButton,
          className,
          theme[this.state.value ? 'ToggleButton-on' : 'ToggleButton-off'],
        )}
        data-tid="toggle-button"
        {...props}
      >
        {children}
      </Button>
    )
  }
}
<|endoftext|>


<commit_before>import { isArray } from 'lodash';

function resolveRowKey({ rowData, rowIndex, rowKey }) {
  if (typeof rowKey === 'function') {
    return `${rowKey({ rowData, rowIndex })}-row`;
  } else if (process.env.NODE_ENV !== 'production') {
    // Arrays cannot have rowKeys by definition so we have to go by index there.
    if (!isArray(rowData) && !rowData[rowKey]) {
      console.warn( // eslint-disable-line no-console
        'Table.Body - Missing valid rowKey!',
        rowData,
        rowKey
      );
    }
  }

  if (rowData[rowKey] === 0) {
    return `${rowData[rowKey]}-row`;
  }

  return `${rowData[rowKey] || rowIndex}-row`;
}

export default resolveRowKey;
<commit_msg>fix: rowKey could be 0<commit_after>import { isArray } from 'lodash';

function resolveRowKey({ rowData, rowIndex, rowKey }) {
  if (typeof rowKey === 'function') {
    return `${rowKey({ rowData, rowIndex })}-row`;
  } else if (process.env.NODE_ENV !== 'production') {
    // Arrays cannot have rowKeys by definition so we have to go by index there.
    if (!isArray(rowData) && rowData[rowKey] === undefined) {
      console.warn( // eslint-disable-line no-console
        'Table.Body - Missing valid rowKey!',
        rowData,
        rowKey
      );
    }
  }

  if (rowData[rowKey] === 0) {
    return `${rowData[rowKey]}-row`;
  }

  return `${rowData[rowKey] || rowIndex}-row`;
}

export default resolveRowKey;
<|endoftext|>


<commit_before>/**
 * @package assets
 */

(function($) {

	/**
	 * Selectable plugin
	 */
 	$.fn.symphonySelectable = function(custom_settings) {
		var objects = this;
		var settings = {
			items: 'tbody tr',
			handles: 'td'
		};

		$.extend(settings, custom_settings);

	/*-----------------------------------------------------------------------*/

		// Make selectable
		objects.addClass('selectable');

		// Process selections
		objects.delegate(settings.items, 'click', function(event) {
			var item = $(this),
				items = item.siblings().andSelf(),
				selection, first, last;

			// Range selection
			if((event.shiftKey) && items.filter('.selected').size() > 0) {

				// Select upwards
				if(item.prevAll().filter('.selected').size() > 0) {
					first = items.filter('.selected:first').index();
					last = item.index() + 1;
				}

				// Select downwards
				else {
					first = item.index();
					last = items.filter('.selected:last').index() + 1;
				}

				// Get selection
				selection = items.slice(first, last);

				// Deselect items outside the selection range
				items.filter('.selected').not(selection).removeClass('selected').trigger('deselect');

				// Select range
				selection.addClass('selected').trigger('select');
			}

			// Single selection
			else {

				// Press meta key to adjust current range, otherwise the selection will be removed
				if(!event.metaKey) {
					items.not(item).filter('.selected').removeClass('selected').trigger('deselect');
				}

				// Toggle selection
				item.toggleClass('selected');

				// Fire event
				if(item.is('.selected')) {
					item.trigger('select');
				}
				else {
					item.trigger('deselect');
				}
			}

		});

		// Handle highlighting conflicts between orderable and selectable items
		objects.find(settings.handles).bind('mousedown', function(event) {
			var object = $(this).parents(objects[0].tagName).addClass('selecting');
			window.setTimeout(function() {
			    object.removeClass('selecting');
			}, 50);
		});

		// Remove all selections by doubleclicking the body
		$('body').bind('dblclick', function() {
			objects.find(settings.items).removeClass('selected');
		});

		// Return objects
		return objects;

	};

})(jQuery.noConflict());
<commit_msg>Namespace selectable click event<commit_after>/**
 * @package assets
 */

(function($) {

	/**
	 * Selectable plugin
	 */
 	$.fn.symphonySelectable = function(custom_settings) {
		var objects = this;
		var settings = {
			items: 'tbody tr',
			handles: 'td'
		};

		$.extend(settings, custom_settings);

	/*-----------------------------------------------------------------------*/

		// Make selectable
		objects.addClass('selectable');

		// Process selections
		objects.delegate(settings.items, 'click.symSelectable', function(event) {
			var item = $(this),
				items = item.siblings().andSelf(),
				selection, first, last;

			// Range selection
			if((event.shiftKey) && items.filter('.selected').size() > 0) {

				// Select upwards
				if(item.prevAll().filter('.selected').size() > 0) {
					first = items.filter('.selected:first').index();
					last = item.index() + 1;
				}

				// Select downwards
				else {
					first = item.index();
					last = items.filter('.selected:last').index() + 1;
				}

				// Get selection
				selection = items.slice(first, last);

				// Deselect items outside the selection range
				items.filter('.selected').not(selection).removeClass('selected').trigger('deselect');

				// Select range
				selection.addClass('selected').trigger('select');
			}

			// Single selection
			else {

				// Press meta key to adjust current range, otherwise the selection will be removed
				if(!event.metaKey) {
					items.not(item).filter('.selected').removeClass('selected').trigger('deselect');
				}

				// Toggle selection
				item.toggleClass('selected');

				// Fire event
				if(item.is('.selected')) {
					item.trigger('select');
				}
				else {
					item.trigger('deselect');
				}
			}

		});

		// Handle highlighting conflicts between orderable and selectable items
		objects.find(settings.handles).bind('mousedown', function(event) {
			var object = $(this).parents(objects[0].tagName).addClass('selecting');
			window.setTimeout(function() {
			    object.removeClass('selecting');
			}, 50);
		});

		// Remove all selections by doubleclicking the body
		$('body').bind('dblclick', function() {
			objects.find(settings.items).removeClass('selected');
		});

		// Return objects
		return objects;

	};

})(jQuery.noConflict());
<|endoftext|>


<commit_before>// Initialize app
var myApp = new Framework7();

// If we need to use custom DOM library, let's save it to $$ variable:
var $$ = Dom7;

// Add view
var mainView = myApp.addView('.view-main', {
    // Because we want to use dynamic navbar, we need to enable it for this view:
    dynamicNavbar: true
});

// Handle Cordova Device Ready Event
$$(document).on('deviceready', function() {
    console.log("Device is ready!");
});

var userLoggedIn=false;

checkLogin();

function checkLogin(){
	 try{
           //var storedData = window.localStorage['baklava7-'+ '001'];
          if(!userLoggedIn) {
              //do your ajax login request here
              // if successful do your login redirect
                 mainView.router.loadPage({url:'login.html', ignoreCache:true, reload:true });

           }
       }catch(e){
	   }
}

// Now we need to run the code that will be executed only for About page.

// Option 1. Using page callback for page (for "about" page in this case) (recommended way):
myApp.onPageInit('about', function (page) {

});

// Option 2. Using one 'pageInit' event handler for all pages:
$$(document).on('pageInit', function (e) {
    // Get page data from event data
    var page = e.detail.page;

	if(!userLoggedIn) {
		return;
	}

    if (page.name === 'about') {
        // Following code will be executed for page with data-page attribute equal to "about"
        myApp.alert('Here comes about page');
    }
});

function loginClick(){
	userLoggedIn=true;
	mainView.router.loadPage({url:'index.html', ignoreCache:true, reload:true });
}

var calendarBirthday = myApp.calendar({
    input: '#calendarBirthday',
});

var postCodeSearch = myApp.autocomplete({
    input: '#autocomplete-dropdown-ajax',
    openIn: 'dropdown',
    preloader: true, //enable preloader
    valueProperty: 'id', //object's "value" property name
    textProperty: 'name', //object's "text" property name
    limit: 8, //limit to 8 results
    dropdownPlaceholderText: '35394 Giessen"',
    expandInput: true, // expand input
    source: function (autocomplete, query, render) {
        var results = [];
        if (query.length === 0) {
            render(results);
            return;
        }
        // Show Preloader
        autocomplete.showPreloader();
        // Do Ajax request to Autocomplete data
        $$.ajax({
            url: 'autocomplete-languages.json',
            method: 'GET',
            dataType: 'json',
            //send "query" to server. Useful in case you generate response dynamically
            data: {
                query: query
            },
            success: function (data) {
                // Find matched items
                for (var i = 0; i < data.length; i++) {
                    if (data[i].name.toLowerCase().indexOf(query.toLowerCase()) >= 0) results.push(data[i]);
                }
                // Hide Preoloader
                autocomplete.hidePreloader();
                // Render items by passing array with result items
                render(results);
            }
        });
    }
});
<commit_msg>swipepanel<commit_after>// Initialize app
var myApp = new Framework7({
        swipePanel: 'left'
        // ... other parameters
}
);

// If we need to use custom DOM library, let's save it to $$ variable:
var $$ = Dom7;

// Add view
var mainView = myApp.addView('.view-main', {
    // Because we want to use dynamic navbar, we need to enable it for this view:
    dynamicNavbar: true
});

// Handle Cordova Device Ready Event
$$(document).on('deviceready', function() {
    console.log("Device is ready!");
});

var userLoggedIn=false;

checkLogin();

function checkLogin(){
	 try{
           //var storedData = window.localStorage['baklava7-'+ '001'];
          if(!userLoggedIn) {
              //do your ajax login request here
              // if successful do your login redirect
                 mainView.router.loadPage({url:'login.html', ignoreCache:true, reload:true });

           }
       }catch(e){
	   }
}

// Now we need to run the code that will be executed only for About page.

// Option 1. Using page callback for page (for "about" page in this case) (recommended way):
myApp.onPageInit('about', function (page) {

});

// Option 2. Using one 'pageInit' event handler for all pages:
$$(document).on('pageInit', function (e) {
    // Get page data from event data
    var page = e.detail.page;

	if(!userLoggedIn) {
		return;
	}

    if (page.name === 'about') {
        // Following code will be executed for page with data-page attribute equal to "about"
        myApp.alert('Here comes about page');
    }
});

function loginClick(){
	userLoggedIn=true;
	mainView.router.loadPage({url:'index.html', ignoreCache:true, reload:true });
}

var calendarBirthday = myApp.calendar({
    input: '#calendarBirthday',
});

var postCodeSearch = myApp.autocomplete({
    input: '#autocomplete-dropdown-ajax',
    openIn: 'dropdown',
    preloader: true, //enable preloader
    valueProperty: 'id', //object's "value" property name
    textProperty: 'name', //object's "text" property name
    limit: 8, //limit to 8 results
    dropdownPlaceholderText: '35394 Giessen"',
    expandInput: true, // expand input
    source: function (autocomplete, query, render) {
        var results = [];
        if (query.length === 0) {
            render(results);
            return;
        }
        // Show Preloader
        autocomplete.showPreloader();
        // Do Ajax request to Autocomplete data
        $$.ajax({
            url: 'autocomplete-languages.json',
            method: 'GET',
            dataType: 'json',
            //send "query" to server. Useful in case you generate response dynamically
            data: {
                query: query
            },
            success: function (data) {
                // Find matched items
                for (var i = 0; i < data.length; i++) {
                    if (data[i].name.toLowerCase().indexOf(query.toLowerCase()) >= 0) results.push(data[i]);
                }
                // Hide Preoloader
                autocomplete.hidePreloader();
                // Render items by passing array with result items
                render(results);
            }
        });
    }
});
<|endoftext|>


<commit_before>// A global callback for youtube... that makes me angry
var onYouTubePlayerAPIReady = function() {

  onYouTubePlayerAPIReady.ready = true;
  for ( var i = 0; i < onYouTubePlayerAPIReady.waiting.length; i++ ) {
    onYouTubePlayerAPIReady.waiting[ i ]();
  }
};

onYouTubePlayerAPIReady.waiting = [];

Popcorn.getScript( "http://www.youtube.com/player_api" );

Popcorn.player( "youtube", {
  _canPlayType: function( nodeName, url ) {

    return (/(?:http:\/\/www\.|http:\/\/|www\.|\.|^)(youtu)/).test( url ) && nodeName.toLowerCase() !== "video";
  },
  _setup: function( options ) {

    var media = this,
        autoPlay = false,
        container = document.createElement( "div" ),
        currentTime = 0,
        paused = true,
        seekTime = 0,
        firstGo = true,
        seeking = false,
        fragmentStart = 0,

        // state code for volume changed polling
        lastMuted = false,
        lastVolume = 100,
        playerQueue = Popcorn.player.playerQueue();

    var createProperties = function() {

      Popcorn.player.defineProperty( media, "currentTime", {
        set: function( val ) {

          if ( options.destroyed ) {
            return;
          }

          seeking = true;
          // make sure val is a number
          currentTime = Math.round( +val * 100 ) / 100;
        },
        get: function() {

          return currentTime;
        }
      });

      Popcorn.player.defineProperty( media, "paused", {
        get: function() {

          return paused;
        }
      });

      Popcorn.player.defineProperty( media, "muted", {
        set: function( val ) {

          if ( options.destroyed ) {

            return val;
          }

          if ( options.youtubeObject.isMuted() !== val ) {

            if ( val ) {

              options.youtubeObject.mute();
            } else {

              options.youtubeObject.unMute();
            }

            lastMuted = options.youtubeObject.isMuted();
            media.dispatchEvent( "volumechange" );
          }

          return options.youtubeObject.isMuted();
        },
        get: function() {

          if ( options.destroyed ) {

            return 0;
          }

          return options.youtubeObject.isMuted();
        }
      });

      Popcorn.player.defineProperty( media, "volume", {
        set: function( val ) {

          if ( options.destroyed ) {

            return val;
          }

          if ( options.youtubeObject.getVolume() / 100 !== val ) {

            options.youtubeObject.setVolume( val * 100 );
            lastVolume = options.youtubeObject.getVolume();
            media.dispatchEvent( "volumechange" );
          }

          return options.youtubeObject.getVolume() / 100;
        },
        get: function() {

          if ( options.destroyed ) {

            return 0;
          }

          return options.youtubeObject.getVolume() / 100;
        }
      });

      media.play = function() {

        if ( options.destroyed ) {

          return;
        }

        paused = false;
        playerQueue.add(function() {

          if ( options.youtubeObject.getPlayerState() !== 1 ) {

            seeking = false;
            options.youtubeObject.playVideo();
          } else {
            playerQueue.next();
          }
        });
      };

      media.pause = function() {

        if ( options.destroyed ) {

          return;
        }

        paused = true;
        playerQueue.add(function() {

          if ( options.youtubeObject.getPlayerState() !== 2 ) {

            options.youtubeObject.pauseVideo();
          } else {
            playerQueue.next();
          }
        });
      };
    };

    container.id = media.id + Popcorn.guid();
    options._container = container;
    media.appendChild( container );

    var youtubeInit = function() {

      var src, width, height, originalStyle, query;

      var timeUpdate = function() {

        if ( options.destroyed ) {
          return;
        }

        if ( !seeking ) {
          currentTime = options.youtubeObject.getCurrentTime();
          media.dispatchEvent( "timeupdate" );
        } else if ( currentTime === options.youtubeObject.getCurrentTime() ) {

          seeking = false;
          media.dispatchEvent( "seeked" );
          media.dispatchEvent( "timeupdate" );
        } else {

          // keep trying the seek until it is right.
          options.youtubeObject.seekTo( currentTime );
        }
        setTimeout( timeUpdate, 250 );
      };

      options.controls = +options.controls === 0 || +options.controls === 1 ? options.controls : 1;
      options.annotations = +options.annotations === 1 || +options.annotations === 3 ? options.annotations : 1;

      src = /^.*(?:\/|v=)(.{11})/.exec( media.src )[ 1 ];

      query = ( media.src.split( "?" )[ 1 ] || "" )
                         .replace( /v=.{11}/, "" );
      query = query.replace( /&t=(?:(\d+)m)?(?:(\d+)s)?/, function( all, minutes, seconds ) {

        // Make sure we have real zeros
        minutes = minutes | 0; // bit-wise OR
        seconds = seconds | 0; // bit-wise OR

        fragmentStart = ( +seconds + ( minutes * 60 ) );
        return "";
      });
      query = query.replace( /&start=(\d+)?/, function( all, seconds ) {

        // Make sure we have real zeros
        seconds = seconds | 0; // bit-wise OR

        fragmentStart = seconds;
        return "";
      });

      autoPlay = ( /autoplay=1/.test( query ) );

      // cache original display property so it can be reapplied
      originalStyle = media.style.display;
      media.style.display = "inline";

      // setting youtube player's height and width, min 640 x 390,
      // anything smaller, and the player reports incorrect states.
      height = media.clientHeight >= 390 ? "" + media.clientHeight : "390";
      width = media.clientWidth >= 640 ? "" + media.clientWidth : "640";

      media.style.display = "block";

      options.youtubeObject = new YT.Player( container.id, {
        height: height,
        width: width,
        videoId: src,
        events: {
          "onReady": function(){

            // pulling initial volume states form baseplayer
            lastVolume = media.volume;
            lastMuted = media.muted;

            media.duration = options.youtubeObject.getDuration();

            media.dispatchEvent( "durationchange" );
            volumeupdate();

            // pulling initial paused state from autoplay or the baseplayer
            // also need to explicitly set to paused otherwise.
            if ( autoPlay || !media.paused ) {
              paused = false;
            }

            createProperties();
            options.youtubeObject.playVideo();

            if ( paused ) {
              options.youtubeObject.pauseVideo();
            }

            media.currentTime = fragmentStart;

            media.dispatchEvent( "loadedmetadata" );
            media.dispatchEvent( "loadeddata" );
            media.readyState = 4;

            timeUpdate();
            media.dispatchEvent( "canplaythrough" );
          },
          "onStateChange": function( state ){

            if ( options.destroyed || state.data === -1 ) {
              return;
            }

            // state.data === 2 is for pause events
            // state.data === 1 is for play events
            if ( state.data === 2 ) {

              paused = true;
              media.dispatchEvent( "pause" );
              playerQueue.next();
            } else if ( state.data === 1 ) {
              paused = false;
              media.dispatchEvent( "play" );
              media.dispatchEvent( "playing" );
              playerQueue.next();
            } else if ( state.data === 0 ) {
              media.dispatchEvent( "ended" );
            }
          },
          "onError": function( error ) {

            if ( [ 2, 100, 101, 150 ].indexOf( error.data ) !== -1 ) {
              media.error = {
                customCode: error.data
              };
              media.dispatchEvent( "error" );
            }
          }
        }
      });

      var volumeupdate = function() {

        if ( options.destroyed ) {

          return;
        }

        if ( lastMuted !== options.youtubeObject.isMuted() ) {

          lastMuted = options.youtubeObject.isMuted();
          media.dispatchEvent( "volumechange" );
        }

        if ( lastVolume !== options.youtubeObject.getVolume() ) {

          lastVolume = options.youtubeObject.getVolume();
          media.dispatchEvent( "volumechange" );
        }

        setTimeout( volumeupdate, 250 );
      };
    };

    if ( onYouTubePlayerAPIReady.ready ) {

      youtubeInit();
    } else {

      onYouTubePlayerAPIReady.waiting.push( youtubeInit );
    }
  },
  _teardown: function( options ) {

    options.destroyed = true;

    var youtubeObject = options.youtubeObject;
    if( youtubeObject ){
      youtubeObject.stopVideo();
     // youtubeObject.clearVideo();
    }

    this.removeChild( document.getElementById( options._container.id ) );
  }
});
<commit_msg>minor fixes<commit_after>// A global callback for youtube... that makes me angry
var onYouTubePlayerAPIReady = function() {

  onYouTubePlayerAPIReady.ready = true;
  for ( var i = 0; i < onYouTubePlayerAPIReady.waiting.length; i++ ) {
    onYouTubePlayerAPIReady.waiting[ i ]();
  }
};

onYouTubePlayerAPIReady.waiting = [];

Popcorn.getScript( "http://www.youtube.com/player_api" );

Popcorn.player( "youtube", {
  _canPlayType: function( nodeName, url ) {

    return (/(?:http:\/\/www\.|http:\/\/|www\.|\.|^)(youtu)/).test( url ) && nodeName.toLowerCase() !== "video";
  },
  _setup: function( options ) {

    var media = this,
        autoPlay = false,
        container = document.createElement( "div" ),
        currentTime = 0,
        paused = true,
        seekTime = 0,
        firstGo = true,
        seeking = false,
        fragmentStart = 0,

        // state code for volume changed polling
        lastMuted = false,
        lastVolume = 100,
        playerQueue = Popcorn.player.playerQueue();

    var createProperties = function() {

      Popcorn.player.defineProperty( media, "currentTime", {
        set: function( val ) {

          if ( options.destroyed ) {
            return;
          }

          seeking = true;
          // make sure val is a number
          currentTime = Math.round( +val * 100 ) / 100;
        },
        get: function() {

          return currentTime;
        }
      });

      Popcorn.player.defineProperty( media, "paused", {
        get: function() {

          return paused;
        }
      });

      Popcorn.player.defineProperty( media, "muted", {
        set: function( val ) {

          if ( options.destroyed ) {

            return val;
          }

          if ( options.youtubeObject.isMuted() !== val ) {

            if ( val ) {

              options.youtubeObject.mute();
            } else {

              options.youtubeObject.unMute();
            }

            lastMuted = options.youtubeObject.isMuted();
            media.dispatchEvent( "volumechange" );
          }

          return options.youtubeObject.isMuted();
        },
        get: function() {

          if ( options.destroyed ) {

            return 0;
          }

          return options.youtubeObject.isMuted();
        }
      });

      Popcorn.player.defineProperty( media, "volume", {
        set: function( val ) {

          if ( options.destroyed ) {

            return val;
          }

          if ( options.youtubeObject.getVolume() / 100 !== val ) {

            options.youtubeObject.setVolume( val * 100 );
            lastVolume = options.youtubeObject.getVolume();
            media.dispatchEvent( "volumechange" );
          }

          return options.youtubeObject.getVolume() / 100;
        },
        get: function() {

          if ( options.destroyed ) {

            return 0;
          }

          return options.youtubeObject.getVolume() / 100;
        }
      });

      media.play = function() {

        if ( options.destroyed ) {

          return;
        }

        paused = false;
        playerQueue.add(function() {

          if ( options.youtubeObject.getPlayerState() !== 1 ) {

            seeking = false;
            options.youtubeObject.playVideo();
          } else {
            playerQueue.next();
          }
        });
      };

      media.pause = function() {

        if ( options.destroyed ) {

          return;
        }

        paused = true;
        playerQueue.add(function() {

          if ( options.youtubeObject.getPlayerState() !== 2 ) {

            options.youtubeObject.pauseVideo();
          } else {
            playerQueue.next();
          }
        });
      };
    };

    container.id = media.id + Popcorn.guid();
    options._container = container;
    media.appendChild( container );

    var youtubeInit = function() {

      var src, width, height, originalStyle, query;

      var timeUpdate = function() {

        if ( options.destroyed ) {
          return;
        }

        if ( !seeking ) {
          currentTime = options.youtubeObject.getCurrentTime();
          media.dispatchEvent( "timeupdate" );
        } else if ( currentTime === options.youtubeObject.getCurrentTime() ) {

          seeking = false;
          media.dispatchEvent( "seeked" );
          media.dispatchEvent( "timeupdate" );
        } else {

          // keep trying the seek until it is right.
          options.youtubeObject.seekTo( currentTime );
        }
        setTimeout( timeUpdate, 250 );
      };

      options.controls = +options.controls === 0 || +options.controls === 1 ? options.controls : 1;
      options.annotations = +options.annotations === 1 || +options.annotations === 3 ? options.annotations : 1;

      src = /^.*(?:\/|v=)(.{11})/.exec( media.src )[ 1 ];

      query = ( media.src.split( "?" )[ 1 ] || "" )
                         .replace( /v=.{11}/, "" );
      query = query.replace( /&t=(?:(\d+)m)?(?:(\d+)s)?/, function( all, minutes, seconds ) {

        // Make sure we have real zeros
        minutes = minutes | 0; // bit-wise OR
        seconds = seconds | 0; // bit-wise OR

        fragmentStart = ( +seconds + ( minutes * 60 ) );
        return "";
      });
      query = query.replace( /&start=(\d+)?/, function( all, seconds ) {

        // Make sure we have real zeros
        seconds = seconds | 0; // bit-wise OR

        fragmentStart = seconds;
        return "";
      });

      autoPlay = ( /autoplay=1/.test( query ) );

      // cache original display property so it can be reapplied
      originalStyle = media.style.display;
      media.style.display = "inline";

      // setting youtube player's height and width, min 640 x 390,
      // anything smaller, and the player reports incorrect states.
      height = media.clientHeight >= 390 ? "" + media.clientHeight : "390";
      width = media.clientWidth >= 640 ? "" + media.clientWidth : "640";

      media.style.display = originalStyle;

      options.youtubeObject = new YT.Player( container.id, {
        height: height,
        width: width,
        videoId: src,
        events: {
          "onReady": function(){

            // pulling initial volume states form baseplayer
            lastVolume = media.volume;
            lastMuted = media.muted;

            media.duration = options.youtubeObject.getDuration();

            media.dispatchEvent( "durationchange" );
            volumeupdate();

            // pulling initial paused state from autoplay or the baseplayer
            // also need to explicitly set to paused otherwise.
            if ( autoPlay || !media.paused ) {
              paused = false;
            }

            createProperties();
            options.youtubeObject.playVideo();

            if ( paused ) {
              options.youtubeObject.pauseVideo();
            }

            media.currentTime = fragmentStart;

            media.dispatchEvent( "loadedmetadata" );
            media.dispatchEvent( "loadeddata" );
            media.readyState = 4;

            timeUpdate();
            media.dispatchEvent( "canplaythrough" );
          },
          "onStateChange": function( state ){

            if ( options.destroyed || state.data === -1 ) {
              return;
            }

            // state.data === 2 is for pause events
            // state.data === 1 is for play events
            if ( state.data === 2 ) {

              paused = true;
              media.dispatchEvent( "pause" );
              playerQueue.next();
            } else if ( state.data === 1 ) {
              paused = false;
              media.dispatchEvent( "play" );
              media.dispatchEvent( "playing" );
              playerQueue.next();
            } else if ( state.data === 0 ) {
              media.dispatchEvent( "ended" );
            }
          },
          "onError": function( error ) {

            if ( [ 2, 100, 101, 150 ].indexOf( error.data ) !== -1 ) {
              media.error = {
                customCode: error.data
              };
              media.dispatchEvent( "error" );
            }
          }
        }
      });

      var volumeupdate = function() {

        if ( options.destroyed ) {

          return;
        }

        if ( lastMuted !== options.youtubeObject.isMuted() ) {

          lastMuted = options.youtubeObject.isMuted();
          media.dispatchEvent( "volumechange" );
        }

        if ( lastVolume !== options.youtubeObject.getVolume() ) {

          lastVolume = options.youtubeObject.getVolume();
          media.dispatchEvent( "volumechange" );
        }

        setTimeout( volumeupdate, 250 );
      };
    };

    if ( onYouTubePlayerAPIReady.ready ) {

      youtubeInit();
    } else {

      onYouTubePlayerAPIReady.waiting.push( youtubeInit );
    }
  },
  _teardown: function( options ) {

    options.destroyed = true;

    var youtubeObject = options.youtubeObject;
    if( youtubeObject ){
      youtubeObject.stopVideo();
      youtubeObject.clearVideo();
    }

    this.removeChild( document.getElementById( options._container.id ) );
  }
});
<|endoftext|>


<commit_before>if (mw.config.get('wgNamespaceNumber') == 10 || mw.config.get('wgNamespaceNumber') == 828) {
	var path = mw.config.get('wgArticlePath');
	var node = document.createElement("span");
	node.id = "template-transclusion-count";
	node.innerHTML = '使用量：未取得';
	document.getElementsByClassName("mw-indicators mw-body-content")[0].appendChild(node);
	$.ajax({
		type: 'GET',
		url: "https://xiplus.twbbs.org/Xiplus-zhWP/Template-transclusion-count.php?namespace="+mw.config.get('wgNamespaceNumber')+"&title="+mw.config.get('wgTitle'),
		success: function success(data) {
			data = JSON.parse(data);
			if (data.status) {
				ttclink.innerHTML = data.result;
			} else {
				if (data.result == "fetch") {
					ttclink.innerHTML = "抓取錯誤2";
				} else if (data.result == "match") {
					ttclink.innerHTML = "分析錯誤";
				} else {
					ttclink.innerHTML = "未知錯誤";
				}
			}
		},
		error: function error(e) {
			ttclink.innerHTML = "抓取錯誤1";
		}
	});
}
<commit_msg>TTC margin<commit_after>if (mw.config.get('wgNamespaceNumber') == 10 || mw.config.get('wgNamespaceNumber') == 828) {
	var path = mw.config.get('wgArticlePath');
	var node = document.createElement("span");
	node.id = "template-transclusion-count";
	node.style = "margin-left: 5px;";
	node.innerHTML = '使用量：未取得';
	document.getElementsByClassName("mw-indicators mw-body-content")[0].appendChild(node);
	$.ajax({
		type: 'GET',
		url: "https://xiplus.twbbs.org/Xiplus-zhWP/Template-transclusion-count.php?namespace="+mw.config.get('wgNamespaceNumber')+"&title="+mw.config.get('wgTitle'),
		success: function success(data) {
			data = JSON.parse(data);
			if (data.status) {
				ttclink.innerHTML = data.result;
			} else {
				if (data.result == "fetch") {
					ttclink.innerHTML = "抓取錯誤2";
				} else if (data.result == "match") {
					ttclink.innerHTML = "分析錯誤";
				} else {
					ttclink.innerHTML = "未知錯誤";
				}
			}
		},
		error: function error(e) {
			ttclink.innerHTML = "抓取錯誤1";
		}
	});
}
<|endoftext|>