<commit_before>import { useMutation, useQuery } from '@apollo/react-hooks'
import { Dialog, DialogContent, SvgIcon, IconButton } from '@material-ui/core'
import { makeStyles } from '@material-ui/core/styles'
import { Form, Formik, FastField } from 'formik'
import gql from 'graphql-tag'
import QRCode from 'qrcode.react'
import * as R from 'ramda'
import React, { memo, useState } from 'react'
import * as Yup from 'yup'

import Title from 'src/components/Title'
import { Button } from 'src/components/buttons'
import { TextInput } from 'src/components/inputs/formik'
import Sidebar from 'src/components/layout/Sidebar'
import { Info2, P } from 'src/components/typography'
import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg'
import { ReactComponent as WarningIcon } from 'src/styling/icons/warning-icon/comet.svg'
import { primaryColor } from 'src/styling/variables'

import styles from './styles'

const SAVE_CONFIG = gql`
  mutation createPairingTotem($name: String!) {
    createPairingTotem(name: $name)
  }
`
const GET_MACHINES = gql`
  {
    machines {
      name
      deviceId
    }
  }
`

const useStyles = makeStyles(styles)

const getSize = R.compose(R.length, R.pathOr([], ['machines']))

const QrCodeComponent = ({ classes, qrCode, name, count, onPaired }) => {
  const { data } = useQuery(GET_MACHINES, { pollInterval: 10000 })

  const addedMachine = data?.machines?.find(m => m.name === name)
  if (getSize(data) > count && addedMachine) onPaired(addedMachine)

  return (
    <>
      <Info2 className={classes.qrTitle}>
        Scan QR code with your new cryptomat
      </Info2>

          <QRCode size={240} fgColor={primaryColor} value={qrCode} />

              <WarningIcon />

              To pair the machine you need scan the QR code with your machine.
              To do this either snap a picture of this QR code or download it
              through the button above and scan it with the scanning bay on your
              machine.

    </>
  )
}

const initialValues = {
  name: ''
}

const validationSchema = Yup.object().shape({
  name: Yup.string()
    .required()
    .max(50, 'Too long')
})

const MachineNameComponent = ({ nextStep, classes, setQrCode, setName }) => {
  const [register] = useMutation(SAVE_CONFIG, {
    onCompleted: ({ createPairingTotem }) => {
      console.log(createPairingTotem)
      setQrCode(createPairingTotem)
      nextStep()
    },
    onError: e => console.log(e)
  })

  return (
    <>
      <Info2 className={classes.nameTitle}>
        Machine Name (ex: Coffee shop 01)
      </Info2>
      <Formik
        initialValues={initialValues}
        validationSchema={validationSchema}
        onSubmit={({ name }) => {
          setName(name)
          register({ variables: { name } })
        }}>
        <Form className={classes.form}>

            <FastField
              name="name"
              label="Enter machine name"
              component={TextInput}
            />

            <Button type="submit">Submit</Button>

        </Form>
      </Formik>
    </>
  )
}

const steps = [
  {
    label: 'Machine name',
    component: MachineNameComponent
  },
  {
    label: 'Scan QR code',
    component: QrCodeComponent
  }
]

const renderStepper = (step, it, idx, classes) => {
  const active = step === idx
  const past = idx < step
  const future = idx > step

  return (

        {it.label}

      {active && <CurrentStageIconZodiac />}
      {past && <CompleteStageIconZodiac />}
      {future && <EmptyStageIconZodiac />}
      {idx < steps.length - 1 && (

      )}

  )
}

const AddMachine = memo(({ close, onPaired }) => {
  const classes = useStyles()
  const { data } = useQuery(GET_MACHINES)
  const [qrCode, setQrCode] = useState('')
  const [name, setName] = useState('')
  const [step, setStep] = useState(0)
  const count = getSize(data)

  const Component = steps[step].component

  return (

      <Dialog
        fullScreen
        className={classes.dialog}
        open={true}
        aria-labelledby="form-dialog-title">
        <DialogContent className={classes.dialog}>

              <Title>Add Machine</Title>
              <IconButton disableRipple={true} onClick={close}>
                <SvgIcon color="error">
                  <CloseIcon />
                </SvgIcon>
              </IconButton>

              <Sidebar>
                {steps.map((it, idx) => renderStepper(step, it, idx, classes))}
              </Sidebar>

                <Component
                  classes={classes}
                  nextStep={() => setStep(1)}
                  count={count}
                  onPaired={onPaired}
                  qrCode={qrCode}
                  setQrCode={setQrCode}
                  name={name}
                  setName={setName}
                />

        </DialogContent>
      </Dialog>

  )
})

export default AddMachine
<commit_msg>fix: rebase fixes<commit_after>import { useMutation, useQuery } from '@apollo/react-hooks'
import { Dialog, DialogContent, SvgIcon, IconButton } from '@material-ui/core'
import { makeStyles } from '@material-ui/core/styles'
import classnames from 'classnames'
import { Form, Formik, FastField } from 'formik'
import gql from 'graphql-tag'
import QRCode from 'qrcode.react'
import * as R from 'ramda'
import React, { memo, useState } from 'react'
import * as Yup from 'yup'

import Title from 'src/components/Title'
import { Button } from 'src/components/buttons'
import { TextInput } from 'src/components/inputs/formik'
import Sidebar from 'src/components/layout/Sidebar'
import { Info2, P } from 'src/components/typography'
import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg'
import { ReactComponent as CompleteStageIconZodiac } from 'src/styling/icons/stage/zodiac/complete.svg'
import { ReactComponent as CurrentStageIconZodiac } from 'src/styling/icons/stage/zodiac/current.svg'
import { ReactComponent as EmptyStageIconZodiac } from 'src/styling/icons/stage/zodiac/empty.svg'
import { ReactComponent as WarningIcon } from 'src/styling/icons/warning-icon/comet.svg'
import { primaryColor } from 'src/styling/variables'

import styles from './styles'

const SAVE_CONFIG = gql`
  mutation createPairingTotem($name: String!) {
    createPairingTotem(name: $name)
  }
`
const GET_MACHINES = gql`
  {
    machines {
      name
      deviceId
    }
  }
`

const useStyles = makeStyles(styles)

const getSize = R.compose(R.length, R.pathOr([], ['machines']))

const QrCodeComponent = ({ classes, qrCode, name, count, onPaired }) => {
  const { data } = useQuery(GET_MACHINES, { pollInterval: 10000 })

  const addedMachine = data?.machines?.find(m => m.name === name)
  if (getSize(data) > count && addedMachine) onPaired(addedMachine)

  return (
    <>
      <Info2 className={classes.qrTitle}>
        Scan QR code with your new cryptomat
      </Info2>

          <QRCode size={240} fgColor={primaryColor} value={qrCode} />

              <WarningIcon />

              To pair the machine you need scan the QR code with your machine.
              To do this either snap a picture of this QR code or download it
              through the button above and scan it with the scanning bay on your
              machine.

    </>
  )
}

const initialValues = {
  name: ''
}

const validationSchema = Yup.object().shape({
  name: Yup.string()
    .required()
    .max(50, 'Too long')
})

const MachineNameComponent = ({ nextStep, classes, setQrCode, setName }) => {
  const [register] = useMutation(SAVE_CONFIG, {
    onCompleted: ({ createPairingTotem }) => {
      setQrCode(createPairingTotem)
      nextStep()
    },
    onError: e => console.log(e)
  })

  return (
    <>
      <Info2 className={classes.nameTitle}>
        Machine Name (ex: Coffee shop 01)
      </Info2>
      <Formik
        initialValues={initialValues}
        validationSchema={validationSchema}
        onSubmit={({ name }) => {
          setName(name)
          register({ variables: { name } })
        }}>
        <Form className={classes.form}>

            <FastField
              name="name"
              label="Enter machine name"
              component={TextInput}
            />

            <Button type="submit">Submit</Button>

        </Form>
      </Formik>
    </>
  )
}

const steps = [
  {
    label: 'Machine name',
    component: MachineNameComponent
  },
  {
    label: 'Scan QR code',
    component: QrCodeComponent
  }
]

const renderStepper = (step, it, idx, classes) => {
  const active = step === idx
  const past = idx < step
  const future = idx > step

  return (

        {it.label}

      {active && <CurrentStageIconZodiac />}
      {past && <CompleteStageIconZodiac />}
      {future && <EmptyStageIconZodiac />}
      {idx < steps.length - 1 && (

      )}

  )
}

const AddMachine = memo(({ close, onPaired }) => {
  const classes = useStyles()
  const { data } = useQuery(GET_MACHINES)
  const [qrCode, setQrCode] = useState('')
  const [name, setName] = useState('')
  const [step, setStep] = useState(0)
  const count = getSize(data)

  const Component = steps[step].component

  return (

      <Dialog
        fullScreen
        className={classes.dialog}
        open={true}
        aria-labelledby="form-dialog-title">
        <DialogContent className={classes.dialog}>

              <Title>Add Machine</Title>
              <IconButton disableRipple={true} onClick={close}>
                <SvgIcon color="error">
                  <CloseIcon />
                </SvgIcon>
              </IconButton>

              <Sidebar>
                {steps.map((it, idx) => renderStepper(step, it, idx, classes))}
              </Sidebar>

                <Component
                  classes={classes}
                  nextStep={() => setStep(1)}
                  count={count}
                  onPaired={onPaired}
                  qrCode={qrCode}
                  setQrCode={setQrCode}
                  name={name}
                  setName={setName}
                />

        </DialogContent>
      </Dialog>

  )
})

export default AddMachine
<|endoftext|>


<commit_before>'use babel'

// NOTE
// this file(= provider-base.js) is NOT using babel specific feature.
// But intentinally use babel, dont remove this!!
// Provider is base class extended by specific providers.
// If provider-A was written with babel and Provider is not,
// it cause TypeError: Class constructor Provider cannot be invoked without 'new'
// This is because Atom's babel transpiled `class` declaration is NOT ES6's class.
// I believe this mismatch wold be solved in future.
// And also with @babel, custom provider can written in CoffeeScript
const _ = require('underscore-plus')
const {CompositeDisposable} = require('atom')
const {
  saveEditorState,
  isActiveEditor,
  paneForItem,
  getNextAdjacentPaneForPane,
  getPreviousAdjacentPaneForPane,
  splitPane,
  isNarrowEditor,
  getCurrentWord
} = require('../utils')
const Ui = require('../ui')
const settings = require('../settings')
const SearchOptions = require('../search-options')

const providerConfig = {
  needRestoreEditorState: true,
  boundToSingleFile: false,

  showProjectHeader: false,
  showFileHeader: false,
  showColumnOnLineHeader: false,
  itemHaveRange: false,

  supportDirectEdit: false,
  supportCacheItems: false,
  supportReopen: true,
  supportFilePathOnlyItemsUpdate: false,
  editor: null,
  refreshOnDidStopChanging: false,
  refreshOnDidSave: false,

  // used by scan, search, atom-scan,
  showSearchOption: false,

  queryWordBoundaryOnByCurrentWordInvocation: false,
  useFirstQueryAsSearchTerm: false
}

module.exports = class Provider {
  static configScope = 'narrow'
  static destroyedProviderStates = []
  static providersByName = {}
  static providerPathsByName = {}
  static reopenableMax = 10
  static service = {}

  // Keep service by name
  // service must be object like `{inlineGitDiff: service}`
  static setService (service) {
    Object.assign(this.service, service)
  }

  static reopen () {
    const stateAtDestroyed = this.destroyedProviderStates.shift()
    if (stateAtDestroyed) {
      const {name, options, state} = stateAtDestroyed
      return this.start(name, options, state)
    }
  }

  static create (options = {}) {
    const editor = atom.workspace.getActiveTextEditor()
    return new Provider(editor, options)
  }

  static start (name, options = {}, state = {}) {
    const Klass = require(`./${name}`)
    return new Klass(state).start(options)
  }

  static registerProvider (name, klassOrFilePath) {
    const type = typeof klassOrFilePath
    if (type === 'string') {
      this.providerPathsByName[name] = klassOrFilePath
    } else if (type === 'function') {
      this.providersByName[name] = klassOrFilePath
    } else {
      throw new Error('provider must be filePath or function')
    }
  }

  static saveState (provider) {
    this.destroyedProviderStates.unshift(provider.saveState())
    this.destroyedProviderStates.splice(this.reopenableMax)
  }

  static get settings () {
    return settings
  }

  static getSetting (providerName, name) {
    const value = settings.get(`${providerName}.${name}`)
    return value === 'inherit' ? settings.get(name) : value
  }
  static setSetting (providerName, name, value) {
    settings.set(`${providerName}.${name}`, value)
  }

  static getConfig (name) {
    const value =
      this.configScope === 'narrow'
        ? settings.get(`${this.name}.${name}`)
        : atom.config.get(`${this.configScope}.${name}`)

    console.log('getconfig', `${this.name}.${name}`, value)
    return value === 'inherit' ? settings.get(name) : value
  }

  getConfig (name) {
    const value =
      this.constructor.configScope === 'narrow'
        ? settings.get(`${this.name}.${name}`)
        : atom.config.get(`${this.configScope}.${name}`)

    return value === 'inherit' ? settings.get(name) : value
  }

  static setConfig (name, value) {
    if (this.configScope === 'narrow') {
      settings.set(`${this.name}.${name}`, value)
    } else {
      atom.config.set(`${this.configScope}.${name}`, value)
    }
  }

  setConfig (name, value) {
    return this.constructor.setConfig(name, value)
  }

  getOnStartConditionValueFor (name) {
    const value = this.getConfig(name)
    if (value === 'never') return false
    if (value === 'always') return true
    if (value === 'on-input') return this.query
    if (value === 'no-input') return !this.query
  }

  needRevealOnStart () {
    return this.getOnStartConditionValueFor('revealOnStartCondition')
  }

  needActivateOnStart () {
    return this.getOnStartConditionValueFor('focusOnStartCondition')
  }

  initializeSearchOptions (restoredState, options) {
    const editor = atom.workspace.getActiveTextEditor()
    let initialState

    if (!restoredState) {
      const queryWordWithoutSelection = options.queryCurrentWord && editor.getSelectedBufferRange().isEmpty()
      initialState = {
        searchWholeWord: queryWordWithoutSelection || this.getConfig('searchWholeWord'),
        searchUseRegex: this.getConfig('searchUseRegex')
      }
    }
    this.searchOptions = new SearchOptions(this, restoredState || initialState)
  }

  // Currently used only in git-diff-all
  onItemOpened (item) {}

  bindEditor (editor) {
    if (editor === this.editor) return

    if (this.editorSubscriptions) this.editorSubscriptions.dispose()
    this.editorSubscriptions = new CompositeDisposable()
    const oldEditor = this.editor
    this.editor = editor
    this.callHook('onBindEditor', {
      newEditor: editor,
      oldEditor: oldEditor
    })
  }

  getPane () {
    // If editor was pending item, it will be destroyed on next pending-item opened
    const pane = paneForItem(this.editor)
    if (pane && pane.isAlive) {
      this.lastPane = pane
    }

    if (this.lastPane && this.lastPane.isAlive()) {
      return this.lastPane
    }
  }

  isActive () {
    return isActiveEditor(this.editor)
  }

  mergeState (stateA, stateB) {
    return Object.assign(stateA, stateB)
  }

  getState () {
    let state
    if (this.searchOptions) state = this.searchOptions.getState()
    return {searchOptionState: state}
  }

  saveState () {
    return {
      name: this.dashName,
      options: {query: this.ui.lastQuery},
      state: {
        provider: this.getState(),
        ui: this.ui.getState()
      }
    }
  }

  constructor (editor, options = {}) {
    this.clientEditor = editor
    Object.assign(this, providerConfig, options.config)

    this.name = options.name
    this.dashName = _.dasherize(this.name)
    this.subscriptions = new CompositeDisposable()

    this.getItems = options.getItems
    this.updateItems = this.updateItems.bind(this)
    this.finishUpdateItems = this.finishUpdateItems.bind(this)
    this.hook = {
      onUiCreated: options.onUiCreated,
      onBindEditor: options.onBindEditor, // called with {newEditor, oldEditor}
      onItemConfirmed: options.onItemConfirmed,
      onItemOpened: options.onItemOpened,
      onDestroyed: options.onDestroyed
    }

    this.restoredState = options.state
    this.reopened = !!this.restoredState

    if (this.restoredState) {
      const providerState = this.restoredState.provider
      this.searchOptionState = providerState.searchOptionState
      delete providerState.searchOptionState
      this.mergeState(this, this.restoredState.provider)
    }
  }

  callHook (name, ...args) {
    const hook = this.hook[name]
    if (hook) {
      return hook(...args)
    }
  }

  async start (options = {}) {
    // If invoked from another Ui( narrow-editor ).
    // Bind to original Ui.provider.editor to behaves as if it invoked from normal-editor.
    if (isNarrowEditor(this.clientEditor)) {
      this.bindEditor(Ui.get(this.clientEditor).provider.editor)
    } else {
      this.bindEditor(this.clientEditor)
    }
    this.restoreEditorState = saveEditorState(this.editor)

    this.query = this.getInitialQuery(this.clientEditor, options)
    if (this.showSearchOption) {
      this.initializeSearchOptions(this.searchOptionState, options)
    }

    const uiState = this.restoredState ? this.restoredState.ui : null
    this.ui = new Ui(this, {query: this.query}, uiState)
    this.callHook('onUiCreated', this.ui)
    const {pending, focus, pane} = options
    await this.ui.open({pending, focus, pane})
    return this
  }

  updateItems (items) {
    this.ui.emitDidUpdateItems(items)
  }

  finishUpdateItems (items) {
    if (items) this.updateItems(items)
    this.ui.emitDidFinishUpdateItems()
  }

  getInitialQuery (editor, options) {
    let query = options.query || editor.getSelectedText()
    if (!query && options.queryCurrentWord) {
      query = getCurrentWord(editor)
      if (this.queryWordBoundaryOnByCurrentWordInvocation) {
        query = `>${query}<`
      }
    }
    return query
  }

  subscribeEditor (...args) {
    this.editorSubscriptions.add(...args)
  }

  restoreEditorStateIfNecessary (...args) {
    if (this.needRestoreEditorState) this.restoreEditorState(...args)
  }

  destroy () {
    if (this.supportReopen) Provider.saveState(this)

    this.subscriptions.dispose()
    this.editorSubscriptions.dispose()

    this.editor = null
    this.editorSubscriptions = null
    this.callHook('onDestroyed')
  }

  // When narrow was invoked from existing narrow-editor.
  //  ( e.g. `narrow:search-by-current-word` on narrow-editor. )
  // ui is opened at same pane of provider.editor( editor invoked narrow )
  // In this case item should be opened on adjacent pane, not on provider.pane.
  getPaneToOpenItem () {
    const pane = this.getPane()
    const paneForUi = this.ui.getPane()

    if (pane && pane !== paneForUi) {
      return pane
    } else {
      return (
        getPreviousAdjacentPaneForPane(paneForUi) ||
        getNextAdjacentPaneForPane(paneForUi) ||
        splitPane(paneForUi, {split: this.getConfig('directionToOpen').split(':')[0]})
      )
    }
  }

  async openFileForItem ({filePath}, {activatePane, pane} = {}) {
    if (!pane) pane = this.getPaneToOpenItem()

    let itemToOpen
    if (this.boundToSingleFile && this.editor.isAlive() && pane === paneForItem(this.editor)) {
      itemToOpen = this.editor
    }

    if (!filePath) filePath = this.editor.getPath()
    if (!itemToOpen) itemToOpen = pane.itemForURI(filePath)

    if (itemToOpen) {
      if (activatePane) pane.activate()
      pane.activateItem(itemToOpen)
    } else {
      itemToOpen = await atom.workspace.open(filePath, {
        pending: true,
        activatePane,
        activateItem: true,
        pane: pane
      })
    }

    this.callHook('onItemOpened', itemToOpen)
    return itemToOpen
  }

  async confirmed (item, openAtUiPane = false) {
    if (this.hook.onItemConfirmed) {
      return this.hook.onItemConfirmed(item, openAtUiPane)
    }

    let pane
    if (openAtUiPane) {
      pane = this.ui.getPane()
    } else {
      pane = this.getPaneToOpenItem()
      this.needRestoreEditorState = false
    }

    const editor = await this.openFileForItem(item, {
      activatePane: true,
      pane: pane
    })

    const {point} = item
    editor.setCursorBufferPosition(point, {autoscroll: false})
    editor.unfoldBufferRow(point.row)
    editor.scrollToBufferPosition(point, {center: true})
    return editor
  }

  // View
  // -------------------------
  viewForItem (item) {
    if (item.header) {
      return item.header
    } else {
      let text
      const threshold = settings.get('textTruncationThreshold')
      if (item.text.length > threshold) {
        const textToPrepend = settings.get('textPrependToTruncatedText') + ' '
        const textDisplayed = item.text.slice(0, threshold)
        item._truncationIndicator = textToPrepend // give hint to ui.highlighter
        item._textDisplayed = textDisplayed
        text = textToPrepend + textDisplayed
      } else {
        text = item.text
      }
      return (item._lineHeader || '') + text
    }
  }

  // Direct Edit
  // -------------------------
  async updateRealFile (changes) {
    if (this.boundToSingleFile) {
      // Intentionally avoid direct use of @editor to skip observation event
      // subscribed to @editor.
      // This prevent auto refresh, so undoable narrow-editor to last state.
      await this.applyChanges(this.editor.getPath(), changes)
    } else {
      const changesByFilePath = _.groupBy(changes, change => change.item.filePath)
      for (const filePath in changesByFilePath) {
        await this.applyChanges(filePath, changesByFilePath[filePath])
      }
    }
  }

  async applyChanges (filePath, changes) {
    const existingBuffer = atom.project.findBufferForPath(filePath)
    const buffer = existingBuffer || (await atom.project.buildBuffer(filePath))

    buffer.transact(() => {
      for (const {newText, item} of changes) {
        const range = buffer.rangeForRow(item.point.row)
        buffer.setTextInRange(range, newText)
        // Sync item's text state
        // To allow re-edit if not saved and non-boundToSingleFile provider
        item.text = newText
      }
    })
    await buffer.save()
    if (!existingBuffer) buffer.destroy()
  }
}
<commit_msg>blank row<commit_after>'use babel'

// NOTE
// this file(= provider-base.js) is NOT using babel specific feature.
// But intentinally use babel, dont remove this!!
// Provider is base class extended by specific providers.
// If provider-A was written with babel and Provider is not,
// it cause TypeError: Class constructor Provider cannot be invoked without 'new'
// This is because Atom's babel transpiled `class` declaration is NOT ES6's class.
// I believe this mismatch wold be solved in future.
// And also with @babel, custom provider can written in CoffeeScript
const _ = require('underscore-plus')
const {CompositeDisposable} = require('atom')
const {
  saveEditorState,
  isActiveEditor,
  paneForItem,
  getNextAdjacentPaneForPane,
  getPreviousAdjacentPaneForPane,
  splitPane,
  isNarrowEditor,
  getCurrentWord
} = require('../utils')
const Ui = require('../ui')
const settings = require('../settings')
const SearchOptions = require('../search-options')

const providerConfig = {
  needRestoreEditorState: true,
  boundToSingleFile: false,

  showProjectHeader: false,
  showFileHeader: false,
  showColumnOnLineHeader: false,
  itemHaveRange: false,

  supportDirectEdit: false,
  supportCacheItems: false,
  supportReopen: true,
  supportFilePathOnlyItemsUpdate: false,
  editor: null,
  refreshOnDidStopChanging: false,
  refreshOnDidSave: false,

  // used by scan, search, atom-scan,
  showSearchOption: false,

  queryWordBoundaryOnByCurrentWordInvocation: false,
  useFirstQueryAsSearchTerm: false
}

module.exports = class Provider {
  static configScope = 'narrow'
  static destroyedProviderStates = []
  static providersByName = {}
  static providerPathsByName = {}
  static reopenableMax = 10
  static service = {}

  // Keep service by name
  // service must be object like `{inlineGitDiff: service}`
  static setService (service) {
    Object.assign(this.service, service)
  }

  static reopen () {
    const stateAtDestroyed = this.destroyedProviderStates.shift()
    if (stateAtDestroyed) {
      const {name, options, state} = stateAtDestroyed
      return this.start(name, options, state)
    }
  }

  static create (options = {}) {
    const editor = atom.workspace.getActiveTextEditor()
    return new Provider(editor, options)
  }

  static start (name, options = {}, state = {}) {
    const Klass = require(`./${name}`)
    return new Klass(state).start(options)
  }

  static registerProvider (name, klassOrFilePath) {
    const type = typeof klassOrFilePath
    if (type === 'string') {
      this.providerPathsByName[name] = klassOrFilePath
    } else if (type === 'function') {
      this.providersByName[name] = klassOrFilePath
    } else {
      throw new Error('provider must be filePath or function')
    }
  }

  static saveState (provider) {
    this.destroyedProviderStates.unshift(provider.saveState())
    this.destroyedProviderStates.splice(this.reopenableMax)
  }

  static get settings () {
    return settings
  }

  static getSetting (providerName, name) {
    const value = settings.get(`${providerName}.${name}`)
    return value === 'inherit' ? settings.get(name) : value
  }
  static setSetting (providerName, name, value) {
    settings.set(`${providerName}.${name}`, value)
  }

  static getConfig (name) {
    const value =
      this.configScope === 'narrow'
        ? settings.get(`${this.name}.${name}`)
        : atom.config.get(`${this.configScope}.${name}`)

    console.log('getconfig', `${this.name}.${name}`, value)
    return value === 'inherit' ? settings.get(name) : value
  }

  getConfig (name) {
    const value =
      this.constructor.configScope === 'narrow'
        ? settings.get(`${this.name}.${name}`)
        : atom.config.get(`${this.configScope}.${name}`)

    return value === 'inherit' ? settings.get(name) : value
  }

  static setConfig (name, value) {
    if (this.configScope === 'narrow') {
      settings.set(`${this.name}.${name}`, value)
    } else {
      atom.config.set(`${this.configScope}.${name}`, value)
    }
  }

  setConfig (name, value) {
    return this.constructor.setConfig(name, value)
  }

  getOnStartConditionValueFor (name) {
    const value = this.getConfig(name)
    if (value === 'never') return false
    if (value === 'always') return true
    if (value === 'on-input') return this.query
    if (value === 'no-input') return !this.query
  }

  needRevealOnStart () {
    return this.getOnStartConditionValueFor('revealOnStartCondition')
  }

  needActivateOnStart () {
    return this.getOnStartConditionValueFor('focusOnStartCondition')
  }

  initializeSearchOptions (restoredState, options) {
    const editor = atom.workspace.getActiveTextEditor()
    let initialState

    if (!restoredState) {
      const queryWordWithoutSelection = options.queryCurrentWord && editor.getSelectedBufferRange().isEmpty()
      initialState = {
        searchWholeWord: queryWordWithoutSelection || this.getConfig('searchWholeWord'),
        searchUseRegex: this.getConfig('searchUseRegex')
      }
    }
    this.searchOptions = new SearchOptions(this, restoredState || initialState)
  }

  // Currently used only in git-diff-all
  onItemOpened (item) {}

  bindEditor (editor) {
    if (editor === this.editor) return

    if (this.editorSubscriptions) this.editorSubscriptions.dispose()
    this.editorSubscriptions = new CompositeDisposable()
    const oldEditor = this.editor
    this.editor = editor
    this.callHook('onBindEditor', {
      newEditor: editor,
      oldEditor: oldEditor
    })
  }

  getPane () {
    // If editor was pending item, it will be destroyed on next pending-item opened
    const pane = paneForItem(this.editor)
    if (pane && pane.isAlive) {
      this.lastPane = pane
    }

    if (this.lastPane && this.lastPane.isAlive()) {
      return this.lastPane
    }
  }

  isActive () {
    return isActiveEditor(this.editor)
  }

  mergeState (stateA, stateB) {
    return Object.assign(stateA, stateB)
  }

  getState () {
    let state
    if (this.searchOptions) state = this.searchOptions.getState()
    return {searchOptionState: state}
  }

  saveState () {
    return {
      name: this.dashName,
      options: {query: this.ui.lastQuery},
      state: {
        provider: this.getState(),
        ui: this.ui.getState()
      }
    }
  }

  constructor (editor, options = {}) {
    this.clientEditor = editor
    Object.assign(this, providerConfig, options.config)

    this.name = options.name
    this.dashName = _.dasherize(this.name)
    this.subscriptions = new CompositeDisposable()

    this.getItems = options.getItems
    this.updateItems = this.updateItems.bind(this)
    this.finishUpdateItems = this.finishUpdateItems.bind(this)

    this.hook = {
      onUiCreated: options.onUiCreated,
      onBindEditor: options.onBindEditor, // called with {newEditor, oldEditor}
      onItemConfirmed: options.onItemConfirmed,
      onItemOpened: options.onItemOpened,
      onDestroyed: options.onDestroyed
    }

    this.restoredState = options.state
    this.reopened = !!this.restoredState

    if (this.restoredState) {
      const providerState = this.restoredState.provider
      this.searchOptionState = providerState.searchOptionState
      delete providerState.searchOptionState
      this.mergeState(this, this.restoredState.provider)
    }
  }

  callHook (name, ...args) {
    const hook = this.hook[name]
    if (hook) {
      return hook(...args)
    }
  }

  async start (options = {}) {
    // If invoked from another Ui( narrow-editor ).
    // Bind to original Ui.provider.editor to behaves as if it invoked from normal-editor.
    if (isNarrowEditor(this.clientEditor)) {
      this.bindEditor(Ui.get(this.clientEditor).provider.editor)
    } else {
      this.bindEditor(this.clientEditor)
    }
    this.restoreEditorState = saveEditorState(this.editor)

    this.query = this.getInitialQuery(this.clientEditor, options)
    if (this.showSearchOption) {
      this.initializeSearchOptions(this.searchOptionState, options)
    }

    const uiState = this.restoredState ? this.restoredState.ui : null
    this.ui = new Ui(this, {query: this.query}, uiState)
    this.callHook('onUiCreated', this.ui)
    const {pending, focus, pane} = options
    await this.ui.open({pending, focus, pane})
    return this
  }

  updateItems (items) {
    this.ui.emitDidUpdateItems(items)
  }

  finishUpdateItems (items) {
    if (items) this.updateItems(items)
    this.ui.emitDidFinishUpdateItems()
  }

  getInitialQuery (editor, options) {
    let query = options.query || editor.getSelectedText()
    if (!query && options.queryCurrentWord) {
      query = getCurrentWord(editor)
      if (this.queryWordBoundaryOnByCurrentWordInvocation) {
        query = `>${query}<`
      }
    }
    return query
  }

  subscribeEditor (...args) {
    this.editorSubscriptions.add(...args)
  }

  restoreEditorStateIfNecessary (...args) {
    if (this.needRestoreEditorState) this.restoreEditorState(...args)
  }

  destroy () {
    if (this.supportReopen) Provider.saveState(this)

    this.subscriptions.dispose()
    this.editorSubscriptions.dispose()

    this.editor = null
    this.editorSubscriptions = null
    this.callHook('onDestroyed')
  }

  // When narrow was invoked from existing narrow-editor.
  //  ( e.g. `narrow:search-by-current-word` on narrow-editor. )
  // ui is opened at same pane of provider.editor( editor invoked narrow )
  // In this case item should be opened on adjacent pane, not on provider.pane.
  getPaneToOpenItem () {
    const pane = this.getPane()
    const paneForUi = this.ui.getPane()

    if (pane && pane !== paneForUi) {
      return pane
    } else {
      return (
        getPreviousAdjacentPaneForPane(paneForUi) ||
        getNextAdjacentPaneForPane(paneForUi) ||
        splitPane(paneForUi, {split: this.getConfig('directionToOpen').split(':')[0]})
      )
    }
  }

  async openFileForItem ({filePath}, {activatePane, pane} = {}) {
    if (!pane) pane = this.getPaneToOpenItem()

    let itemToOpen
    if (this.boundToSingleFile && this.editor.isAlive() && pane === paneForItem(this.editor)) {
      itemToOpen = this.editor
    }

    if (!filePath) filePath = this.editor.getPath()
    if (!itemToOpen) itemToOpen = pane.itemForURI(filePath)

    if (itemToOpen) {
      if (activatePane) pane.activate()
      pane.activateItem(itemToOpen)
    } else {
      itemToOpen = await atom.workspace.open(filePath, {
        pending: true,
        activatePane,
        activateItem: true,
        pane: pane
      })
    }

    this.callHook('onItemOpened', itemToOpen)
    return itemToOpen
  }

  async confirmed (item, openAtUiPane = false) {
    if (this.hook.onItemConfirmed) {
      return this.hook.onItemConfirmed(item, openAtUiPane)
    }

    let pane
    if (openAtUiPane) {
      pane = this.ui.getPane()
    } else {
      pane = this.getPaneToOpenItem()
      this.needRestoreEditorState = false
    }

    const editor = await this.openFileForItem(item, {
      activatePane: true,
      pane: pane
    })

    const {point} = item
    editor.setCursorBufferPosition(point, {autoscroll: false})
    editor.unfoldBufferRow(point.row)
    editor.scrollToBufferPosition(point, {center: true})
    return editor
  }

  // View
  // -------------------------
  viewForItem (item) {
    if (item.header) {
      return item.header
    } else {
      let text
      const threshold = settings.get('textTruncationThreshold')
      if (item.text.length > threshold) {
        const textToPrepend = settings.get('textPrependToTruncatedText') + ' '
        const textDisplayed = item.text.slice(0, threshold)
        item._truncationIndicator = textToPrepend // give hint to ui.highlighter
        item._textDisplayed = textDisplayed
        text = textToPrepend + textDisplayed
      } else {
        text = item.text
      }
      return (item._lineHeader || '') + text
    }
  }

  // Direct Edit
  // -------------------------
  async updateRealFile (changes) {
    if (this.boundToSingleFile) {
      // Intentionally avoid direct use of @editor to skip observation event
      // subscribed to @editor.
      // This prevent auto refresh, so undoable narrow-editor to last state.
      await this.applyChanges(this.editor.getPath(), changes)
    } else {
      const changesByFilePath = _.groupBy(changes, change => change.item.filePath)
      for (const filePath in changesByFilePath) {
        await this.applyChanges(filePath, changesByFilePath[filePath])
      }
    }
  }

  async applyChanges (filePath, changes) {
    const existingBuffer = atom.project.findBufferForPath(filePath)
    const buffer = existingBuffer || (await atom.project.buildBuffer(filePath))

    buffer.transact(() => {
      for (const {newText, item} of changes) {
        const range = buffer.rangeForRow(item.point.row)
        buffer.setTextInRange(range, newText)
        // Sync item's text state
        // To allow re-edit if not saved and non-boundToSingleFile provider
        item.text = newText
      }
    })
    await buffer.save()
    if (!existingBuffer) buffer.destroy()
  }
}
<|endoftext|>


<commit_before>import { search } from './search';
import { assign } from './utils';

/**
 * Class to help with paginated results of an OpenSearch service.
 */
export class OpenSearchPaginator {
  /**
   * @param {OpenSearchUrl} url The URL to perform all subsequent requests on.
   * @param {object} parameters Search parameters.
   * @param {object} [options] Additional options for the pagination
   * @param {boolean} [useCache=true] Whether response pages shall be cached.
   * @param {int} [preferredItemsPerPage=undefined] The preferred page size. This
   *                                                defaults to the advertised
   *                                                default of the URL.
   * @param {boolean} [preferStartIndex=true] Whether the paging shall be done
   *                                          using the `startIndex` parameter
   *                                          (the default) or the `startPage`.
   */
  constructor(url, parameters, { useCache = true,
                                 preferredItemsPerPage = undefined,
                                 preferStartIndex = true } = {}) {
    this._url = url;
    this._parameters = parameters;
    this._cache = useCache ? {} : null;
    this._preferredItemsPerPage = preferredItemsPerPage;
    this._preferStartIndex = preferStartIndex;
    this._serverItemsPerPage = undefined;
    this._totalResults = undefined;
  }

  /**
   * Fetch a single page of the result set. Sets the server side items per page,
   * when the result is available.
   * @param {int} [pageIndex=0] The index of the page to be fetched.
   * @param {int} [maxCount=undefined] The maximum count of objects to be retrieved.
   * @returns {Promise<SearchResult>} The search result.
   */
  fetchPage(pageIndex = 0, maxCount = undefined) {
    // TODO: implement caching of whole pages
    // if (this._cache && this._cache[pageIndex]) {
    //   return this._cache[pageIndex];
    // }
    const parameters = assign({}, this._parameters);

    const pageSize = this.getActualPageSize();
    if (pageSize && maxCount) {
      parameters.count = Math.min(maxCount, pageSize);
    } else if (pageSize) {
      parameters.count = pageSize;
    } else if (maxCount) {
      parameters.count = maxCount;
    }

    if (this._preferStartIndex) {
      if (typeof pageSize === 'undefined') {
        parameters.startIndex = this._url.indexOffset;
      } else {
        parameters.startIndex = (pageSize * pageIndex) + this._url.indexOffset;
      }
    } else {
      parameters.startPage = pageIndex + this._url.pageOffset;
    }
    return search(this._url, parameters)
      .then((result) => {
        this._totalResults = result.totalResults;
        if (!this._serverItemsPerPage && result.itemsPerPage) {
          this._serverItemsPerPage = result.itemsPerPage;
        }
        return result;
      });
  }

  /**
   * Fetches all pages from the URL. A probing request is sent to determine how
   * many succeeding requests have to be sent.
   * @returns {Promise<SearchResult[]>} The async result of all the pages in the
   *                                    search.
   */
  fetchAllPages() {
    return this.fetchPage()
      .then((firstPage) => {
        const pageCount = this.getPageCount();
        const requests = [firstPage];
        for (let i = 1; i < pageCount; ++i) {
          requests.push(this.fetchPage(i));
        }
        return Promise.all(requests);
      });
  }

  /**
   * Convenience method to get the records of all pages in a single result array
   * @returns {Promise<SearchResult>} The records of all the pages in the search.
   */
  fetchAllRecords() {
    return this.fetchAllPages()
      .then((pages) => {
        const firstPage = pages[0];
        const records = pages.reduce((rs, page) => rs.concat(page.records), []);
        return {
          totalResults: firstPage.totalResults,
          startIndex: firstPage.startIndex,
          itemsPerPage: firstPage.itemsPerPage,
          records,
        };
      });
  }

  /**
   * Fetches the first X records of a search in a single search result.
   * @param {int} maxCount The maximum number of records to fetch.
   * @returns {Promise<SearchResult>} The resulting records as a promise.
   */
  fetchFirstRecords(maxCount) {
    // Get the first page
    return this.fetchPage(0, maxCount)
      .then((firstPage) => {
        // check if all records fit in the first page (then return this page)
        if (firstPage.totalResults <= firstPage.itemsPerPage) {
          // return if we already have all records
          return firstPage;
        }
        // fetch other pages until we have the required count
        const requests = [firstPage];
        for (let i = 1; i < maxCount / firstPage.itemsPerPage; ++i) {
          let count = firstPage.itemsPerPage;
          if (firstPage.itemsPerPage * i > maxCount) {
            count = maxCount - (firstPage.itemsPerPage * (i - 1));
          }
          requests.push(this.fetchPage(i, count));
        }

        return Promise.all(requests)
          .then((pages) => {
            const records = pages.reduce((rs, page) => rs.concat(page.records), []);
            return {
              totalResults: firstPage.totalResults,
              startIndex: firstPage.startIndex,
              itemsPerPage: firstPage.itemsPerPage,
              records,
            };
          });
      });
  }

  /**
   * Returns the actual page size.
   * @returns {int} The computed page size.
   */
  getActualPageSize() {
    if (this._preferredItemsPerPage && this._serverItemsPerPage) {
      return Math.min(this._preferredItemsPerPage, this._serverItemsPerPage);
    } else if (this._serverItemsPerPage) {
      return this._serverItemsPerPage;
    } else if (this._preferredItemsPerPage) {
      return this._preferredItemsPerPage;
    }
    const countParam = this._url.getParameter('count');
    if (countParam) {
      return countParam.minInclusive || countParam.maxInclusive;
    }
    return undefined;
  }

  /**
   * Returns the computed number of pages, which is available once the first page
   * was received.
   * @returns {int} The number of pages.
   */
  getPageCount() {
    const pageSize = this.getActualPageSize();
    if (!this._totalResults) {
      return this._totalResults;
    } else if (!pageSize) {
      return undefined;
    }
    return Math.ceil(this._totalResults / pageSize);
  }
}
<commit_msg>Fixing issue in calculation of required number of pages.<commit_after>import { search } from './search';
import { assign } from './utils';

/**
 * Class to help with paginated results of an OpenSearch service.
 */
export class OpenSearchPaginator {
  /**
   * @param {OpenSearchUrl} url The URL to perform all subsequent requests on.
   * @param {object} parameters Search parameters.
   * @param {object} [options] Additional options for the pagination
   * @param {boolean} [useCache=true] Whether response pages shall be cached.
   * @param {int} [preferredItemsPerPage=undefined] The preferred page size. This
   *                                                defaults to the advertised
   *                                                default of the URL.
   * @param {boolean} [preferStartIndex=true] Whether the paging shall be done
   *                                          using the `startIndex` parameter
   *                                          (the default) or the `startPage`.
   */
  constructor(url, parameters, { useCache = true,
                                 preferredItemsPerPage = undefined,
                                 preferStartIndex = true } = {}) {
    this._url = url;
    this._parameters = parameters;
    this._cache = useCache ? {} : null;
    this._preferredItemsPerPage = preferredItemsPerPage;
    this._preferStartIndex = preferStartIndex;
    this._serverItemsPerPage = undefined;
    this._totalResults = undefined;
  }

  /**
   * Fetch a single page of the result set. Sets the server side items per page,
   * when the result is available.
   * @param {int} [pageIndex=0] The index of the page to be fetched.
   * @param {int} [maxCount=undefined] The maximum count of objects to be retrieved.
   * @returns {Promise<SearchResult>} The search result.
   */
  fetchPage(pageIndex = 0, maxCount = undefined) {
    // TODO: implement caching of whole pages
    // if (this._cache && this._cache[pageIndex]) {
    //   return this._cache[pageIndex];
    // }
    const parameters = assign({}, this._parameters);

    const pageSize = this.getActualPageSize();
    if (pageSize && maxCount) {
      parameters.count = Math.min(maxCount, pageSize);
    } else if (pageSize) {
      parameters.count = pageSize;
    } else if (maxCount) {
      parameters.count = maxCount;
    }

    if (this._preferStartIndex) {
      if (typeof pageSize === 'undefined') {
        parameters.startIndex = this._url.indexOffset;
      } else {
        parameters.startIndex = (pageSize * pageIndex) + this._url.indexOffset;
      }
    } else {
      parameters.startPage = pageIndex + this._url.pageOffset;
    }
    return search(this._url, parameters)
      .then((result) => {
        this._totalResults = result.totalResults;
        if (!this._serverItemsPerPage && result.itemsPerPage) {
          this._serverItemsPerPage = result.itemsPerPage;
        }
        return result;
      });
  }

  /**
   * Fetches all pages from the URL. A probing request is sent to determine how
   * many succeeding requests have to be sent.
   * @returns {Promise<SearchResult[]>} The async result of all the pages in the
   *                                    search.
   */
  fetchAllPages() {
    return this.fetchPage()
      .then((firstPage) => {
        const pageCount = this.getPageCount();
        const requests = [firstPage];
        for (let i = 1; i < pageCount; ++i) {
          requests.push(this.fetchPage(i));
        }
        return Promise.all(requests);
      });
  }

  /**
   * Convenience method to get the records of all pages in a single result array
   * @returns {Promise<SearchResult>} The records of all the pages in the search.
   */
  fetchAllRecords() {
    return this.fetchAllPages()
      .then((pages) => {
        const firstPage = pages[0];
        const records = pages.reduce((rs, page) => rs.concat(page.records), []);
        return {
          totalResults: firstPage.totalResults,
          startIndex: firstPage.startIndex,
          itemsPerPage: firstPage.itemsPerPage,
          records,
        };
      });
  }

  /**
   * Fetches the first X records of a search in a single search result.
   * @param {int} maxCount The maximum number of records to fetch.
   * @returns {Promise<SearchResult>} The resulting records as a promise.
   */
  fetchFirstRecords(maxCount) {
    // Get the first page
    return this.fetchPage(0, maxCount)
      .then((firstPage) => {
        // check if all records fit in the first page (then return this page)
        if (firstPage.totalResults <= firstPage.itemsPerPage) {
          // return if we already have all records
          return firstPage;
        }
        // fetch other pages until we have the required count
        const requests = [firstPage];
        const numPages = Math.ceil(
          Math.min(maxCount, firstPage.totalResults) / firstPage.itemsPerPage
        );
        for (let i = 1; i < numPages; ++i) {
          let count = firstPage.itemsPerPage;
          if (firstPage.itemsPerPage * i > maxCount) {
            count = maxCount - (firstPage.itemsPerPage * (i - 1));
          }
          requests.push(this.fetchPage(i, count));
        }

        return Promise.all(requests)
          .then(pages => ({
            totalResults: firstPage.totalResults,
            startIndex: firstPage.startIndex,
            itemsPerPage: firstPage.itemsPerPage,
            records: pages.reduce((rs, page) => rs.concat(page.records), []),
          }));
      });
  }

  /**
   * Returns the actual page size.
   * @returns {int} The computed page size.
   */
  getActualPageSize() {
    if (this._preferredItemsPerPage && this._serverItemsPerPage) {
      return Math.min(this._preferredItemsPerPage, this._serverItemsPerPage);
    } else if (this._serverItemsPerPage) {
      return this._serverItemsPerPage;
    } else if (this._preferredItemsPerPage) {
      return this._preferredItemsPerPage;
    }
    const countParam = this._url.getParameter('count');
    if (countParam) {
      return countParam.minInclusive || countParam.maxInclusive;
    }
    return undefined;
  }

  /**
   * Returns the computed number of pages, which is available once the first page
   * was received.
   * @returns {int} The number of pages.
   */
  getPageCount() {
    const pageSize = this.getActualPageSize();
    if (!this._totalResults) {
      return this._totalResults;
    } else if (!pageSize) {
      return undefined;
    }
    return Math.ceil(this._totalResults / pageSize);
  }
}
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react';
import OnClickOutside from 'shared/components/OnClickOutside';

const Dropdown = React.createClass({
  propTypes: {
    children: PropTypes.node.isRequired,
    items: PropTypes.arrayOf(PropTypes.shape({
      text: PropTypes.string.isRequired,
    })).isRequired,
    onChoose: PropTypes.func.isRequired,
    className: PropTypes.string,
  },
  getInitialState() {
    return {
      isOpen: false,
    };
  },
  handleClickOutside() {
    this.setState({isOpen: false});
  },
  handleSelection(item) {
    this.toggleMenu();
    this.props.onChoose(item);
  },
  toggleMenu(e) {
    if (e) {
      e.stopPropagation();
    }
    this.setState({isOpen: !this.state.isOpen});
  },
  render() {
    const self = this;
    const {items, className} = self.props;

    return (
      <div onClick={this.toggleMenu} className={`dropdown ${className}`}>

          {this.props.children}

        {self.state.isOpen ?

            {items.map((item, i) => {
              return (

 self.handleSelection(item)}>

                    {item.text}

              );
            })}

          : null}

    );
  },
});

export default OnClickOutside(Dropdown);
<commit_msg>Adding "open" class to dropdown toggle if it is open<commit_after>import React, {PropTypes} from 'react';
import classNames from 'classnames';
import OnClickOutside from 'shared/components/OnClickOutside';

const Dropdown = React.createClass({
  propTypes: {
    children: PropTypes.node.isRequired,
    items: PropTypes.arrayOf(PropTypes.shape({
      text: PropTypes.string.isRequired,
    })).isRequired,
    onChoose: PropTypes.func.isRequired,
    className: PropTypes.string,
  },
  getInitialState() {
    return {
      isOpen: false,
    };
  },
  handleClickOutside() {
    this.setState({isOpen: false});
  },
  handleSelection(item) {
    this.toggleMenu();
    this.props.onChoose(item);
  },
  toggleMenu(e) {
    if (e) {
      e.stopPropagation();
    }
    this.setState({isOpen: !this.state.isOpen});
  },
  render() {
    const self = this;
    const {items, className} = self.props;

    return (
      <div onClick={this.toggleMenu} className={classNames(`dropdown ${className}`, {open: self.state.isOpen})}>

          {this.props.children}

        {self.state.isOpen ?

            {items.map((item, i) => {
              return (

 self.handleSelection(item)}>

                    {item.text}

              );
            })}

          : null}

    );
  },
});

export default OnClickOutside(Dropdown);
<|endoftext|>


<commit_before>var imageSize = 8192;
var tileFolder = './tiles/';
var tileSize = 256;
var maxTileLevel = 7;
var antialias = 4;

var fs = require('fs');
var path = require('path');
var gm = require('gm');

var data = require('./lib/prepare_data.js');

var nodes = data.nodes;
var links = data.links;

nodes.forEach(function (node) {
	node.x *= data.config.scale;
	node.y *= data.config.scale;
	node.r *= data.config.scale;
})

if (process.argv[2]) antialias = parseInt(process.argv[2], 10);

saveTiles(maxTileLevel);

function saveTiles(maxDepth) {
	var maxProcesses = 4;
	var emptyImageBuffer;

	var activeProcesses = 0;
	var processes = [];
	var startTime = (new Date()).getTime();
	var tileCount = 0;
	var tileCountMax = Math.floor(Math.pow(4, maxDepth)/0.75);

	createEmptyTile(function () {
		renderTiles(0,0,0,nodes,links);
	});

	function nextProcess(func) {
		if (func) processes.push(func);
		while ((activeProcesses < maxProcesses) && (processes.length > 0)) {
			var process = processes.pop();
			activeProcesses++;
			setImmediate(process);
		}
	}

	function finishProcess() {
		activeProcesses--;
		nextProcess();
	}

	function renderTiles(x0, y0, z0, nodes, links, callback) {

		var foldername = path.join(tileFolder, z0+'/'+y0 );
		var filename = foldername+'/'+x0+'.png';

		ensureFolder(foldername);

		if (z0 < maxDepth) {
			var subTilesFilename = [];
			var subTilesRendered = 0;
			prepareSubTile(x0*2+0, y0*2+0, z0+1, 0);
			prepareSubTile(x0*2+1, y0*2+0, z0+1, 1);
			prepareSubTile(x0*2+0, y0*2+1, z0+1, 2);
			prepareSubTile(x0*2+1, y0*2+1, z0+1, 3);
		} else {
			renderTile(finish);
		}

		function finish() {
			tileCount++;
			if (tileCount % 100 == 0) console.log([
				tileCount,
				(new Date()).getTime() - startTime,
				(100*tileCount/tileCountMax).toFixed(1)+'%'
			].join('\t'));
			if (callback) callback(filename);
		}

		function prepareSubTile(xn, yn, zn, index) {
			var radius = 0.8*imageSize/Math.pow(2,zn);
			var radius2 = sqr(radius);
			var cx = imageSize*(-1/2 + (1/2 + xn)/Math.pow(2,zn));
			var cy = imageSize*(-1/2 + (1/2 + yn)/Math.pow(2,zn));

			var newNodes = nodes.filter(function (node) {
				return Math.sqrt(sqr(cx-node.x)+sqr(cy-node.y)) < (radius+node.r)
			})

			var newLinks = links.filter(function (link) {
				var n1 = link.source;
				var n2 = link.target;
				lx = (n1.x-n2.x)*a + n2.x;
				ly = (n1.y-n2.y)*a + n2.y;
				var ldx = (n1.x - n2.x);
				var ldy = (n1.y - n2.y);
				var lx0 = (n2.x - cx);
				var ly0 = (n2.y - cy);

				var a = -(lx0*ldx + ly0*ldy)/(ldx*ldx + ldy*ldy);
				if (a < 0) a = 0;
				if (a > 1) a = 1;
				var d2 = sqr(ldx*a + lx0) + sqr(ldy*a + ly0);

				return d2 < radius2;
			});

			renderTiles(xn, yn, zn, newNodes, newLinks, function (filename) {
				subTilesRendered++;
				subTilesFilename[index] = filename;
				if (subTilesRendered == 4) {
					mergeTiles(subTilesFilename, finish)
				}
			})
		}

		function renderTile(callback) {
			if ((nodes.length == 0) && (links.length == 0)) {
				fs.writeFileSync(filename, emptyImageBuffer);
				callback();
				return
			}

			var aaTileSize = antialias*tileSize;
			var scale = imageSize/(aaTileSize*Math.pow(2,z0));
			var cx = imageSize*(1/2 - x0/Math.pow(2,z0));
			var cy = imageSize*(1/2 - y0/Math.pow(2,z0));

			var strokeWidth = (0.5/scale);

			var commands = [
				'push graphic-context',
					'viewbox 0 0 '+aaTileSize+' '+aaTileSize,
					'push graphic-context',
						'stroke "rgb(20,59,82)"',
						'fill none',
						'stroke-width '+strokeWidth,
						links.map(line).join('\n'),
					'pop graphic-context',
					'push graphic-context',
						//'fill "#fa7d18"',
						'fill "#fee915"',
						nodes.filter(function (n) { return n.type == 'person' }).map(circle).join('\n'),
					'pop graphic-context',
					'push graphic-context',
						'fill "#a3db19"',
						nodes.filter(function (n) { return n.type != 'person' }).map(circle).join('\n'),
					'pop graphic-context',
				'pop graphic-context'
			].join('\n');

			//fs.writeFileSync(filename.replace(/png$/, 'mvg'), commands, 'utf8');

			function circle(node) {
				return 'circle ' + [
					(node.x + cx         )/scale,
					(node.y + cy         )/scale,
					(node.x + cx + node.r)/scale,
					(node.y + cy         )/scale
				].join(',');
			}

			function line(link) {
				var n1 = link.source;
				var n2 = link.target;
				return 'line ' + [
					(n1.x + cx)/scale,
					(n1.y + cy)/scale,
					(n2.x + cx)/scale,
					(n2.y + cy)/scale
				].join(',');
			}

			nextProcess(function () {
				var img = gm(new Buffer(commands));

				img.addSrcFormatter(function (a) {
					a.forEach(function (e,i) { a[i] = 'MVG:'+e });
				});
				img.in('-size');
				img.in((tileSize*antialias)+'x'+(tileSize*antialias));
				img.in('-background');
				img.in('transparent');
				img.in('+antialias');
				img.filter('Box');
				img.resize(tileSize, tileSize);

				img.write(filename, function (err) {
					if (err) {
						console.error(err);
						return
					}
					finishProcess();
					callback()
				})
			})
		}

		function mergeTiles(subTilesFilename, callback) {
			nextProcess(function () {
				var img = gm(tileSize*2, tileSize*2, 'transparent');

				img.out('-page');
				img.out('+0+0');
				img.out(subTilesFilename[0]);
				img.out('-page');
				img.out('+256+0');
				img.out(subTilesFilename[1]);
				img.out('-page');
				img.out('+0+256');
				img.out(subTilesFilename[2]);
				img.out('-page');
				img.out('+256+256');
				img.out(subTilesFilename[3]);
				img.out('-mosaic');
				img.out('-resize');
				img.out('50%');

				img.write(filename, function (err) {
					if (err) {
						console.error(err);
						return
					}
					finishProcess();
					callback()
				})
			})
		}
	}

	function createEmptyTile(callback) {
		var t = gm(tileSize, tileSize, '#ffffffff');
		t.colors(2);
		t.toBuffer('PNG', function (err, buf) {
			if (err) console.error(err);
			emptyImageBuffer = buf;
			callback();
		});
	}

	function ensureFolder(folder) {
		if (!fs.existsSync(folder)) {
			ensureFolder(path.dirname(folder));
			fs.mkdirSync(folder);
		}
	}

	function sqr(v) {
		return v*v;
	}
}<commit_msg>add scaling to stroke width<commit_after>var imageSize = 8192;
var tileFolder = './tiles/';
var tileSize = 256;
var maxTileLevel = 7;
var antialias = 4;

var fs = require('fs');
var path = require('path');
var gm = require('gm');

var data = require('./lib/prepare_data.js');

var nodes = data.nodes;
var links = data.links;

nodes.forEach(function (node) {
	node.x *= data.config.scale;
	node.y *= data.config.scale;
	node.r *= data.config.scale;
})

if (process.argv[2]) antialias = parseInt(process.argv[2], 10);

saveTiles(maxTileLevel);

function saveTiles(maxDepth) {
	var maxProcesses = 4;
	var emptyImageBuffer;

	var activeProcesses = 0;
	var processes = [];
	var startTime = (new Date()).getTime();
	var tileCount = 0;
	var tileCountMax = Math.floor(Math.pow(4, maxDepth)/0.75);

	createEmptyTile(function () {
		renderTiles(0,0,0,nodes,links);
	});

	function nextProcess(func) {
		if (func) processes.push(func);
		while ((activeProcesses < maxProcesses) && (processes.length > 0)) {
			var process = processes.pop();
			activeProcesses++;
			setImmediate(process);
		}
	}

	function finishProcess() {
		activeProcesses--;
		nextProcess();
	}

	function renderTiles(x0, y0, z0, nodes, links, callback) {

		var foldername = path.join(tileFolder, z0+'/'+y0 );
		var filename = foldername+'/'+x0+'.png';

		ensureFolder(foldername);

		if (z0 < maxDepth) {
			var subTilesFilename = [];
			var subTilesRendered = 0;
			prepareSubTile(x0*2+0, y0*2+0, z0+1, 0);
			prepareSubTile(x0*2+1, y0*2+0, z0+1, 1);
			prepareSubTile(x0*2+0, y0*2+1, z0+1, 2);
			prepareSubTile(x0*2+1, y0*2+1, z0+1, 3);
		} else {
			renderTile(finish);
		}

		function finish() {
			tileCount++;
			if (tileCount % 100 == 0) console.log([
				tileCount,
				(new Date()).getTime() - startTime,
				(100*tileCount/tileCountMax).toFixed(1)+'%'
			].join('\t'));
			if (callback) callback(filename);
		}

		function prepareSubTile(xn, yn, zn, index) {
			var radius = 0.8*imageSize/Math.pow(2,zn);
			var radius2 = sqr(radius);
			var cx = imageSize*(-1/2 + (1/2 + xn)/Math.pow(2,zn));
			var cy = imageSize*(-1/2 + (1/2 + yn)/Math.pow(2,zn));

			var newNodes = nodes.filter(function (node) {
				return Math.sqrt(sqr(cx-node.x)+sqr(cy-node.y)) < (radius+node.r)
			})

			var newLinks = links.filter(function (link) {
				var n1 = link.source;
				var n2 = link.target;
				lx = (n1.x-n2.x)*a + n2.x;
				ly = (n1.y-n2.y)*a + n2.y;
				var ldx = (n1.x - n2.x);
				var ldy = (n1.y - n2.y);
				var lx0 = (n2.x - cx);
				var ly0 = (n2.y - cy);

				var a = -(lx0*ldx + ly0*ldy)/(ldx*ldx + ldy*ldy);
				if (a < 0) a = 0;
				if (a > 1) a = 1;
				var d2 = sqr(ldx*a + lx0) + sqr(ldy*a + ly0);

				return d2 < radius2;
			});

			renderTiles(xn, yn, zn, newNodes, newLinks, function (filename) {
				subTilesRendered++;
				subTilesFilename[index] = filename;
				if (subTilesRendered == 4) {
					mergeTiles(subTilesFilename, finish)
				}
			})
		}

		function renderTile(callback) {
			if ((nodes.length == 0) && (links.length == 0)) {
				fs.writeFileSync(filename, emptyImageBuffer);
				callback();
				return
			}

			var aaTileSize = antialias*tileSize;
			var scale = imageSize/(aaTileSize*Math.pow(2,z0));
			var cx = imageSize*(1/2 - x0/Math.pow(2,z0));
			var cy = imageSize*(1/2 - y0/Math.pow(2,z0));

			var strokeWidth = (0.5/scale)*data.config.scale;

			var commands = [
				'push graphic-context',
					'viewbox 0 0 '+aaTileSize+' '+aaTileSize,
					'push graphic-context',
						'stroke "rgb(20,59,82)"',
						'fill none',
						'stroke-width '+strokeWidth,
						links.map(line).join('\n'),
					'pop graphic-context',
					'push graphic-context',
						//'fill "#fa7d18"',
						'fill "#fee915"',
						nodes.filter(function (n) { return n.type == 'person' }).map(circle).join('\n'),
					'pop graphic-context',
					'push graphic-context',
						'fill "#a3db19"',
						nodes.filter(function (n) { return n.type != 'person' }).map(circle).join('\n'),
					'pop graphic-context',
				'pop graphic-context'
			].join('\n');

			//fs.writeFileSync(filename.replace(/png$/, 'mvg'), commands, 'utf8');

			function circle(node) {
				return 'circle ' + [
					(node.x + cx         )/scale,
					(node.y + cy         )/scale,
					(node.x + cx + node.r)/scale,
					(node.y + cy         )/scale
				].join(',');
			}

			function line(link) {
				var n1 = link.source;
				var n2 = link.target;
				return 'line ' + [
					(n1.x + cx)/scale,
					(n1.y + cy)/scale,
					(n2.x + cx)/scale,
					(n2.y + cy)/scale
				].join(',');
			}

			nextProcess(function () {
				var img = gm(new Buffer(commands));

				img.addSrcFormatter(function (a) {
					a.forEach(function (e,i) { a[i] = 'MVG:'+e });
				});
				img.in('-size');
				img.in((tileSize*antialias)+'x'+(tileSize*antialias));
				img.in('-background');
				img.in('transparent');
				img.in('+antialias');
				img.filter('Box');
				img.resize(tileSize, tileSize);

				img.write(filename, function (err) {
					if (err) {
						console.error(err);
						return
					}
					finishProcess();
					callback()
				})
			})
		}

		function mergeTiles(subTilesFilename, callback) {
			nextProcess(function () {
				var img = gm(tileSize*2, tileSize*2, 'transparent');

				img.out('-page');
				img.out('+0+0');
				img.out(subTilesFilename[0]);
				img.out('-page');
				img.out('+256+0');
				img.out(subTilesFilename[1]);
				img.out('-page');
				img.out('+0+256');
				img.out(subTilesFilename[2]);
				img.out('-page');
				img.out('+256+256');
				img.out(subTilesFilename[3]);
				img.out('-mosaic');
				img.out('-resize');
				img.out('50%');

				img.write(filename, function (err) {
					if (err) {
						console.error(err);
						return
					}
					finishProcess();
					callback()
				})
			})
		}
	}

	function createEmptyTile(callback) {
		var t = gm(tileSize, tileSize, '#ffffffff');
		t.colors(2);
		t.toBuffer('PNG', function (err, buf) {
			if (err) console.error(err);
			emptyImageBuffer = buf;
			callback();
		});
	}

	function ensureFolder(folder) {
		if (!fs.existsSync(folder)) {
			ensureFolder(path.dirname(folder));
			fs.mkdirSync(folder);
		}
	}

	function sqr(v) {
		return v*v;
	}
}<|endoftext|>


<commit_before>import { run } from '@ember/runloop';
import { A } from '@ember/array';
import EmberObject from '@ember/object';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';

module('Unit | Service | ember cli', function(hooks) {
  setupTest(hooks);

  test('compiling a gist works', function(assert) {
    let done = assert.async();

    assert.expect(7);
    let service = this.owner.lookup('service:ember-cli');
    assert.ok(service);

    var gist = EmberObject.create({
      files: A([
        EmberObject.create({
          filePath: 'templates/application.hbs',
          extension: '.hbs',
          content: '
Hi, I\'m{{appName}}
'
        }),
        EmberObject.create({
          filePath: 'controllers/application.js',
          extension: '.js',
          content: 'import Ember from "ember";\n\nexport default Ember.Controller.extend({appName:"foo"});'
        }),
        EmberObject.create({
          filePath: 'twiddle.json',
          extension: '.json',
          content: `{
                    "version": "0.7.0",
                    "EmberENV": {
                      "FEATURES": {}
                    },
                    "options": {
                      "use_pods": false,
                      "enable-testing": false
                    },
                    "dependencies": {
                      "jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
                      "ember": "https://cdnjs.cloudflare.com/ajax/libs/ember.js/2.4.3/ember.debug.js",
                      "ember-data": "https://cdnjs.cloudflare.com/ajax/libs/ember-data.js/2.4.0/ember-data.js"
                    }
                  }`
        })
      ])
    });

    run(function() {
      service.compileGist(gist).then(function(output) {
        output = output.replace(/define\('([a-z0-9-/]+)'/gi,'define("$1"');
        assert.ok(output.indexOf('define("twiddle/router"')>-1, 'build contains router');
        assert.ok(output.indexOf('define("twiddle/initializers/router"')>-1, 'build contains router initializer');
        assert.ok(output.indexOf('define("twiddle/app"')>-1, 'build contains app');
        assert.ok(output.indexOf('define("twiddle/templates/application"')>-1, 'build contains template');
        assert.ok(output.indexOf('define("twiddle/controllers/application"')>-1, 'build contains controller');
        assert.ok(output.indexOf('define("twiddle/config/environment"')>-1, 'build contains config');
        done();
      });
    });
  });

  test("buildProperties() works as expected without replacements", function (assert) {
    assert.expect(3);

    var service = this.owner.lookup('service:ember-cli');
    var props = service.buildProperties('helper');

    assert.equal(props.filePath, 'helpers/my-helper.js', 'filePath set');
    assert.ok(props.content, 'has content');
    assert.ok(props.content.indexOf('<%=') === -1, 'No replacement tags in content');
  });

  test("buildProperties() works as expected with replacements", function (assert) {
    assert.expect(5);

    var service = this.owner.lookup('service:ember-cli');
    var props = service.buildProperties('helper', {
      camelizedModuleName: 'myHelper'
    });

    assert.equal(props.filePath, 'helpers/my-helper.js', 'filePath set');
    assert.ok(props.content, 'has content');
    assert.ok(props.content.indexOf('<%=') === -1, 'No replacement tags in content');
    assert.ok(props.content.indexOf('myHelper(params') !== -1, 'Replacements worked');
    assert.ok(props.content.indexOf('helper(myHelper)') !== -1, 'Replacements worked if multiple');
  });

  test('compileHbs includes moduleName', function(assert) {
    var service = this.owner.lookup('service:ember-cli');
    var result = service.compileHbs('foo', 'somePath/here.hbs');

    assert.ok(result.indexOf('twiddle/somePath/here') > -1, 'moduleName included');
  });

  test('compileHbs can include backticks', function(assert) {
    var template = "`stuff`";
    var service = this.owner.lookup('service:ember-cli');
    var result = service.compileHbs(template, 'some-path');
    var mungedCode = "\\`stuff\\`";

    assert.ok(result.indexOf(mungedCode) > -1, 'munged template included');
  });

  test("buildHtml works when testing not enabled", function(assert) {
    var service = this.owner.lookup('service:ember-cli');

    var twiddleJson = {
      "version": "0.5.0",
      "EmberENV": {
        "FEATURES": {}
      },
      "options": {
        "enable-testing": false
      },
      "dependencies": {
        "jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js"
      }
    };

    var gist = EmberObject.create({
      initialRoute: "/"
    });

    var output = service.buildHtml(gist, '/* app */', '/* styles */', twiddleJson);

    assert.ok(output.indexOf("window.location.hash='/';") > 0, "output sets initialRoute");
    assert.ok(output.indexOf('EmberENV = {"FEATURES":{}}') > 0, "output contains feature flags");
    assert.ok(output.indexOf('') > 0, "output includes dependency");
    assert.ok(output.indexOf('


<commit_before>/**
 * paginator.js
 * Description: A lightweight and dependency-free pagination library
 * Version: 0.0.1
 * Author: Ossama Edbali
 */

var paginator = (function () {
    'use strict';

    var _ = {},
        $ = {};

    var defaults = {
        'appendTo': null,
        'itemsPerPage': 10,
        'displayedPageNumbers': 5,
        'currentPage': 1,
        'margins': 2,
        'prevText': 'Prev',
        'nextText': 'Next',
        'theme': 'default' // or 'no-theme' (so it can be customised)
    };

    // BEGIN: Utilities
    $.extend = function (defaults, options) {
        var extended = {};
        var prop;
        for (prop in defaults) {
            if (Object.prototype.hasOwnProperty.call(defaults, prop)) {
                extended[prop] = defaults[prop];
            }
        }
        for (prop in options) {
            if (Object.prototype.hasOwnProperty.call(options, prop)) {
                extended[prop] = options[prop];
            }
        }
        return extended;
    };

    $.isElement = function (o) {
        return o.nodeType && o.nodeType === 1;
    };

    $.getElements = function (e) {
        if (typeof e === 'string') {
            return document.querySelectorAll(e); // NodeList
        }

        if ($.isElement(e)) {
            return e.children; // HTMLCollection
        }
    };

    $.getParent = function () {
        var o = this._opts;

        // [squeeze]: ternary op here
        if (o.appendTo === null) {
            // Append to elements parent
            var testElement = this._elements[0]; // [fix]: empty array
            return testElement.parentNode;
        }
        else {
            return document.querySelector(o.appendTo);
        }
    };

    $.isOutOfRange = function (i, arr) {
        return i < 0 || i >= arr.length;
    };

    $.toArray = function (collection) {
        return [].slice.call(collection);
    };

    $.wrap = function (fn) {
        var args = Array.prototype.slice.call(arguments, 1),
            self = this;

        return function (e) {
            e.preventDefault();
            fn.apply(self, args);
        };
    };
    // END: Utilities

    // BEGIN: Private member
    $.createLinks = function (parent) {
        var self = this,
            o = self._opts,
            elements = self._elements,
            numPages = Math.ceil(elements.length / o.itemsPerPage);

        // Create wrapper around the links
        var wrapper = document.createElement('div'),
            fragment = document.createDocumentFragment();
        wrapper.className = 'paginator-wrapper ' + (o.theme === 'default' ? 'default-theme' : 'no-theme');

        // Create previous
        var prev = document.createElement('a');
        prev.className = 'paginator-link';
        prev.setAttribute('href', '#');
        prev.innerHTML = o.prevText;
        prev.addEventListener('click', $.wrap.call(self, self.previous));
        fragment.appendChild(prev);

        // Create page links
        for (var i = 1; i <= numPages; i++) {
            var plink = document.createElement('a');
            plink.className = 'paginator-link';
            if (o.currentPage === i) {
                plink.className += ' paginator-active';
            }
            plink.setAttribute('href', '#');
            plink.innerHTML = i + '';
            plink.addEventListener('click', $.wrap.call(self, self.select, i - 1), false);

            self._links.push(plink);
            fragment.appendChild(plink);

            // Add dots
            if (i === o.margins || numPages - i === o.margins) {
                var dots = document.createElement('span');
                dots.className = 'paginator-dots';
                dots.innerHTML = '...';
                fragment.appendChild(dots);
            }
        }

        // Create next
        var next = document.createElement('a');
        next.className = 'paginator-link';
        next.setAttribute('href', '#');
        next.innerHTML = o.nextText;
        next.addEventListener('click', $.wrap.call(self, self.next));
        fragment.appendChild(next);

        // Append to wrapper and save
        wrapper.appendChild(fragment);
        self._linksWrapper = wrapper;

        if (parent) {
            parent.appendChild(wrapper);
        }
    };

    $.createPages = function (parent) {
        var o = this._opts,
            elements = $.toArray(this._elements),
            numItems = elements.length,
            itemsPerPage = o.itemsPerPage,
            numPages = Math.ceil(numItems / itemsPerPage);

        for (var i = 1; i <= numPages; i++) {
            var page = document.createElement('div'),
                toAdd = elements.slice(0, itemsPerPage);

            page.className = 'paginator-page';
            if (o.currentPage === i) {
                page.className += ' paginator-active';
            }

            // Append to page
            for (var j = 0, l = toAdd.length; j < l; j++) {
                page.appendChild(toAdd[j]);
            }

            // Append page and update elements
            parent.appendChild(page);
            this._pages.push(page);
            elements = elements.slice(itemsPerPage);
        }
    };

    $.showInterval = function () {
        var o = this._opts;
        var activePageNum = this._activePageNum;
        var numLinks = this._links.length;

        // Reset all links
        for (var i = 0, l = this._links.length; i < l; i++) {
            this._links[i].style.display = 'none';
        }

        // Show margins
        for (i = 0; i < o.margins; i++) {
            this._links[i].style.display = 'inline';
        }

        for (i = numLinks - 1; i >= numLinks - o.margins; i--) {
            this._links[i].style.display = 'inline';
        }

        // Show interval
        var start = (activePageNum + o.displayedPageNumbers >= numLinks) ? numLinks - o.displayedPageNumbers : activePageNum,
            end = (activePageNum + o.displayedPageNumbers >= numLinks) ? numLinks : activePageNum + o.displayedPageNumbers;

        for (i = start; i < end; i++) {
            if (this._links[i].style.display === 'none') {
                this._links[i].style.display = 'inline';
            }
        }

        // Show/hide dots
        var dots = this._linksWrapper.getElementsByClassName('paginator-dots');
        dots[0].style.display = (start > o.margins) ? 'inline' : 'none';
        dots[1].style.display = (end < numLinks - o.margins) ? 'inline' : 'none';
    };

    // END: Private member

    _.Paginator = function (elements, opts) {
        var self = this;

        // Unpack options
        opts = opts || {};
        self._opts = $.extend(defaults, opts);
        self._elements = $.getElements(elements);
        self._pages = [];
        self._links = [];
        self._linksWrapper = null;
        self._activePageNum = self._opts.currentPage - 1;

        // Initialise links and pages
        var parent = $.getParent.call(self);
        $.createPages.call(self, parent);
        $.createLinks.call(self, parent);
        $.showInterval.call(self);
    };

    _.create = function (elements, opts) {
        return new _.Paginator(elements, opts);
    };

    // BEGIN: Public methods
    _.Paginator.prototype.select = function (pageNum) {
        var currentPage = this.getCurrentPage();

        // Remove
        currentPage.classList.remove('paginator-active');
        this._links[this._activePageNum].classList.remove('paginator-active');

        // Add
        this._pages[pageNum].classList.add('paginator-active');
        this._links[pageNum].classList.add('paginator-active');

        // Update active page number
        this._activePageNum = pageNum;
        $.showInterval.call(this);
    };

    _.Paginator.prototype.getCurrentPage = function () {
        return this._pages[this._activePageNum];
    };

    _.Paginator.prototype.previous = function () {
        var pageNum = this._activePageNum - 1;
        if (!$.isOutOfRange(pageNum, this._pages)) {
            this.select(pageNum);
        }
    };

    _.Paginator.prototype.next = function () {
        var pageNum = this._activePageNum + 1;
        if (!$.isOutOfRange(pageNum, this._pages)) {
            this.select(pageNum);
        }
    };

    _.Paginator.prototype.pagesCount = function () {
        return this._pages.length;
    };

    _.Paginator.prototype.disable = function () {

    };

    _.Paginator.prototype.enable = function () {

    };

    // END: Public methods

    return _;

})();<commit_msg>Added return values for select methods<commit_after>/**
 * paginator.js
 * Description: A lightweight and dependency-free pagination library
 * Version: 0.0.1
 * Author: Ossama Edbali
 */

var paginator = (function () {
    'use strict';

    var _ = {},
        $ = {};

    var defaults = {
        'appendTo': null,
        'itemsPerPage': 10,
        'displayedPageNumbers': 5,
        'currentPage': 1,
        'margins': 2,
        'prevText': 'Prev',
        'nextText': 'Next',
        'theme': 'default' // or 'no-theme' (so it can be customised)
    };

    // BEGIN: Utilities
    $.extend = function (defaults, options) {
        var extended = {};
        var prop;
        for (prop in defaults) {
            if (Object.prototype.hasOwnProperty.call(defaults, prop)) {
                extended[prop] = defaults[prop];
            }
        }
        for (prop in options) {
            if (Object.prototype.hasOwnProperty.call(options, prop)) {
                extended[prop] = options[prop];
            }
        }
        return extended;
    };

    $.isElement = function (o) {
        return o.nodeType && o.nodeType === 1;
    };

    $.getElements = function (e) {
        if (typeof e === 'string') {
            return document.querySelectorAll(e); // NodeList
        }

        if ($.isElement(e)) {
            return e.children; // HTMLCollection
        }
    };

    $.getParent = function () {
        var o = this._opts;

        // [squeeze]: ternary op here
        if (o.appendTo === null) {
            // Append to elements parent
            var testElement = this._elements[0]; // [fix]: empty array
            return testElement.parentNode;
        }
        else {
            return document.querySelector(o.appendTo);
        }
    };

    $.isOutOfRange = function (i, arr) {
        return i < 0 || i >= arr.length;
    };

    $.toArray = function (collection) {
        return [].slice.call(collection);
    };

    $.wrap = function (fn) {
        var args = Array.prototype.slice.call(arguments, 1),
            self = this;

        return function (e) {
            e.preventDefault();
            fn.apply(self, args);
        };
    };
    // END: Utilities

    // BEGIN: Private member
    $.createLinks = function (parent) {
        var self = this,
            o = self._opts,
            elements = self._elements,
            numPages = Math.ceil(elements.length / o.itemsPerPage);

        // Create wrapper around the links
        var wrapper = document.createElement('div'),
            fragment = document.createDocumentFragment();
        wrapper.className = 'paginator-wrapper ' + (o.theme === 'default' ? 'default-theme' : 'no-theme');

        // Create previous
        var prev = document.createElement('a');
        prev.className = 'paginator-link';
        prev.setAttribute('href', '#');
        prev.innerHTML = o.prevText;
        prev.addEventListener('click', $.wrap.call(self, self.previous));
        fragment.appendChild(prev);

        // Create page links
        for (var i = 1; i <= numPages; i++) {
            var plink = document.createElement('a');
            plink.className = 'paginator-link';
            if (o.currentPage === i) {
                plink.className += ' paginator-active';
            }
            plink.setAttribute('href', '#');
            plink.innerHTML = i + '';
            plink.addEventListener('click', $.wrap.call(self, self.select, i - 1), false);

            self._links.push(plink);
            fragment.appendChild(plink);

            // Add dots
            if (i === o.margins || numPages - i === o.margins) {
                var dots = document.createElement('span');
                dots.className = 'paginator-dots';
                dots.innerHTML = '...';
                fragment.appendChild(dots);
            }
        }

        // Create next
        var next = document.createElement('a');
        next.className = 'paginator-link';
        next.setAttribute('href', '#');
        next.innerHTML = o.nextText;
        next.addEventListener('click', $.wrap.call(self, self.next));
        fragment.appendChild(next);

        // Append to wrapper and save
        wrapper.appendChild(fragment);
        self._linksWrapper = wrapper;

        if (parent) {
            parent.appendChild(wrapper);
        }
    };

    $.createPages = function (parent) {
        var o = this._opts,
            elements = $.toArray(this._elements),
            numItems = elements.length,
            itemsPerPage = o.itemsPerPage,
            numPages = Math.ceil(numItems / itemsPerPage);

        for (var i = 1; i <= numPages; i++) {
            var page = document.createElement('div'),
                toAdd = elements.slice(0, itemsPerPage);

            page.className = 'paginator-page';
            if (o.currentPage === i) {
                page.className += ' paginator-active';
            }

            // Append to page
            for (var j = 0, l = toAdd.length; j < l; j++) {
                page.appendChild(toAdd[j]);
            }

            // Append page and update elements
            parent.appendChild(page);
            this._pages.push(page);
            elements = elements.slice(itemsPerPage);
        }
    };

    $.showInterval = function () {
        var o = this._opts;
        var activePageNum = this._activePageNum;
        var numLinks = this._links.length;

        // Reset all links
        for (var i = 0, l = this._links.length; i < l; i++) {
            this._links[i].style.display = 'none';
        }

        // Show margins
        for (i = 0; i < o.margins; i++) {
            this._links[i].style.display = 'inline';
        }

        for (i = numLinks - 1; i >= numLinks - o.margins; i--) {
            this._links[i].style.display = 'inline';
        }

        // Show interval
        var start = (activePageNum + o.displayedPageNumbers >= numLinks) ? numLinks - o.displayedPageNumbers : activePageNum,
            end = (activePageNum + o.displayedPageNumbers >= numLinks) ? numLinks : activePageNum + o.displayedPageNumbers;

        for (i = start; i < end; i++) {
            if (this._links[i].style.display === 'none') {
                this._links[i].style.display = 'inline';
            }
        }

        // Show/hide dots
        var dots = this._linksWrapper.getElementsByClassName('paginator-dots');
        dots[0].style.display = (start > o.margins) ? 'inline' : 'none';
        dots[1].style.display = (end < numLinks - o.margins) ? 'inline' : 'none';
    };

    // END: Private member

    _.Paginator = function (elements, opts) {
        var self = this;

        // Unpack options
        opts = opts || {};
        self._opts = $.extend(defaults, opts);
        self._elements = $.getElements(elements);
        self._pages = [];
        self._links = [];
        self._linksWrapper = null;
        self._activePageNum = self._opts.currentPage - 1;

        // Initialise links and pages
        var parent = $.getParent.call(self);
        $.createPages.call(self, parent);
        $.createLinks.call(self, parent);
        $.showInterval.call(self);
    };

    _.create = function (elements, opts) {
        return new _.Paginator(elements, opts);
    };

    // BEGIN: Public methods
    _.Paginator.prototype.select = function (pageNum) {
        var currentPage = this.getCurrentPage();

        // Remove
        currentPage.classList.remove('paginator-active');
        this._links[this._activePageNum].classList.remove('paginator-active');

        // Add
        this._pages[pageNum].classList.add('paginator-active');
        this._links[pageNum].classList.add('paginator-active');

        // Update active page number
        this._activePageNum = pageNum;
        $.showInterval.call(this);

        return {
            'page': this._pages[pageNum],
            'link': this._links[pageNum]
        }
    };

    _.Paginator.prototype.getCurrentPage = function () {
        return this._pages[this._activePageNum];
    };

    _.Paginator.prototype.previous = function () {
        var pageNum = this._activePageNum - 1;
        if (!$.isOutOfRange(pageNum, this._pages)) {
            return this.select(pageNum);
        }

        return null
    };

    _.Paginator.prototype.next = function () {
        var pageNum = this._activePageNum + 1;
        if (!$.isOutOfRange(pageNum, this._pages)) {
            return this.select(pageNum);
        }

        return null;
    };

    _.Paginator.prototype.pagesCount = function () {
        return this._pages.length;
    };

    _.Paginator.prototype.disable = function () {

    };

    _.Paginator.prototype.enable = function () {

    };

    // END: Public methods

    return _;

})();<|endoftext|>


<commit_before>/**
 * Very basic server that simply responds with hello world
 *
 **/

var http = require("http");

http.createServer(function(request, response) {
	response.writeHead(200, {"Content-Type": "text/plain"});
	response.write("Hello World");
	response.end();
    }).listen(8000);<commit_msg>onRequest is now a named function<commit_after>
/**
 * Very basic server that simply responds with hello world
 *
 **/

var http = require("http");

/**
 * onRequest will respond to all http requests
 */
function onRequest(request, response) {
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello World");
    response.end();
}

http.createServer(onRequest).listen(8000);
console.log("started");
<|endoftext|>


<commit_before>/*
 This context helper adds a json function to the
 context and callsback when done.

 The json function takes json object, and allows you to
manipulate it in various ways, and either send it as
a response ( .send() ), return it as a string
( .toString() ), or return it as an object ( .toObject() ).

 */

var HyperJson = require('../HyperJson');
var HyperJsonCollection = require('../HyperJsonCollection');

var JsonContextHelper = function($, handler, cb){
  $.json = function(obj){
    var json = new HyperJson(obj);
    json.send = function(){send($, json);};
    return json;
  };
  $.jsonCollection = function(objArr){
    var json = new HyperJsonCollection(objArr);
    json.send = function(){send($, json);};
    return json;
  };
};

module.exports = JsonContextHelper;

function send($, json){
  if ($.app.autoLink){
    addDefaultLinks($, json);
  }
  $.res.setHeader('content-type', 'application/json');
  $.res.end(json.toString());
}

function addDefaultLinks($, json){
  var current = json.toObject();
  if (!current._links || !current._links.self){
    json.link('self', $.uri.self());
  }
  if (!current._links || !current._links.parent){
    try {
      var parent = $.uri.parent();
      json.link('parent', parent);
    } catch(ex){
      if (ex.message !== "The given path has no parent path"){
        throw ex;
      }
    }
  }
  return current;
}

<commit_msg>removed superfluous default self links.<commit_after>/*
 This context helper adds a json function to the
 context and callsback when done.

 The json function takes json object, and allows you to
manipulate it in various ways, and either send it as
a response ( .send() ), return it as a string
( .toString() ), or return it as an object ( .toObject() ).

 */

var HyperJson = require('../HyperJson');
var HyperJsonCollection = require('../HyperJsonCollection');

var JsonContextHelper = function($, handler, cb){
  $.json = function(obj){
    var json = new HyperJson(obj);
    json.send = function(){send($, json);};
    return json;
  };
  $.jsonCollection = function(objArr){
    var json = new HyperJsonCollection(objArr);
    json.send = function(){send($, json);};
    return json;
  };
};

module.exports = JsonContextHelper;

function send($, json){
  if ($.app.autoLink){
    addDefaultLinks($, json);
  }
  $.res.setHeader('content-type', 'application/json');
  $.res.end(json.toString());
}

function addDefaultLinks($, json){
  var current = json.toObject();
  if (!current._links || !current._links.parent){
    try {
      var parent = $.uri.parent();
      json.link('parent', parent);
    } catch(ex){
      if (ex.message !== "The given path has no parent path"){
        throw ex;
      }
    }
  }
  return current;
}

<|endoftext|>


<commit_before>// ==UserScript==
// @id             iitc-plugin-portals-count@yenky
// @name           IITC plugin: Show total counts of portals
// @version        0.0.5.@@DATETIMEVERSION@@
// @namespace      https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL      @@UPDATEURL@@
// @downloadURL    @@DOWNLOADURL@@
// @description    [@@BUILDNAME@@-@@BUILDDATE@@] Display a list of all localized portals by level and faction
// @include        https://www.ingress.com/intel*
// @include        http://www.ingress.com/intel*
// @match          https://www.ingress.com/intel*
// @match          http://www.ingress.com/intel*
// ==/UserScript==

/* whatsnew
* 0.0.5 : changed table layout, added some colors
* 0.0.4 : reverse show order of portals, using MAX_PORTAL_LEVEL now for array, changed table layout to be more compact, cleaned up code
* 0.0.3 : fixed incorrect rounded portal levels, adjusted viewport
* 0.0.2 : fixed counts to be reset after scrolling
* 0.0.1 : initial release, show count of portals
* todo :
*/

function wrapper() {
// ensure plugin framework is there, even if iitc is not yet loaded
if(typeof window.plugin !== 'function') window.plugin = function() {};

// PLUGIN START ////////////////////////////////////////////////////////

// use own namespace for plugin
window.plugin.portalcounts = function() {};
window.VIEWPORT_PAD_RATIO = 0.1;

//count portals for each level avalaible on the map
window.plugin.portalcounts.getPortals = function(){
  //console.log('** getPortals');
  // just count portals in viewport, default: 0.3
  var retval=false;
  window.plugin.portalcounts.enlP = 0;
  window.plugin.portalcounts.resP = 0;
  window.plugin.portalcounts.neuP = 0;

  window.plugin.portalcounts.PortalsEnl = new Array();
  window.plugin.portalcounts.PortalsRes = new Array();
  for(var level = window.MAX_PORTAL_LEVEL; level > 0; level--){
    window.plugin.portalcounts.PortalsEnl[level] = 0;
    window.plugin.portalcounts.PortalsRes[level] = 0;
  }

  $.each(window.portals, function(i, portal) {
    retval=true;
    var d = portal.options.details;
    var team = portal.options.team;
    var level = Math.floor(getPortalLevel(d));
    switch (team){
      case 1 :
        window.plugin.portalcounts.resP++;
        window.plugin.portalcounts.PortalsRes[level]++;
        break;
      case 2 :
        window.plugin.portalcounts.enlP++;
        window.plugin.portalcounts.PortalsEnl[level]++;
        break;
      default:
        window.plugin.portalcounts.neuP++;
        break;
    }
  });

  //get portals informations from IITC
  var minlvl = getMinPortalLevel();

  var counts = '
';
  if(retval) {
    counts += '
	Enlightment	Resistance
';  //'+window.plugin.portalcounts.enlP+' Portal(s)
';
    for(var level = window.MAX_PORTAL_LEVEL; level > 0; level--){
      counts += '
Level '+level+'	';
      if(minlvl > level)
        counts += 'zoom in to see portals in this level	';
      else
        counts += ''+window.plugin.portalcounts.PortalsEnl[level]+'	'+window.plugin.portalcounts.PortalsRes[level]+'	';
      counts += '
';
    }
    counts += '
&nbsp
';
    counts += '
Neutral:	';
    if(minlvl > 0)
      counts += 'zoom in to see unclaimed';
    else
      counts += window.plugin.portalcounts.neuP;
    counts += ' Portal(s)
';
    counts += '
Enlightment:	'+window.plugin.portalcounts.enlP+' Portal(s)
';
    counts += '
Resistance:	'+window.plugin.portalcounts.resP+' Portal(s)
';
  } else
    counts += '
No Portals in range !
';
  counts += '
';
  alert('
'+counts+'
');
}

var setup =  function() {
  $('body').append('

');
  $('#toolbox').append('Portalcounts');
  $('head').append('');
}

// PLUGIN END //////////////////////////////////////////////////////////

if(window.iitcLoaded && typeof setup === 'function') {
  setup();
} else {
  if(window.bootPlugins)
    window.bootPlugins.push(setup);
  else
    window.bootPlugins = [setup];
}
} // wrapper end
// inject code into site context
var script = document.createElement('script');
script.appendChild(document.createTextNode('('+ wrapper +')();'));
(document.body || document.head || document.documentElement).appendChild(script);
<commit_msg>Ignoring out of bounds portals by current bounds (better than manipulating default value)<commit_after>// ==UserScript==
// @id             iitc-plugin-portals-count@yenky
// @name           IITC plugin: Show total counts of portals
// @version        0.0.6.@@DATETIMEVERSION@@
// @namespace      https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL      @@UPDATEURL@@
// @downloadURL    @@DOWNLOADURL@@
// @description    [@@BUILDNAME@@-@@BUILDDATE@@] Display a list of all localized portals by level and faction
// @include        https://www.ingress.com/intel*
// @include        http://www.ingress.com/intel*
// @match          https://www.ingress.com/intel*
// @match          http://www.ingress.com/intel*
// ==/UserScript==

/* whatsnew
* 0.0.6 : ignoring outside bounds portals (even if close to)
* 0.0.5 : changed table layout, added some colors
* 0.0.4 : reverse show order of portals, using MAX_PORTAL_LEVEL now for array, changed table layout to be more compact, cleaned up code
* 0.0.3 : fixed incorrect rounded portal levels, adjusted viewport
* 0.0.2 : fixed counts to be reset after scrolling
* 0.0.1 : initial release, show count of portals
* todo :
*/

function wrapper() {
// ensure plugin framework is there, even if iitc is not yet loaded
if(typeof window.plugin !== 'function') window.plugin = function() {};

// PLUGIN START ////////////////////////////////////////////////////////

// use own namespace for plugin
window.plugin.portalcounts = function() {};

//count portals for each level avalaible on the map
window.plugin.portalcounts.getPortals = function(){
  //console.log('** getPortals');
  var retval=false;
  var displayBounds = map.getBounds();
  window.plugin.portalcounts.enlP = 0;
  window.plugin.portalcounts.resP = 0;
  window.plugin.portalcounts.neuP = 0;

  window.plugin.portalcounts.PortalsEnl = new Array();
  window.plugin.portalcounts.PortalsRes = new Array();
  for(var level = window.MAX_PORTAL_LEVEL; level > 0; level--){
    window.plugin.portalcounts.PortalsEnl[level] = 0;
    window.plugin.portalcounts.PortalsRes[level] = 0;
  }

  $.each(window.portals, function(i, portal) {
    retval=true;
    var d = portal.options.details;
    var team = portal.options.team;
    var level = Math.floor(getPortalLevel(d));
    // just count portals in viewport
    if(!displayBounds.contains(portal.getLatLng())) return true;
    switch (team){
      case 1 :
        window.plugin.portalcounts.resP++;
        window.plugin.portalcounts.PortalsRes[level]++;
        break;
      case 2 :
        window.plugin.portalcounts.enlP++;
        window.plugin.portalcounts.PortalsEnl[level]++;
        break;
      default:
        window.plugin.portalcounts.neuP++;
        break;
    }
  });

  //get portals informations from IITC
  var minlvl = getMinPortalLevel();

  var counts = '
';
  if(retval) {
    counts += '
	Enlightment	Resistance
';  //'+window.plugin.portalcounts.enlP+' Portal(s)
';
    for(var level = window.MAX_PORTAL_LEVEL; level > 0; level--){
      counts += '
Level '+level+'	';
      if(minlvl > level)
        counts += 'zoom in to see portals in this level	';
      else
        counts += ''+window.plugin.portalcounts.PortalsEnl[level]+'	'+window.plugin.portalcounts.PortalsRes[level]+'	';
      counts += '
';
    }
    counts += '
&nbsp
';
    counts += '
Neutral:	';
    if(minlvl > 0)
      counts += 'zoom in to see unclaimed';
    else
      counts += window.plugin.portalcounts.neuP;
    counts += ' Portal(s)
';
    counts += '
Enlightment:	'+window.plugin.portalcounts.enlP+' Portal(s)
';
    counts += '
Resistance:	'+window.plugin.portalcounts.resP+' Portal(s)
';
  } else
    counts += '
No Portals in range !
';
  counts += '
';
  alert('
'+counts+'
');
}

var setup =  function() {
  $('body').append('

');
  $('#toolbox').append('Portalcounts');
  $('head').append('');
}

// PLUGIN END //////////////////////////////////////////////////////////

if(window.iitcLoaded && typeof setup === 'function') {
  setup();
} else {
  if(window.bootPlugins)
    window.bootPlugins.push(setup);
  else
    window.bootPlugins = [setup];
}
} // wrapper end
// inject code into site context
var script = document.createElement('script');
script.appendChild(document.createTextNode('('+ wrapper +')();'));
(document.body || document.head || document.documentElement).appendChild(script);
<|endoftext|>


<commit_before>// Write your package code here!
<commit_msg>remove autoform-polygon-map.js<commit_after><|endoftext|>