<commit_before>import {chain, forEach, map} from 'lodash'
import Reflux from 'reflux'
import Immutable from 'immutable'

import Student from '../models/student'
import demoStudent from '../models/demoStudent.json'

import studentActions from './studentActions'
import notificationActions from './notificationActions'

let cleanLocalStorage = () => {
	localStorage.removeItem('activeStudentId')
	localStorage.removeItem('student-v3.0a6')
}

let studentStore = Reflux.createStore({
	listenables: studentActions,

	init() {
		this.students = Immutable.Map()
		this.history = Immutable.Stack()
		this.future = Immutable.Stack()

		this._loadData()
	},

	getInitialState() {
		return this.students
	},

	undo() {
		if (this.history.size) {
			// console.log('undoing...')
			this.future = this.future.push(this.students)
			this.students = this.history.first()
			this.history = this.history.pop()
			this._postChange()
		}
	},

	redo() {
		if (this.future.size) {
			// console.log('redoing...')
			this.history = this.history.push(this.students)
			this.students = this.future.first()
			this.future = this.future.pop()
			this._postChange()
		}
	},

	_preChange() {
		this.history = this.history.push(this.students)
		this.future = this.future.clear()
	},

	_postChange() {
		// console.groupCollapsed('studentStore._postChange')
		// console.group('studentStore._postChange')
		// console.log('students', this.students)
		this.students.forEach(student => student.save())
		// console.groupEnd('studentStore._postChange')
		this.trigger(this.students)
	},

	resetStudentToDemo(studentId) {
		// console.info(`resetting student ${studentId} to the demo student`)
		let rawStudent = demoStudent
		rawStudent.id = studentId

		let student = new Student(rawStudent)
		window.studentData = student

		this._preChange()
		this.students = this.students.set(studentId, student)
		this._postChange()
	},

	reloadStudents() {
		let loadedIds = this.students.map(s => s.id).toList()
		let localIds = Immutable.List(localStorage.getItem('studentIds') || [])

		if (!loadedIds.equals(localIds))
			this._loadData()
	},

	_loadData(studentId) {
		// console.log('studentStore._loadData')

		// studentIds is a list of IDs we know about.
		let studentIds =
			// Get the list of students we know about, or the string 'null'
			// if localStorage doesn't have the key 'studentIds'.
			JSON.parse(localStorage.getItem('studentIds')) ||
			// If both those fail, grab the really old 'student-v3.0a6'
			['student-v3.0a6']

		if (studentId) {
			studentIds.push(studentId)
		}

		// Fetch and load the students from their IDs
		let localStudents = chain(studentIds)
			// pull the students from localStorage
			.map(id => [id, localStorage.getItem(id)])
			// Remove any broken students from localStorage
			.map(idAndStudent => {
				let [id, rawStudent] = idAndStudent
				if (rawStudent === '[object Object]')
					localStorage.removeItem(id)
				return rawStudent
			})
			// filter out any that don't exist
			.reject(rawStudent => rawStudent === null)
			// and any that are bad
			.reject(rawStudent => rawStudent === '[object Object]')
			// then process them
			.map((rawStudent, idx) => {
				// basicStudent defaults to an empty object so that the constructor
				// has something to build from.
				let basicStudent = {}
				try {
					basicStudent = JSON.parse(rawStudent)
				}
				catch (e) {
					notificationActions.logError('error parsing student', basicStudent)
				}

				if (basicStudent.id === 'student-v3.0a6')
					delete basicStudent.id

				// Make the student...
				let fleshedStudent = new Student(basicStudent)

				// and save them, of course
				fleshedStudent.save()

				return fleshedStudent
			})
			.value()

		// Update the studentIds list from the current list of students
		localStorage.setItem('studentIds', JSON.stringify(map(localStudents, s => s.id)))

		// Add them to students
		this.students = this.students.withMutations(students => {
			forEach(localStudents, localStudent => {
				students = students.set(localStudent.id, localStudent)
			})
			return students
		})

		// Clean up localStorage
		cleanLocalStorage()

		this._postChange()
	},

	initStudent() {
		let fleshedStudent = new Student()
		fleshedStudent.save()
		this._preChange()
		this._loadData(fleshedStudent.id)
	},

	_change(studentId, method, ...args) {
		this._preChange()
		this.students = this.students.set(studentId, this.students.get(studentId)[method](...args))
		this._postChange()
	},

	_alter(pathToData, method, ...args) {
		this._preChange()
		this.students = this.students.setIn(pathToData, this.students.getIn(pathToData)[method](...args))
		this._postChange()
	},

	changeName(studentId, ...args)               { this._change(studentId, 'changeName',               ...args) },
	changeCreditsNeeded(studentId, ...args)      { this._change(studentId, 'changeCreditsNeeded',      ...args) },
	changeMatriculation(studentId, ...args)      { this._change(studentId, 'changeMatriculation',      ...args) },
	changeGraduation(studentId, ...args)         { this._change(studentId, 'changeGraduation',         ...args) },
	changeSetting(studentId, key, value)         { this._change(studentId, 'changeSetting',         key, value) },
	addArea(studentId, ...args)                  { this._change(studentId, 'addArea',                  ...args) },
	addSchedule(studentId, ...args)              { this._change(studentId, 'addSchedule',              ...args) },
	addFabrication(studentId, ...args)           { this._change(studentId, 'addArea',                  ...args) },
	addOverride(studentId, ...args)              { this._change(studentId, 'addSchedule',              ...args) },
	removeArea(studentId, ...args)               { this._change(studentId, 'removeArea',               ...args) },
	removeMultipleAreas(studentId, ...args)      { this._change(studentId, 'removeMultipleArea',       ...args) },
	destroySchedule(studentId, ...args)          { this._change(studentId, 'destroySchedule',          ...args) },
	destroyMultipleSchedules(studentId, ...args) { this._change(studentId, 'destroyMultipleSchedules', ...args) },
	moveCourse(studentId, ...args)               { this._change(studentId, 'moveCourse',               ...args) },

	renameSchedule(studentId, scheduleId, ...args)  { this._alter([studentId, 'schedules', scheduleId], 'rename',        ...args) },
	reorderSchedule(studentId, scheduleId, ...args) { this._alter([studentId, 'schedules', scheduleId], 'reorder',       ...args) },
	moveSchedule(studentId, scheduleId, ...args)    { this._alter([studentId, 'schedules', scheduleId], 'move',          ...args) },
	addCourse(studentId, scheduleId, ...args)       { this._alter([studentId, 'schedules', scheduleId], 'addCourse',     ...args) },
	removeCourse(studentId, scheduleId, ...args)    { this._alter([studentId, 'schedules', scheduleId], 'removeCourse',  ...args) },
	reorderCourse(studentId, scheduleId, ...args)   { this._alter([studentId, 'schedules', scheduleId], 'reorderCourse', ...args) },
	reorderArea(studentId, areaId, ...args)         { this._alter([studentId, 'studies', areaId],       'reorder',       ...args) },
})

window.store = studentStore

export default studentStore
<commit_msg>Don't load a studentId if it's already in studentIds<commit_after>import {chain, forEach, map, uniq} from 'lodash'
import Reflux from 'reflux'
import Immutable from 'immutable'

import Student from '../models/student'
import demoStudent from '../models/demoStudent.json'

import studentActions from './studentActions'
import notificationActions from './notificationActions'

let cleanLocalStorage = () => {
	localStorage.removeItem('activeStudentId')
	localStorage.removeItem('student-v3.0a6')
}

let studentStore = Reflux.createStore({
	listenables: studentActions,

	init() {
		this.students = Immutable.Map()
		this.history = Immutable.Stack()
		this.future = Immutable.Stack()

		this._loadData()
	},

	getInitialState() {
		return this.students
	},

	undo() {
		if (this.history.size) {
			// console.log('undoing...')
			this.future = this.future.push(this.students)
			this.students = this.history.first()
			this.history = this.history.pop()
			this._postChange()
		}
	},

	redo() {
		if (this.future.size) {
			// console.log('redoing...')
			this.history = this.history.push(this.students)
			this.students = this.future.first()
			this.future = this.future.pop()
			this._postChange()
		}
	},

	_preChange() {
		this.history = this.history.push(this.students)
		this.future = this.future.clear()
	},

	_postChange() {
		// console.groupCollapsed('studentStore._postChange')
		// console.group('studentStore._postChange')
		// console.log('students', this.students)
		this.students.forEach(student => student.save())
		// console.groupEnd('studentStore._postChange')
		this.trigger(this.students)
	},

	resetStudentToDemo(studentId) {
		// console.info(`resetting student ${studentId} to the demo student`)
		let rawStudent = demoStudent
		rawStudent.id = studentId

		let student = new Student(rawStudent)
		window.studentData = student

		this._preChange()
		this.students = this.students.set(studentId, student)
		this._postChange()
	},

	reloadStudents() {
		let loadedIds = this.students.map(s => s.id).toList()
		let localIds = Immutable.List(localStorage.getItem('studentIds') || [])

		if (!loadedIds.equals(localIds))
			this._loadData()
	},

	_loadData(studentId) {
		// console.log('studentStore._loadData')

		// studentIds is a list of IDs we know about.
		let studentIds =
			// Get the list of students we know about, or the string 'null'
			// if localStorage doesn't have the key 'studentIds'.
			JSON.parse(localStorage.getItem('studentIds')) ||
			// If both those fail, grab the really old 'student-v3.0a6'
			['student-v3.0a6']

		if (studentId) {
			studentIds.push(studentId)
		}

		studentIds = uniq(studentIds)

		// Fetch and load the students from their IDs
		let localStudents = chain(studentIds)
			// pull the students from localStorage
			.map(id => [id, localStorage.getItem(id)])
			// Remove any broken students from localStorage
			.map(idAndStudent => {
				let [id, rawStudent] = idAndStudent
				if (rawStudent === '[object Object]')
					localStorage.removeItem(id)
				return rawStudent
			})
			// filter out any that don't exist
			.reject(rawStudent => rawStudent === null)
			// and any that are bad
			.reject(rawStudent => rawStudent === '[object Object]')
			// then process them
			.map((rawStudent, idx) => {
				// basicStudent defaults to an empty object so that the constructor
				// has something to build from.
				let basicStudent = {}
				try {
					basicStudent = JSON.parse(rawStudent)
				}
				catch (e) {
					notificationActions.logError('error parsing student', basicStudent)
				}

				if (basicStudent.id === 'student-v3.0a6')
					delete basicStudent.id

				// Make the student...
				let fleshedStudent = new Student(basicStudent)

				// and save them, of course
				fleshedStudent.save()

				return fleshedStudent
			})
			.value()

		// Update the studentIds list from the current list of students
		localStorage.setItem('studentIds', JSON.stringify(map(localStudents, s => s.id)))

		// Add them to students
		this.students = this.students.withMutations(students => {
			forEach(localStudents, localStudent => {
				students = students.set(localStudent.id, localStudent)
			})
			return students
		})

		// Clean up localStorage
		cleanLocalStorage()

		this._postChange()
	},

	initStudent() {
		let fleshedStudent = new Student()
		fleshedStudent.save()
		this._preChange()
		this._loadData(fleshedStudent.id)
	},

	_change(studentId, method, ...args) {
		this._preChange()
		this.students = this.students.set(studentId, this.students.get(studentId)[method](...args))
		this._postChange()
	},

	_alter(pathToData, method, ...args) {
		this._preChange()
		this.students = this.students.setIn(pathToData, this.students.getIn(pathToData)[method](...args))
		this._postChange()
	},

	changeName(studentId, ...args)               { this._change(studentId, 'changeName',               ...args) },
	changeCreditsNeeded(studentId, ...args)      { this._change(studentId, 'changeCreditsNeeded',      ...args) },
	changeMatriculation(studentId, ...args)      { this._change(studentId, 'changeMatriculation',      ...args) },
	changeGraduation(studentId, ...args)         { this._change(studentId, 'changeGraduation',         ...args) },
	changeSetting(studentId, key, value)         { this._change(studentId, 'changeSetting',         key, value) },
	addArea(studentId, ...args)                  { this._change(studentId, 'addArea',                  ...args) },
	addSchedule(studentId, ...args)              { this._change(studentId, 'addSchedule',              ...args) },
	addFabrication(studentId, ...args)           { this._change(studentId, 'addArea',                  ...args) },
	addOverride(studentId, ...args)              { this._change(studentId, 'addSchedule',              ...args) },
	removeArea(studentId, ...args)               { this._change(studentId, 'removeArea',               ...args) },
	removeMultipleAreas(studentId, ...args)      { this._change(studentId, 'removeMultipleArea',       ...args) },
	destroySchedule(studentId, ...args)          { this._change(studentId, 'destroySchedule',          ...args) },
	destroyMultipleSchedules(studentId, ...args) { this._change(studentId, 'destroyMultipleSchedules', ...args) },
	moveCourse(studentId, ...args)               { this._change(studentId, 'moveCourse',               ...args) },

	renameSchedule(studentId, scheduleId, ...args)  { this._alter([studentId, 'schedules', scheduleId], 'rename',        ...args) },
	reorderSchedule(studentId, scheduleId, ...args) { this._alter([studentId, 'schedules', scheduleId], 'reorder',       ...args) },
	moveSchedule(studentId, scheduleId, ...args)    { this._alter([studentId, 'schedules', scheduleId], 'move',          ...args) },
	addCourse(studentId, scheduleId, ...args)       { this._alter([studentId, 'schedules', scheduleId], 'addCourse',     ...args) },
	removeCourse(studentId, scheduleId, ...args)    { this._alter([studentId, 'schedules', scheduleId], 'removeCourse',  ...args) },
	reorderCourse(studentId, scheduleId, ...args)   { this._alter([studentId, 'schedules', scheduleId], 'reorderCourse', ...args) },
	reorderArea(studentId, areaId, ...args)         { this._alter([studentId, 'studies', areaId],       'reorder',       ...args) },
})

window.store = studentStore

export default studentStore
<|endoftext|>


<commit_before>import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import Navbar from './components/Navbar'
import { AppsActions } from './store/apps'
import { Box, Flex, Type } from 'blockstack-ui'
import { Hover } from 'react-powerplug'
import { Spinner } from '@components/ui/components/spinner'

const Loading = ({ ...rest }) => (
  <Flex
    flexDirection="column"
    alignItems="center"
    width={1}
    justifyContent="center"
    p={4}
    {...rest}
  >
    <Box width="48px" mx="auto">
      <Spinner color="black" size={48} />
    </Box>
    <Box py={4} textAlign="center">
      <Type fontWeight="500" fontSize={2} opacity={0.5}>
        Fetching apps...
      </Type>
    </Box>
  </Flex>
)

const Content = ({ topApps, allApps, ...rest }) => (
  <Box maxWidth={1280} width="100%" mx="auto" p={[1, 2, 4]} {...rest}>
    <AppsSection title="Top Ranked Apps" apps={topApps} limit={24} />
    {allApps.map(category => (
      <AppsSection title={category.label} apps={category.apps} limit={15} />
    ))}
  </Box>
)

const AppsSection = ({ title, apps, limit, category, ...rest }) => {
  let appsList = apps
  if (limit) {
    appsList = appsList.filter((app, i) => i <= limit - 1)
  }
  if (category) {
    appsList = appsList.filter(app => app.category === category)
  }
  return (
    <Box
      width={1}
      mx="auto"
      p={4}
      mb={4}
      borderBottom="1px solid rgba(15,15,15,0.1)"
      {...rest}
    >
      <Box textAlign="center">

{title}

      </Box>
      <Flex
        pt={4}
        justifyContent={['space-between', 'center']}
        alignItems="flex-start"
        flexWrap="wrap"
      >
        {appsList.map(app => (
          <AppItem
            key={app.name}
            name={app.name}
            imgixImageUrl={app.imgixImageUrl}
            website={app.website}
            description={app.description}
          />
        ))}
      </Flex>
    </Box>
  )
}

const Image = props => (
  <Box
    is="img"
    borderRadius="15px"
    boxShadow="0px 0px 35px 0px rgba(0, 0, 0, 0.15)"
    bg="rgba(44, 150, 255, 0.15)"
    {...props}
  />
)

const AppItem = ({ website, imgixImageUrl, name, description }) => {
  const descMaxLength = 55
  let desc = description.trim()

  if (description[description.length - 1] !== '.') {
    desc += '.'
  }

  if (description.length > descMaxLength) {
    desc = <>{desc.substring(0, descMaxLength).trim()}…</>
  }

  return (
    <Hover>
      {({ bind, hovered }) => (
        <Box
          width={['calc(50% - 10px)', 1 / 3, 1 / 3, 1 / 4]}
          maxWidth={['160px', 'unset', 'unset', 'unset']}
          pr={[0, 3, 3, 4]}
          flexShrink={0}
          mb={[5]}
          transition="0.15s all ease-in-out"
          transform={hovered ? 'translateY(-5px)' : 'none'}
          color="blue.dark"
          {...bind}
        >
          <Flex
            maxWidth="100%"
            width={1}
            is="a"
            href={website}
            target="_blank"
            alignItems="center"
            flexDirection={['column', 'row', 'row', 'row']}
            textAlign={['center', 'left', 'left', 'left']}
            style={{
              textDecoration: 'none',
              color: 'black !important'
            }}
          >
            <Image
              maxWidth="100%"
              width="64px"
              display="block"
              flexShrink="0"
              src={imgixImageUrl}
              alt={name}
            />
            <Box ml={[0, 3, 3, 3]} mt={[3, 0, 0, 0]}>
              <Box>
                <Type
                  is="h3"
                  fontSize={[2]}
                  lineHeight={1.45}
                  fontWeight="600"
                  color="black !important"
                  mb={1}
                >
                  {name}
                </Type>
              </Box>
              <Box opacity={0.75} color="black !important">
                {desc}
              </Box>
            </Box>
          </Flex>
        </Box>
      )}
    </Hover>
  )
}

const HomeScreenPage = props => {
  const loading = props.apps && props.apps.loading && !props.apps.topApps.length
  return (
    <Box>
      <Navbar hideBackToHomeLink activeTab="home" />
      <Box className="home-screen">
        {loading ? (
          <Loading />
        ) : (
          <Content
            allApps={!loading && props.apps.appsByCategory}
            topApps={!loading && props.apps.topApps}
          />
        )}
      </Box>
    </Box>
  )
}

Content.propTypes = {
  topApps: PropTypes.array.isRequired,
  allApps: PropTypes.array.isRequired
}

AppsSection.propTypes = {
  title: PropTypes.string.isRequired,
  apps: PropTypes.array.isRequired,
  limit: PropTypes.number.isRequired,
  category: PropTypes.string.isRequired
}
AppItem.propTypes = {
  website: PropTypes.string.isRequired,
  imgixImageUrl: PropTypes.string.isRequired,
  name: PropTypes.string.isRequired,
  description: PropTypes.string.isRequired
}

HomeScreenPage.propTypes = {
  apps: PropTypes.object.isRequired,
  refreshAppList: PropTypes.func.isRequired,
  doFetchApps: PropTypes.func.isRequired,
  appListLastUpdated: PropTypes.number,
  api: PropTypes.object.isRequired,
  instanceIdentifier: PropTypes.string,
  instanceCreationDate: PropTypes.number
}

const mapStateToProps = state => ({
  apps: state.apps,
  appListLastUpdated: state.apps.lastUpdated,
  api: state.settings.api,
  instanceIdentifier: state.apps.instanceIdentifier,
  instanceCreationDate: state.apps.instanceCreationDate
})

const mapDispatchToProps = dispatch =>
  bindActionCreators({ ...AppsActions }, dispatch)

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(HomeScreenPage)
<commit_msg>add hyphenation<commit_after>import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import Navbar from './components/Navbar'
import { AppsActions } from './store/apps'
import { Box, Flex, Type } from 'blockstack-ui'
import { Hover } from 'react-powerplug'
import { Spinner } from '@components/ui/components/spinner'

const Loading = ({ ...rest }) => (
  <Flex
    flexDirection="column"
    alignItems="center"
    width={1}
    justifyContent="center"
    p={4}
    {...rest}
  >
    <Box width="48px" mx="auto">
      <Spinner color="black" size={48} />
    </Box>
    <Box py={4} textAlign="center">
      <Type fontWeight="500" fontSize={2} opacity={0.5}>
        Fetching apps...
      </Type>
    </Box>
  </Flex>
)

const Content = ({ topApps, allApps, ...rest }) => (
  <Box maxWidth={1280} width="100%" mx="auto" p={[1, 2, 4]} {...rest}>
    <AppsSection title="Top Ranked Apps" apps={topApps} limit={24} />
    {allApps.map(category => (
      <AppsSection title={category.label} apps={category.apps} limit={15} />
    ))}
  </Box>
)

const AppsSection = ({ title, apps, limit, category, ...rest }) => {
  let appsList = apps
  if (limit) {
    appsList = appsList.filter((app, i) => i <= limit - 1)
  }
  if (category) {
    appsList = appsList.filter(app => app.category === category)
  }
  return (
    <Box
      width={1}
      mx="auto"
      p={4}
      mb={4}
      borderBottom="1px solid rgba(15,15,15,0.1)"
      {...rest}
    >
      <Box textAlign="center">

{title}

      </Box>
      <Flex
        pt={4}
        justifyContent={['space-between', 'center']}
        alignItems="flex-start"
        flexWrap="wrap"
      >
        {appsList.map(app => (
          <AppItem
            key={app.name}
            name={app.name}
            imgixImageUrl={app.imgixImageUrl}
            website={app.website}
            description={app.description}
          />
        ))}
      </Flex>
    </Box>
  )
}

const Image = props => (
  <Box
    is="img"
    borderRadius="15px"
    boxShadow="0px 0px 35px 0px rgba(0, 0, 0, 0.15)"
    bg="rgba(44, 150, 255, 0.15)"
    {...props}
  />
)

const AppItem = ({ website, imgixImageUrl, name, description }) => {
  const descMaxLength = 55
  let desc = description.trim()

  if (description[description.length - 1] !== '.') {
    desc += '.'
  }

  if (description.length > descMaxLength) {
    desc = <>{desc.substring(0, descMaxLength).trim()}…</>
  }

  return (
    <Hover>
      {({ bind, hovered }) => (
        <Box
          width={['calc(50% - 10px)', 1 / 3, 1 / 3, 1 / 4]}
          maxWidth={['160px', 'unset', 'unset', 'unset']}
          pr={[0, 3, 3, 4]}
          flexShrink={0}
          mb={[5]}
          transition="0.15s all ease-in-out"
          transform={hovered ? 'translateY(-5px)' : 'none'}
          color="blue.dark"
          {...bind}
        >
          <Flex
            maxWidth="100%"
            width={1}
            is="a"
            href={website}
            target="_blank"
            alignItems="center"
            flexDirection={['column', 'row', 'row', 'row']}
            textAlign={['center', 'left', 'left', 'left']}
            style={{
              textDecoration: 'none',
              color: 'black !important'
            }}
          >
            <Image
              maxWidth="100%"
              width="64px"
              display="block"
              flexShrink="0"
              src={imgixImageUrl}
              alt={name}
            />
            <Box ml={[0, 3, 3, 3]} mt={[3, 0, 0, 0]}>
              <Box>
                <Type
                  is="h3"
                  fontSize={[2]}
                  lineHeight={1.45}
                  fontWeight="600"
                  color="black !important"
                  mb={1}
                >
                  {name}
                </Type>
              </Box>
              <Box
                opacity={0.75}
                color="black !important"
                style={{
                  hyphens: 'auto'
                }}
              >
                {desc}
              </Box>
            </Box>
          </Flex>
        </Box>
      )}
    </Hover>
  )
}

const HomeScreenPage = props => {
  const loading = props.apps && props.apps.loading && !props.apps.topApps.length
  return (
    <Box>
      <Navbar hideBackToHomeLink activeTab="home" />
      <Box className="home-screen">
        {loading ? (
          <Loading />
        ) : (
          <Content
            allApps={!loading && props.apps.appsByCategory}
            topApps={!loading && props.apps.topApps}
          />
        )}
      </Box>
    </Box>
  )
}

Content.propTypes = {
  topApps: PropTypes.array.isRequired,
  allApps: PropTypes.array.isRequired
}

AppsSection.propTypes = {
  title: PropTypes.string.isRequired,
  apps: PropTypes.array.isRequired,
  limit: PropTypes.number.isRequired,
  category: PropTypes.string.isRequired
}
AppItem.propTypes = {
  website: PropTypes.string.isRequired,
  imgixImageUrl: PropTypes.string.isRequired,
  name: PropTypes.string.isRequired,
  description: PropTypes.string.isRequired
}

HomeScreenPage.propTypes = {
  apps: PropTypes.object.isRequired,
  refreshAppList: PropTypes.func.isRequired,
  doFetchApps: PropTypes.func.isRequired,
  appListLastUpdated: PropTypes.number,
  api: PropTypes.object.isRequired,
  instanceIdentifier: PropTypes.string,
  instanceCreationDate: PropTypes.number
}

const mapStateToProps = state => ({
  apps: state.apps,
  appListLastUpdated: state.apps.lastUpdated,
  api: state.settings.api,
  instanceIdentifier: state.apps.instanceIdentifier,
  instanceCreationDate: state.apps.instanceCreationDate
})

const mapDispatchToProps = dispatch =>
  bindActionCreators({ ...AppsActions }, dispatch)

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(HomeScreenPage)
<|endoftext|>


<commit_before>'use strict'

import {Component}      from 'react'
import {Link}           from 'react-router'
import DocumentTitle    from 'react-document-title'
import marked           from 'marked'
import RetinaImage      from 'react-retina-image'

import Image            from '../components/Image'
import Header           from '../components/Header'
import Footer           from '../components/Footer'
import CardLink         from '../components/CardLink'
import docs             from '../../docs.json'

marked.setOptions({
  renderer: new marked.Renderer(),
  gfm: true,
  tables: true,
  breaks: false,
  pedantic: false,
  sanitize: false,
  smartLists: true,
  smartypants: false
})

class DocsPage extends Component {

  constructor(props) {
    super(props)

    this.state = {
      currentPage: null,
      nextPage: null,
      imageLoading: false
    }

    this.initHighlighting = this.initHighlighting.bind(this)
    this.getPageName = this.getPageName.bind(this)
    this.setPage = this.setPage.bind(this)
    this.filterMarkup = this.filterMarkup.bind(this)
    this.getHeaderImageSrc = this.getHeaderImageSrc.bind(this)
    this.onImageLoad = this.onImageLoad.bind(this)
  }

  initHighlighting() {
    const blocks = document.querySelectorAll('pre code')
    Array.prototype.forEach.call(blocks, hljs.highlightBlock)
  }

  componentWillMount() {
    this.setPage(this.props)
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      imageLoading: true
    })
    if (this.props !== nextProps) {
      this.setPage(nextProps)
    }
  }

  componentDidUpdate() {
    this.initHighlighting()
  }

  getPageName(props) {
    let pageName = '404'
    if (props.route.path === '/about') {
      pageName = 'about'
    } else if (props.routeParams.hasOwnProperty('docSection')) {
      if (docs.hasOwnProperty(props.routeParams.docSection)) {
        pageName = props.routeParams.docSection
      }
    }
    return pageName
  }

  filterMarkup(markup) {
    return markup.replace('<a href="', '<a target="_blank" href="')
  }

  setPage(props) {
    let pageName = this.getPageName(props)
    let currentPage = Object.assign({}, docs[pageName], {
      pageName: pageName,
      markup: this.filterMarkup(marked(docs[pageName].markdown))
    })

    let nextPage = null
    if (currentPage.hasOwnProperty('next')) {
      nextPage = Object.assign({}, docs[currentPage.next], {
        pageName: currentPage.next
      })
    }

    this.setState({
      currentPage: currentPage,
      nextPage: nextPage
    })
  }

  getHeaderImageSrc() {
    let headerImageSrc = null
    if (this.state.currentPage !== null) {
      headerImageSrc = `/images/article-photos/full/${this.state.currentPage.image}`
    }
    return headerImageSrc
  }

  onImageLoad() {
    this.setState({
      imageLoading: false
    })
  }

  render() {
    const currentPage = this.state.currentPage,
          nextPage = this.state.nextPage,
          title = currentPage ? `Blockstack - ${currentPage.title}` : "Blockstack"

    const headerImageSrc = this.getHeaderImageSrc()

    return (
      <DocumentTitle title={title}>

            <Image src={headerImageSrc} onLoad={this.onImageLoad} />

            { currentPage !== null && this.state.imageLoading !== true ?
            <Image src={headerImageSrc}
              fallbackSrc="/images/article-photos/full/road.jpg"
              className="img-fluid docs-header-image" />
            : null }

          { currentPage.pageName !== 'about' ?

                <Link className="page-link" to="/docs" aria-label="Back">
                  « Back to Docs
                  Back
                </Link>

          : null }
<<<<<<>>>>>> 4a07c4060b9a22fc65386412f5d404a9382df551

Next Article

                      <CardLink href={`/docs/${nextPage.pageName}`}
                        title={nextPage.title} body={nextPage.description}
                        imageSrc={`/images/article-photos/800x600/${nextPage.image}`} />

                : null }

      </DocumentTitle>
    )
  }
}

export default DocsPage
<commit_msg>manual merge of DocsPage<commit_after>'use strict'

import {Component}      from 'react'
import {Link}           from 'react-router'
import DocumentTitle    from 'react-document-title'
import marked           from 'marked'
import RetinaImage      from 'react-retina-image'

import Image            from '../components/Image'
import Header           from '../components/Header'
import Footer           from '../components/Footer'
import CardLink         from '../components/CardLink'
import docs             from '../../docs.json'

marked.setOptions({
  renderer: new marked.Renderer(),
  gfm: true,
  tables: true,
  breaks: false,
  pedantic: false,
  sanitize: false,
  smartLists: true,
  smartypants: false
})

class DocsPage extends Component {

  constructor(props) {
    super(props)

    this.state = {
      currentPage: null,
      nextPage: null,
      imageLoading: false
    }

    this.initHighlighting = this.initHighlighting.bind(this)
    this.getPageName = this.getPageName.bind(this)
    this.setPage = this.setPage.bind(this)
    this.filterMarkup = this.filterMarkup.bind(this)
    this.getHeaderImageSrc = this.getHeaderImageSrc.bind(this)
    this.onImageLoad = this.onImageLoad.bind(this)
  }

  initHighlighting() {
    const blocks = document.querySelectorAll('pre code')
    Array.prototype.forEach.call(blocks, hljs.highlightBlock)
  }

  componentWillMount() {
    this.setPage(this.props)
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      imageLoading: true
    })
    if (this.props !== nextProps) {
      this.setPage(nextProps)
    }
  }

  componentDidUpdate() {
    this.initHighlighting()
  }

  getPageName(props) {
    let pageName = '404'
    if (props.route.path === '/about') {
      pageName = 'about'
    } else if (props.routeParams.hasOwnProperty('docSection')) {
      if (docs.hasOwnProperty(props.routeParams.docSection)) {
        pageName = props.routeParams.docSection
      }
    }
    return pageName
  }

  filterMarkup(markup) {
    return markup.replace('<a href="', '<a target="_blank" href="')
  }

  setPage(props) {
    let pageName = this.getPageName(props)
    let currentPage = Object.assign({}, docs[pageName], {
      pageName: pageName,
      markup: this.filterMarkup(marked(docs[pageName].markdown))
    })

    let nextPage = null
    if (currentPage.hasOwnProperty('next')) {
      nextPage = Object.assign({}, docs[currentPage.next], {
        pageName: currentPage.next
      })
    }

    this.setState({
      currentPage: currentPage,
      nextPage: nextPage
    })
  }

  getHeaderImageSrc() {
    let headerImageSrc = null
    if (this.state.currentPage !== null) {
      headerImageSrc = `/images/article-photos/full/${this.state.currentPage.image}`
    }
    return headerImageSrc
  }

  onImageLoad() {
    this.setState({
      imageLoading: false
    })
  }

  render() {
    const currentPage = this.state.currentPage,
          nextPage = this.state.nextPage,
          title = currentPage ? `Blockstack - ${currentPage.title}` : "Blockstack"

    const headerImageSrc = this.getHeaderImageSrc()

    return (
      <DocumentTitle title={title}>

            <Image src={headerImageSrc} onLoad={this.onImageLoad} />

            { currentPage !== null && this.state.imageLoading !== true ?
            <Image src={headerImageSrc}
              fallbackSrc="/images/article-photos/full/road.jpg"
              className="img-fluid docs-header-image" />
            : null }

          { currentPage.pageName !== 'about' ?

                <Link className="page-link" to="/docs" aria-label="Back">
                  « Back to Docs
                  Back
                </Link>

          : null }

{currentPage.title}

                {nextPage ?

Next Article

                      <CardLink href={`/docs/${nextPage.pageName}`}
                        title={nextPage.title} body={nextPage.description}
                        imageSrc={`/images/article-photos/800x600/${nextPage.image}`} />

                : null }

      </DocumentTitle>
    )
  }
}

export default DocsPage
<|endoftext|>


<commit_before>'use strict'

import {Component}   from 'react'
import {Link}        from 'react-router'
import DocumentTitle from 'react-document-title'
import request       from 'request'

import Image         from '../components/Image'
import Header        from '../components/Header'
import Footer        from '../components/Footer'

class HomePage extends Component {

  constructor(props) {
    super(props)

    this.state = {
      domainCount: 70000,
      slackUserCount: 2500,
      meetupUserCount: 5000,
      forumUserCount: 300
    }

    this.updateStats = this.updateStats.bind(this)
  }

  componentDidMount() {
    // Get the number of Slack users
    request({
      url: "https://blockstack-site-api.herokuapp.com/v1/stats",
      withCredentials: false
    }, (error, response, body) => {
      if (!error && response.statusCode === 200) {
        this.updateStats(body)
      } else {
        console.log(error)
      }
    })
  }

  updateStats(response) {
    const jsonResponse = JSON.parse(response)
    if (jsonResponse.hasOwnProperty("slack_users") &&
        jsonResponse.hasOwnProperty("meetup_users") &&
        jsonResponse.hasOwnProperty("forum_users") &&
        jsonResponse.hasOwnProperty("domains")) {

      let newSlackUsers = this.state.slackUserCount
      if (jsonResponse.slack_users !== 0) {
        newSlackUsers = jsonResponse.slack_users
      }

      // Set the stats
      this.setState({
        slackUserCount: newSlackUsers,
        meetupUserCount: jsonResponse.meetup_users,
        forumUserCount: jsonResponse.forum_users,
        domainCount: jsonResponse.domains
      })
    }
  }

  render() {
    return (
      <DocumentTitle title="Blockstack, building the decentralized internet">

                  What will you build on the decentralized internet?

                  Blockstack is a new decentralized internet where you own your data and apps run locally without remote servers.

                  <Link to="/tutorials/hello-blockstack" role="button"
                    className="btn btn-lg btn-secondary btn-block">
                    Watch Tutorial
                  </Link>

                  <Link to="/download" className="hero-caption-text">
                    Try the browser add-on.   ›
                    Download
                  </Link>

                    Access the Decentralized Internet

                    Downloading Blockstack will give you access to a decentralized internet within your favorite browser. Claim your name, try out the first apps, lookup people in the public directory, make payments with globally-accepted currency, and connect your storage providers to host your user-owned data.

                    The decentralized internet is powered by a technological breakthrough in consensus algorithms that lets you take back your safety, privacy, and property rights on the internet. You're free to experience the internet as it was truly meant to be.

                    As a developer, you can build decentralized apps without having to set up any infrastructure or worry about hosting user data. The decentralized Blockstack network handles identity, DNS and public key distribution. You get your own private storage and authentication is between just you and your apps, with no 3rd parties.

                    Blockstack is an open source project with {this.state.domainCount} users and core developers located in New York City and Hong Kong. Learn more about what Blockstack <Link to="/about">here</Link>.

                    Build apps like these on the Blockstack network:

                    Censorship-resistant social network

                    Cloud democracy with secure voting

                    Peer-to-peer marketplace

                    As a developer, what you create is no longer limited by walled gardens, infrastructure maintainance, and concerns about user data security. Build apps that live on forever and publish them to the decentralized internet where they will run locally on your users' servers.

                    <Image
                      src="/images/visuals/sign-in-with-blockstack.gif"
                      fallbackSrc="/images/visuals/sign-in-with-blockstack.gif"
                      retinaSupport={false} />

                    Complete the step-by-step tutorial and see how easy it is to build an app with a decentralized identity system in a few lines of code and no servers.

                    <Link to="/tutorials/hello-blockstack" role="button"
                      className="btn btn-outline-primary btn-block">
                      Hello Blockstack Tutorial
                    </Link>

                    Want to learn more about building apps on blockstack? Tutorials on building serverless apps with “get” and “put” functions are coming soon, but in the meantime check out our Github repo and join the community

      </DocumentTitle>
    )
  }
}

export default HomePage
<commit_msg>fix typo in home page<commit_after>'use strict'

import {Component}   from 'react'
import {Link}        from 'react-router'
import DocumentTitle from 'react-document-title'
import request       from 'request'

import Image         from '../components/Image'
import Header        from '../components/Header'
import Footer        from '../components/Footer'

class HomePage extends Component {

  constructor(props) {
    super(props)

    this.state = {
      domainCount: 70000,
      slackUserCount: 2500,
      meetupUserCount: 5000,
      forumUserCount: 300
    }

    this.updateStats = this.updateStats.bind(this)
  }

  componentDidMount() {
    // Get the number of Slack users
    request({
      url: "https://blockstack-site-api.herokuapp.com/v1/stats",
      withCredentials: false
    }, (error, response, body) => {
      if (!error && response.statusCode === 200) {
        this.updateStats(body)
      } else {
        console.log(error)
      }
    })
  }

  updateStats(response) {
    const jsonResponse = JSON.parse(response)
    if (jsonResponse.hasOwnProperty("slack_users") &&
        jsonResponse.hasOwnProperty("meetup_users") &&
        jsonResponse.hasOwnProperty("forum_users") &&
        jsonResponse.hasOwnProperty("domains")) {

      let newSlackUsers = this.state.slackUserCount
      if (jsonResponse.slack_users !== 0) {
        newSlackUsers = jsonResponse.slack_users
      }

      // Set the stats
      this.setState({
        slackUserCount: newSlackUsers,
        meetupUserCount: jsonResponse.meetup_users,
        forumUserCount: jsonResponse.forum_users,
        domainCount: jsonResponse.domains
      })
    }
  }

  render() {
    return (
      <DocumentTitle title="Blockstack, building the decentralized internet">

                  What will you build on the decentralized internet?

                  Blockstack is a new decentralized internet where you own your data and apps run locally without remote servers.

                  <Link to="/tutorials/hello-blockstack" role="button"
                    className="btn btn-lg btn-secondary btn-block">
                    Watch Tutorial
                  </Link>

                  <Link to="/download" className="hero-caption-text">
                    Try the browser add-on.   ›
                    Download
                  </Link>

                    Access the Decentralized Internet

                    Downloading Blockstack will give you access to a decentralized internet within your favorite browser. Claim your name, try out the first apps, lookup people in the public directory, make payments with globally-accepted currency, and connect your storage providers to host your user-owned data.

                    The decentralized internet is powered by a technological breakthrough in consensus algorithms that lets you take back your safety, privacy, and property rights on the internet. You're free to experience the internet as it was truly meant to be.

                    As a developer, you can build decentralized apps without having to set up any infrastructure or worry about hosting user data. The decentralized Blockstack network handles identity, DNS and public key distribution. You get your own private storage and authentication is between just you and your apps, with no 3rd parties.

                    Blockstack is an open source project with {this.state.domainCount} users and core developers located in New York City and Hong Kong. Learn more about what Blockstack is <Link to="/about">here</Link>.

                    Build apps like these on the Blockstack network:

                    Censorship-resistant social network

                    Cloud democracy with secure voting

                    Peer-to-peer marketplace

                    As a developer, what you create is no longer limited by walled gardens, infrastructure maintainance, and concerns about user data security. Build apps that live on forever and publish them to the decentralized internet where they will run locally on your users' servers.

                    <Image
                      src="/images/visuals/sign-in-with-blockstack.gif"
                      fallbackSrc="/images/visuals/sign-in-with-blockstack.gif"
                      retinaSupport={false} />

                    Complete the step-by-step tutorial and see how easy it is to build an app with a decentralized identity system in a few lines of code and no servers.

                    <Link to="/tutorials/hello-blockstack" role="button"
                      className="btn btn-outline-primary btn-block">
                      Hello Blockstack Tutorial
                    </Link>

                    Want to learn more about building apps on blockstack? Tutorials on building serverless apps with “get” and “put” functions are coming soon, but in the meantime check out our Github repo and join the community

      </DocumentTitle>
    )
  }
}

export default HomePage
<|endoftext|>


<commit_before>"use strict";

var Backbone = require('backbone');
var $ = require('jquery');
Backbone.$ = $;

module.exports = Backbone.View.extend({
  tagName: 'div',
  id: 'map-canvas',

  initialize: function(){
    var mapOptions = {
      zoom: this.model.get('zoom'),
    };
    var map = new google.maps.Map(this.el, mapOptions);

    this.getDirections(map);
    this.render();
    console.log('We\'re in the view, and the model says: ' + this.model.get('start'));
  },

  getDirections: function(map){
    var directionsService = new google.maps.DirectionsService();
    var directionsDisplay = new google.maps.DirectionsRenderer();
    directionsDisplay.setMap(map);

    var request = {
      origin: this.model.get('start'),
      destination: this.model.get('end'),
      travelMode: google.maps.DirectionsTravelMode.WALKING
    };

    directionsService.route(request, function(response, status) {
      if (status === google.maps.DirectionsStatus.OK){
        directionsDisplay.setDirections(response);
      }
    });
    this.render();
  },

  render: function(){
    $('map-canvas').replaceWith(this.$el);
    return this;
  },
});<commit_msg>Obtain the coordinates for each interval along a route<commit_after>"use strict";

var Backbone = require('backbone');
var $ = require('jquery');
Backbone.$ = $;

module.exports = Backbone.View.extend({
  tagName: 'div',
  id: 'map-canvas',

  initialize: function(){
    var mapOptions = {
      zoom: this.model.get('zoom'),
    };
    var map = new google.maps.Map(this.el, mapOptions);

    this.getDirections(map);
    this.render();
    console.log('We\'re in the view, and the model says: ' + this.model.get('start'));
  },

  getDirections: function(map){
    var directionsService = new google.maps.DirectionsService();
    var directionsDisplay = new google.maps.DirectionsRenderer();
    directionsDisplay.setMap(map);

    var request = {
      origin: this.model.get('start'),
      destination: this.model.get('end'),
      travelMode: google.maps.DirectionsTravelMode.WALKING
    };

    directionsService.route(request, function(response, status) {
      if (status === google.maps.DirectionsStatus.OK){
        directionsDisplay.setDirections(response);

        // One leg for each waypoint
        var legs = response.routes[0].legs[0];

        // Array containing each separate step along a leg
        var steps = legs.steps;

        // Coordinates for Yelp searches
        var routeIntervals = [];

        steps.forEach(function(step) {

          // Grab latitude and longitude from each starting point
          routeIntervals.push({ lat: step.start_location.k, lon: step.start_location.B });

        });
      }
    });

    this.render();
  },

  render: function(){
    $('map-canvas').replaceWith(this.$el);
    return this;
  },
});
<|endoftext|>


<commit_before>#!/usr/bin/env node

/* eslint-disable complexity */

'use strict';

const UPM = false; // USE_PREINSTALLED_MODULES

const fs = require('fs');
const path = require('path');
const assert = require('assert');
const globby = require('globby');
const utils = require('../utils.js');

assert(!module.parent);
assert(__dirname === process.cwd());

const host = 'node' + process.version[1];
const target = process.argv[2] || host;
const windows = process.platform === 'win32';
const npm = { 0: 2, 4: 2, 6: 3, 7: 4, 8: 5 }[
  process.version.match(/^(node|v)?(\d+)/)[2] | 0];
assert(npm !== undefined);

function applyMetaToRight (right, meta) {
  right = (meta.take === 'stderr' ? right.stderr : right.stdout);
  if (meta.take === 'last-line') right = right.split('\n').slice(-2).join('\n');
  if (right.slice(-2) === '\r\n') right = right.slice(0, -2);
  if (right.slice(-1) === '\n') right = right.slice(0, -1);
  return right;
}

let stamp = {};

const checklist = fs.readFileSync('checklist.js', 'utf-8');
let table = checklist.split('const table = ')[1].split(';')[0];
table = JSON.parse(table);
let changes = checklist.split('const changes = ')[1].split(';')[0];
changes = JSON.parse(changes);

function save () {
  const t = utils.stringify(table, undefined, 2);
  let c = utils.stringify(changes, undefined, 2);
  if (c === '[]') c = '[\n]';
  fs.writeFileSync('checklist.js',
    '/* eslint-disable no-unused-vars */\n' +
    '/* eslint-disable quotes */\n' +
    '\n' +
    '\'use strict\';\n' +
    '\n' +
    'const table = ' + t + ';\n' +
    'const changes = ' + c + ';\n'
  );
}

function stamp2string (s) {
  // platform, arch, modules
  return s.p + '/' + s.a + '/m' + s.m.toString();
}

function update (p, r, v, note) {
  if (!table[p]) table[p] = {};
  const row = table[p];
  const ss = stamp2string(stamp);
  const o = row[ss];
  const rv = r + (v ? (',' + v) : '');
  const rn = r + (note ? (',' + note) : '');
  row[ss] = rv + (note ? (',' + note) : '');
  const o2 = o ? o.split(',')[0] : undefined;
  if ((!o) && (r !== 'ok')) {
    changes.push(p + ',' + ss + ': new ' + rn);
  } else
  if ((o2 !== undefined) && (o2 !== r)) {
    changes.push(p + ',' + ss + ': ' + o + ' -> ' + rn);
  }
  save();
}

if (!UPM) {
  console.log('Cleaning cache...');

  if (windows) {
    utils.vacuum.sync(path.join(
      process.env.APPDATA, 'npm-cache'
    ));
    utils.mkdirp.sync(path.join(
      process.env.APPDATA, 'npm-cache'
    ));
  } else {
    if (npm >= 5) {
      utils.exec.sync(
        'npm cache clean --force'
      );
    } else {
      utils.exec.sync(
        'npm cache clean'
      );
    }
  }

  utils.mkdirp.sync('_isolator');
}

(function () {
  console.log('Getting stamp...');

  const input = path.resolve('stamp.js');
  const lucky = path.basename(input).slice(0, -3);
  const output = path.resolve('_isolator', lucky + '.exe');

  utils.pkg.sync([
    '--target', target,
    '--output', output, input
  ]);

  stamp = utils.spawn.sync(
    output
  );

  stamp = JSON.parse(stamp);
  utils.vacuum.sync(output);
  console.log('Stamp is ' + JSON.stringify(stamp));
  console.log('Waiting...');
  utils.pause(5);
}());

const dickies = globby.sync([
  './*/*.js',
  '!./*/*.config.js',
  '!./*/*.meta.js',
  '!./*/gulpfile.js',
  '!./*/*fixture*'
]);

dickies.some(function (dicky) {
  let input = path.resolve(dicky);

  const foldy = path.dirname(input);
  const foldyName = path.basename(foldy);

  const packy = path.basename(input).slice(0, -3);
  const packyName = packy.split('@')[0];
  const packyWildcard = packy.split('@')[1];

  let wordy = packy;
  if (packyName !== foldyName) {
    wordy = foldyName + '/' + wordy;
  }

  const output = path.resolve('_isolator', packy + '.exe');

  console.log();
  console.log('*********************************************************');
  console.log('*********************************************************');
  console.log('*********************************************************');

  console.log('Testing ' + wordy + '...');

  const flags = { ci: process.env.CI };
  let metajs = path.join(foldy, packy + '.meta.js');
  metajs = fs.existsSync(metajs) ? require(metajs) : undefined;

  let meta;

  if (metajs) {
    meta = metajs(stamp, flags) || {};
  } else {
    meta = {};
  }

  let allow;

  if (typeof meta.allow !== 'undefined') {
    allow = meta.allow;
  } else {
    allow = true;
  }

  const note = meta.note;

  if (!allow) {
    update(wordy, 'nop', '', note);
    console.log(wordy + ' not allowed here!');
    if (note) console.log('Note:', note);
    return;
  }

  let version = '';

  if (!UPM) {
    const build = meta.build;
    const packages = [ packy ].concat(meta.packages || []);
    console.log('Installing ' + packages + '...');
    let successful = false;
    let counter = 10;
    while ((!successful) && (counter > 0)) {
      successful = true;
      let command = 'npm install ' + packages.join(' ');
      if (npm >= 5) command += ' --no-save';
      if (build) command += ' --build-from-source=' + build;
      command += ' --unsafe-perm';
      try {
        utils.exec.sync(command, { cwd: foldy });
      } catch (__) {
        assert(__);
        utils.vacuum.sync(path.join(foldy, 'node_modules'));
        successful = false;
        counter -= 1;
      }
    }

    let packyVersion;

    try {
      packyVersion = JSON.parse(fs.readFileSync(
        path.join(foldy, 'node_modules', packy.split('@')[0], 'package.json'), 'utf8'
      )).version;
    } catch (___) {
      update(wordy, 'bad-npm-i', '', note);
      console.log(wordy + ' failed to install here!');
      if (note) console.log('Note:', note);
      return;
    }

    console.log('Version of ' + packy + ' is ' + packyVersion);
    version = packyVersion;

    if (packyWildcard) {
      assert.equal(packyWildcard.split('.').length, 3);
      assert.equal(packyVersion, packyWildcard);
    }
  }

  let right;

  console.log('Running non-compiled ' + wordy + '...');

  try {
    right = utils.spawn.sync(
      'node', [ input ],
      { cwd: path.dirname(input),
        stdio: 'pipe' }
    );
  } catch (___) {
    right = {
      stdout: '',
      stderr: ___.toString()
    };
  }

  right = applyMetaToRight(right, meta);

  console.log('Result is \'' + right + '\'');

  if (right !== 'ok') {
    update(wordy, 'bad-test', version, note);
  } else {
    console.log('Compiling ' + wordy + '...');
    const config = path.join(foldy, packy + '.config.json');

    if (fs.existsSync(config)) {
      const bin = JSON.parse(fs.readFileSync(config)).bin;
      assert.equal(path.join(foldy, bin), input);
      input = config;
    }

    utils.pkg.sync([
      '--target', target,
      '--output', output, input
    ]);

    console.log('Copying addons...');

    const deployFiles = globby.sync(
      path.join(foldy, 'node_modules', '**', '*.node')
    ).map(function (file) {
      return {
        deployFrom: file,
        deployTo: path.join(path.dirname(output), path.basename(file))
      };
    });

    let deployFilesExt = [];

    if (meta.deployFiles) {
      deployFilesExt = deployFilesExt.concat(meta.deployFiles);
    }

    if (meta.deployFilesFrom) {
      meta.deployFilesFrom.some(function (dictName) {
        const dict = require('../../dictionary/' + dictName);
        deployFilesExt = deployFilesExt.concat(
          dict.pkg.deployFiles.map(function (deployFile) {
            const deployFrom = 'node_modules/' + dictName + '/' + deployFile[0];
            const deployTo = deployFile[1];
            return [ deployFrom, deployTo ];
          })
        );
      });
    }

    deployFilesExt.some(function (deployFile) {
      let deployFrom;
      let deployTo;
      if (Array.isArray(deployFile)) {
        deployFrom = deployFile[0];
        deployTo = deployFile[1];
      } else {
        deployFrom = deployFile;
        deployTo = deployFile;
      }
      assert(deployFrom.indexOf('*') < 0);
      assert(deployTo.indexOf('*') < 0);
      deployFiles.push({
        deployFrom: path.join(foldy, deployFrom),
        deployTo: path.join(path.dirname(output), deployTo)
      });
    });

    deployFiles.some(function (deployFile) {
      if (fs.existsSync(deployFile.deployFrom)) {
        utils.mkdirp.sync(
          path.dirname(deployFile.deployTo)
        );
        fs.writeFileSync(
          deployFile.deployTo,
          fs.readFileSync(deployFile.deployFrom)
        );
        fs.chmodSync(
          deployFile.deployTo,
          fs.statSync(deployFile.deployFrom).mode.toString(8).slice(-3)
        );
      }
    });

    console.log('Running compiled ' + wordy + '...');

    try {
      right = utils.spawn.sync(
        './' + path.basename(output), [],
        { cwd: path.dirname(output),
          stdio: 'pipe' }
      );
    } catch (___) {
      right = {
        stdout: '',
        stderr: ___.toString()
      };
    }

    right = applyMetaToRight(right, meta);
    console.log('Result is \'' + right + '\'');

    if (right !== 'ok') {
      update(wordy, 'error', version, note);
    } else {
      update(wordy, 'ok', version);
    }
  }

  const rubbishes = globby.sync(
    path.join(path.dirname(output), '**', '*')
  );

  rubbishes.some(function (rubbish) {
    utils.vacuum.sync(rubbish);
  });

  if (!UPM) {
    console.log('Cleanup...');
    utils.vacuum.sync(path.join(foldy, 'node_modules'));
  }
});

console.log(
  '\nChanges:\n' +
  changes.join('\n') +
  '\n'
);
<commit_msg>simplify deployFiles testing<commit_after>#!/usr/bin/env node

/* eslint-disable complexity */

'use strict';

const UPM = false; // USE_PREINSTALLED_MODULES

const fs = require('fs');
const path = require('path');
const assert = require('assert');
const globby = require('globby');
const utils = require('../utils.js');

assert(!module.parent);
assert(__dirname === process.cwd());

const host = 'node' + process.version[1];
const target = process.argv[2] || host;
const windows = process.platform === 'win32';
const npm = { 0: 2, 4: 2, 6: 3, 7: 4, 8: 5 }[
  process.version.match(/^(node|v)?(\d+)/)[2] | 0];
assert(npm !== undefined);

function applyMetaToRight (right, meta) {
  right = (meta.take === 'stderr' ? right.stderr : right.stdout);
  if (meta.take === 'last-line') right = right.split('\n').slice(-2).join('\n');
  if (right.slice(-2) === '\r\n') right = right.slice(0, -2);
  if (right.slice(-1) === '\n') right = right.slice(0, -1);
  return right;
}

let stamp = {};

const checklist = fs.readFileSync('checklist.js', 'utf-8');
let table = checklist.split('const table = ')[1].split(';')[0];
table = JSON.parse(table);
let changes = checklist.split('const changes = ')[1].split(';')[0];
changes = JSON.parse(changes);

function save () {
  const t = utils.stringify(table, undefined, 2);
  let c = utils.stringify(changes, undefined, 2);
  if (c === '[]') c = '[\n]';
  fs.writeFileSync('checklist.js',
    '/* eslint-disable no-unused-vars */\n' +
    '/* eslint-disable quotes */\n' +
    '\n' +
    '\'use strict\';\n' +
    '\n' +
    'const table = ' + t + ';\n' +
    'const changes = ' + c + ';\n'
  );
}

function stamp2string (s) {
  // platform, arch, modules
  return s.p + '/' + s.a + '/m' + s.m.toString();
}

function update (p, r, v, note) {
  if (!table[p]) table[p] = {};
  const row = table[p];
  const ss = stamp2string(stamp);
  const o = row[ss];
  const rv = r + (v ? (',' + v) : '');
  const rn = r + (note ? (',' + note) : '');
  row[ss] = rv + (note ? (',' + note) : '');
  const o2 = o ? o.split(',')[0] : undefined;
  if ((!o) && (r !== 'ok')) {
    changes.push(p + ',' + ss + ': new ' + rn);
  } else
  if ((o2 !== undefined) && (o2 !== r)) {
    changes.push(p + ',' + ss + ': ' + o + ' -> ' + rn);
  }
  save();
}

if (!UPM) {
  console.log('Cleaning cache...');

  if (windows) {
    utils.vacuum.sync(path.join(
      process.env.APPDATA, 'npm-cache'
    ));
    utils.mkdirp.sync(path.join(
      process.env.APPDATA, 'npm-cache'
    ));
  } else {
    if (npm >= 5) {
      utils.exec.sync(
        'npm cache clean --force'
      );
    } else {
      utils.exec.sync(
        'npm cache clean'
      );
    }
  }

  utils.mkdirp.sync('_isolator');
}

(function () {
  console.log('Getting stamp...');

  const input = path.resolve('stamp.js');
  const lucky = path.basename(input).slice(0, -3);
  const output = path.resolve('_isolator', lucky + '.exe');

  utils.pkg.sync([
    '--target', target,
    '--output', output, input
  ]);

  stamp = utils.spawn.sync(
    output
  );

  stamp = JSON.parse(stamp);
  utils.vacuum.sync(output);
  console.log('Stamp is ' + JSON.stringify(stamp));
  console.log('Waiting...');
  utils.pause(5);
}());

const dickies = globby.sync([
  './*/*.js',
  '!./*/*.config.js',
  '!./*/*.meta.js',
  '!./*/gulpfile.js',
  '!./*/*fixture*'
]);

dickies.some(function (dicky) {
  let input = path.resolve(dicky);

  const foldy = path.dirname(input);
  const foldyName = path.basename(foldy);

  const packy = path.basename(input).slice(0, -3);
  const packyName = packy.split('@')[0];
  const packyWildcard = packy.split('@')[1];

  let wordy = packy;
  if (packyName !== foldyName) {
    wordy = foldyName + '/' + wordy;
  }

  const output = path.resolve('_isolator', packy + '.exe');

  console.log();
  console.log('*********************************************************');
  console.log('*********************************************************');
  console.log('*********************************************************');

  console.log('Testing ' + wordy + '...');

  const flags = { ci: process.env.CI };
  let metajs = path.join(foldy, packy + '.meta.js');
  metajs = fs.existsSync(metajs) ? require(metajs) : undefined;

  let meta;

  if (metajs) {
    meta = metajs(stamp, flags) || {};
  } else {
    meta = {};
  }

  let allow;

  if (typeof meta.allow !== 'undefined') {
    allow = meta.allow;
  } else {
    allow = true;
  }

  const note = meta.note;

  if (!allow) {
    update(wordy, 'nop', '', note);
    console.log(wordy + ' not allowed here!');
    if (note) console.log('Note:', note);
    return;
  }

  let version = '';

  if (!UPM) {
    const build = meta.build;
    const packages = [ packy ].concat(meta.packages || []);
    console.log('Installing ' + packages + '...');
    let successful = false;
    let counter = 10;
    while ((!successful) && (counter > 0)) {
      successful = true;
      let command = 'npm install ' + packages.join(' ');
      if (npm >= 5) command += ' --no-save';
      if (build) command += ' --build-from-source=' + build;
      command += ' --unsafe-perm';
      try {
        utils.exec.sync(command, { cwd: foldy });
      } catch (__) {
        assert(__);
        utils.vacuum.sync(path.join(foldy, 'node_modules'));
        successful = false;
        counter -= 1;
      }
    }

    let packyVersion;

    try {
      packyVersion = JSON.parse(fs.readFileSync(
        path.join(foldy, 'node_modules', packy.split('@')[0], 'package.json'), 'utf8'
      )).version;
    } catch (___) {
      update(wordy, 'bad-npm-i', '', note);
      console.log(wordy + ' failed to install here!');
      if (note) console.log('Note:', note);
      return;
    }

    console.log('Version of ' + packy + ' is ' + packyVersion);
    version = packyVersion;

    if (packyWildcard) {
      assert.equal(packyWildcard.split('.').length, 3);
      assert.equal(packyVersion, packyWildcard);
    }
  }

  let right;

  console.log('Running non-compiled ' + wordy + '...');

  try {
    right = utils.spawn.sync(
      'node', [ input ],
      { cwd: path.dirname(input),
        stdio: 'pipe' }
    );
  } catch (___) {
    right = {
      stdout: '',
      stderr: ___.toString()
    };
  }

  right = applyMetaToRight(right, meta);

  console.log('Result is \'' + right + '\'');

  if (right !== 'ok') {
    update(wordy, 'bad-test', version, note);
  } else {
    console.log('Compiling ' + wordy + '...');
    const config = path.join(foldy, packy + '.config.json');

    if (fs.existsSync(config)) {
      const bin = JSON.parse(fs.readFileSync(config)).bin;
      assert.equal(path.join(foldy, bin), input);
      input = config;
    }

    utils.pkg.sync([
      '--target', target,
      '--output', output, input
    ]);

    console.log('Copying addons...');

    const deployFiles = globby.sync(
      path.join(foldy, 'node_modules', '**', '*.node')
    ).map(function (file) {
      return {
        deployFrom: file,
        deployTo: path.join(path.dirname(output), path.basename(file))
      };
    });

    let deployFilesExt = [];

    if (meta.deployFiles) {
      deployFilesExt = deployFilesExt.concat(meta.deployFiles);
    }

    if (meta.deployFilesFrom) {
      meta.deployFilesFrom.some(function (dictName) {
        const dict = require('../../dictionary/' + dictName);
        deployFilesExt = deployFilesExt.concat(
          dict.pkg.deployFiles.map(function (deployFile) {
            const deployFrom = 'node_modules/' + dictName + '/' + deployFile[0];
            const deployTo = deployFile[1];
            return [ deployFrom, deployTo ];
          })
        );
      });
    }

    deployFilesExt.some(function (deployFile) {
      let deployFrom;
      let deployTo;

      if (Array.isArray(deployFile)) {
        deployFrom = deployFile[0];
        deployTo = deployFile[1];
      } else {
        deployFrom = deployFile;
        deployTo = deployFile;
      }

      assert(deployFrom.indexOf('*') < 0);
      assert(deployTo.indexOf('*') < 0);

      deployFiles.push([
        path.join(foldy, deployFrom),
        path.join(path.dirname(output), deployTo)
      ]);
    });

    deployFiles.some(function (deployFile) {
      const deployFrom = deployFile[0];
      const deployTo = deployFile[1];
      if (fs.existsSync(deployFrom)) {
        utils.mkdirp.sync(
          path.dirname(deployTo)
        );
        fs.writeFileSync(
          deployTo,
          fs.readFileSync(deployFrom)
        );
        fs.chmodSync(
          deployTo,
          fs.statSync(deployFrom).mode.toString(8).slice(-3)
        );
      }
    });

    console.log('Running compiled ' + wordy + '...');

    try {
      right = utils.spawn.sync(
        './' + path.basename(output), [],
        { cwd: path.dirname(output),
          stdio: 'pipe' }
      );
    } catch (___) {
      right = {
        stdout: '',
        stderr: ___.toString()
      };
    }

    right = applyMetaToRight(right, meta);
    console.log('Result is \'' + right + '\'');

    if (right !== 'ok') {
      update(wordy, 'error', version, note);
    } else {
      update(wordy, 'ok', version);
    }
  }

  const rubbishes = globby.sync(
    path.join(path.dirname(output), '**', '*')
  );

  rubbishes.some(function (rubbish) {
    utils.vacuum.sync(rubbish);
  });

  if (!UPM) {
    console.log('Cleanup...');
    utils.vacuum.sync(path.join(foldy, 'node_modules'));
  }
});

console.log(
  '\nChanges:\n' +
  changes.join('\n') +
  '\n'
);
<|endoftext|>


<commit_before>/**common -- iServer**/
import './common/iServer/AddressMatchServiceSpec.js';
import './common/iServer/AggQueryBuilderParameterSpec.js';
import './common/iServer/AggregationParameterSpec.js';
import './common/iServer/AreaSolarRadiationParametersSpec.js';
import './common/iServer/BufferAnalystServiceSpec.js';
import './common/iServer/BufferDistanceSpec.js';
import './common/iServer/BufferSettingSpec.js';
import './common/iServer/BurstPipelineAnalystServiceSpec.js';
import './common/iServer/ChartQueryFilterParameterSpec.js';
import './common/iServer/ChartQueryParametersSpec.js';
import './common/iServer/ClipParameterSpec.js';
import './common/iServer/ComputeWeightMatrixServiceSpec.js';
import './common/iServer/DensityAnalystServiceSpec.js';
import './common/iServer/EditFeaturesServiceSpec.js';
import './common/iServer/FacilityAnalystStreamParametersSpec.js';
import './common/iServer/FacilityAnalystUpstream3DParametersSpec.js';
import './common/iServer/FieldStatisticServiceSpec.js';
import './common/iServer/FilterAggParameterSpec.js';
import './common/iServer/FindClosestFacilitiesServiceSpec.js';
import './common/iServer/FindLocationServiceSpec.js';
import './common/iServer/FindMTSPPathsServiceSpec.js';
import './common/iServer/FindPathServiceSpec.js';
import './common/iServer/FindServiceAreasServiceSpec.js';
import './common/iServer/FindTSPPathsServiceSpec.js';
import './common/iServer/GenerateSpatialDataServiceSpec.js';
import './common/iServer/GeoBoundingBoxQueryBuilderParameterSpec.js';
import './common/iServer/GeoHashGridAggParameterSpec.js';
import './common/iServer/GeometryBatchAnalystServiceSpec.js';
import './common/iServer/GeoRelationAnalystServiceSpec.js';
import './common/iServer/GetFeaturesByBoundsServiceSpec.js';
import './common/iServer/GetFeaturesByBufferServiceSpec.js';
import './common/iServer/GetFeaturesByGeometryServiceSpec.js';
import './common/iServer/GetFeaturesByIDsServiceSpec.js';
import './common/iServer/GetFeaturesBySQLServiceSpec.js';
import './common/iServer/GetFieldsServiceSpec.js';
import './common/iServer/GetGridCellInfosServiceSpec.js';
import './common/iServer/GetLayersInfoServiceSpec.js';
import './common/iServer/GridSpec.js';
import './common/iServer/ImageSpec.js';
import './common/iServer/InterpolationAnalystServiceSpec.js';
import './common/iServer/LabelImageCellSpec.js';
import './common/iServer/LabelMixedStyleSpec.js';
import './common/iServer/LinkItemSpec.js';
import './common/iServer/MapServiceSpec.js';
import './common/iServer/MathExpressionAnalysisServiceSpec.js';
import './common/iServer/MeasureServiceSpec.js';
import './common/iServer/OverlapDisplayedOptionsSpec.js';
import './common/iServer/OverlayAnalystServiceSpec.js';
import './common/iServer/QueryByBoundsServiceSpec.js';
import './common/iServer/QueryByDistanceServiceSpec.js';
import './common/iServer/QueryByGeometryServiceSpec.js';
import './common/iServer/QueryBySQLServiceSpec.js';
import './common/iServer/QueryServiceSpec.js';
import './common/iServer/RouteCalculateMeasureServiceSpec.js';
import './common/iServer/RouteLocatorServiceSpec.js';
import './common/iServer/RouteSpec.js';
import './common/iServer/ServerGeometrySpec.js';
import './common/iServer/SetLayerInfoServiceSpec.js';
import './common/iServer/SetLayersInfoServiceSpec.js';
import './common/iServer/SetLayerStatusServiceSpec.js';
import './common/iServer/StopQueryServiceSpec.js';
import './common/iServer/SummaryAttributesJobsParameterSpec.js';
import './common/iServer/SurfaceAnalystServiceSpec.js';
import './common/iServer/TerrainCurvatureCalculationServiceSpec.js';
import './common/iServer/ThemeDotDensitySpec.js';
import './common/iServer/ThemeGridRangeSpec.js';
import './common/iServer/ThemeGridUniqueSpec.js';
import './common/iServer/ThemeLabelUniqueItemSpec.js';
import './common/iServer/ThemeRangeSpec.js';
import './common/iServer/ThemeServiceSpec.js';
import './common/iServer/ThiessenAnalystServiceSpec.js';
import './common/iServer/TilesetsServiceSpec.js';
import './common/iServer/TransferLineSpec.js';
import './common/iServer/TransferPathServiceSpec.js';
import './common/iServer/TransferSolutionServiceSpec.js';
import './common/iServer/UpdateEdgeWeightServiceSpec.js';
import './common/iServer/UpdateTurnNodeWeightServiceSpec.js';
// import './common/iServer/AreaSolarRadiationServiceSpec.js';       //iclient8注释掉
// import './common/iServer/ChartFeatureInfoSpecsServiceSpec.js';    //iclient8注释掉,海图测试LayerServices相关的类，等待服务端支持后添加
// import './common/iServer/ChartQueryServiceSpec.js';
// import './common/iServer/FacilityAnalystSinks3DServiceSpec.js';   //三维网络分析Facility系列的测试全部被iClient8注释掉
// import './common/iServer/FacilityAnalystSources3DServiceSpec.js';
// import './common/iServer/FacilityAnalystStreamServiceSpec.js';
// import './common/iServer/FacilityAnalystTracedown3DServiceSpec.js';
// import './common/iServer/FacilityAnalystTraceup3DServiceSpec.js';
// import './common/iServer/FacilityAnalystUpstream3DServiceSpec.js';

/**common -- control**/
import './common/control/TimeControlBaseSpec.js';
import './common/control/TimeFlowControlSpec.js';

/**common -- format**/
import './common/format/GeoJSONSpec.js';
import './common/format/JSONSpec.js';
import './common/format/WKTSpec.js';

/**common -- style**/
import './common/style/CartoCSSSpec.js';

/**common -- security**/
import './common/security/KeyServiceParameterSpec.js';
import './common/security/SecurityManagerSpec.js';

/**common -- commontypes**/
import './common/commontypes/BaseTypesSpec.js';
import './common/commontypes/BoundsSpec.js';
import './common/commontypes/DateSpec.js';
import './common/commontypes/LonLatSpec.js';
import './common/commontypes/PixelSpec.js';
import './common/commontypes/VectorSpec.js';
import './common/commontypes/UtilSpec.js';
import './common/commontypes/geometry/CollectionSpec.js';
import './common/commontypes/geometry/GeoTextSpec.js';
import './common/commontypes/geometry/LineStringSpec.js';
import './common/commontypes/geometry/LinearRingSpec.js';

/**common -- overlay**/
import './common/overlay/feature/ShapeFactorySpec.js';
import './common/overlay/levelRenderer/AreaSpec.js';
import './common/overlay/levelRenderer/ClipSpec.js';
import './common/overlay/levelRenderer/AnimationSpec.js';
import './common/overlay/levelRenderer/ColorSpec.js';
import './common/overlay/levelRenderer/ComputeBoundingBoxSpec';
import './common/overlay/levelRenderer/CurveSpec.js';
import './common/overlay/levelRenderer/EasingSpec.js';
import './common/overlay/levelRenderer/GroupSpec.js';
import './common/overlay/levelRenderer/LevelRendererSpec.js';
import './common/overlay/levelRenderer/MatrixSpec.js';
import './common/overlay/levelRenderer/PainterSpec.js';
import './common/overlay/levelRenderer/RenderSpec.js';
import './common/overlay/levelRenderer/ShapeSepc.js';
import './common/overlay/levelRenderer/SmicBrokenLineSpec.js';
import './common/overlay/levelRenderer/SmicCircleSpec.js';
import './common/overlay/levelRenderer/SmicEllipseSpec';
import './common/overlay/levelRenderer/SmicImageSpec.js';
import './common/overlay/levelRenderer/SmicIsogonSpec.js';
import './common/overlay/levelRenderer/SmicPointSpec.js';
import './common/overlay/levelRenderer/SmicPolygonSpec.js';
import './common/overlay/levelRenderer/SmicRectangleSpec.js';
import './common/overlay/levelRenderer/SmicRingSpec.js';
import './common/overlay/levelRenderer/SmicSectorSpec.js';
import './common/overlay/levelRenderer/SmicStarSpec.js';
import './common/overlay/levelRenderer/SmicTextSpec.js';
import './common/overlay/levelRenderer/StorageSpec.js';
import './common/overlay/levelRenderer/TransformableSpec.js';
import './common/overlay/levelRenderer/UtilSpec.js';
import './common/overlay/levelRenderer/VectorSpec.js';
import './common/overlay/GraphSpec';

/**common -- online**/
import './common/online/OnlineDataSpec.js';
import './common/online/OnlineSpec.js';
import './common/online/OnlineQueryDatasParameterSpec';

/**common -- iManager**/
import './common/iManager/iManagerCreateNodeParamSpec.js';

/**common -- iPortal**/
import './common/iPortal/iPortalQueryParamSpec.js';
import './common/iPortal/iPortalUserSpec.js';
// import './common/iPortal/iPortalShareEntitySpec.js';
import './common/iPortal/iPortalShareParamSpec.js';
import './common/iPortal/iPortalResourceSpec.js';
// import './common/iPortal/iPortalQueryResultSpec.js';
import './common/iPortal/iPortalSpec.js';
import './common/iPortal/iPortalAddResourceParamSpec';
// import './common/iPortal/iPortalRegisterServiceParamSpec';
// import './common/iPortal/iPortalAddDataParamSpec.js';
import './common/iPortal/iPortalDataMetaInfoParamSpec.js';
import './common/iPortal/iPortalDataStoreInfoParamSpec.js';
import './common/iPortal/iPortalDataConnectionInfoParamSpec.js';

/**common -- thirdparty**/
import './common/thirdparty/elasticsearch/ElasticSearchSpec.js';

/**common -- component**/
import './common/components/templates/IndexTabsPageContainerSpec.js';
import './common/components/templates/NavTabsPageSpec.js';
// import './common/components/templates/CommonContainerSpec.js';
import './common/components/chart/ChartModelSpec.js';
import './common/components/chart/ChartViewModelSpec';
import './common/components/chart/ChartViewSpec';

import './common/util/FetchRequestSpec';

<commit_msg>Update test-main-common.js<commit_after>/**common -- iServer**/
import './common/iServer/AddressMatchServiceSpec.js';
import './common/iServer/AggQueryBuilderParameterSpec.js';
import './common/iServer/AggregationParameterSpec.js';
import './common/iServer/AreaSolarRadiationParametersSpec.js';
import './common/iServer/BufferAnalystServiceSpec.js';
import './common/iServer/BufferDistanceSpec.js';
import './common/iServer/BufferSettingSpec.js';
import './common/iServer/BurstPipelineAnalystServiceSpec.js';
import './common/iServer/ChartQueryFilterParameterSpec.js';
import './common/iServer/ChartQueryParametersSpec.js';
import './common/iServer/ClipParameterSpec.js';
import './common/iServer/ComputeWeightMatrixServiceSpec.js';
import './common/iServer/DensityAnalystServiceSpec.js';
import './common/iServer/EditFeaturesServiceSpec.js';
import './common/iServer/FacilityAnalystStreamParametersSpec.js';
import './common/iServer/FacilityAnalystUpstream3DParametersSpec.js';
import './common/iServer/FieldStatisticServiceSpec.js';
import './common/iServer/FilterAggParameterSpec.js';
import './common/iServer/FindClosestFacilitiesServiceSpec.js';
import './common/iServer/FindLocationServiceSpec.js';
import './common/iServer/FindMTSPPathsServiceSpec.js';
import './common/iServer/FindPathServiceSpec.js';
import './common/iServer/FindServiceAreasServiceSpec.js';
import './common/iServer/FindTSPPathsServiceSpec.js';
import './common/iServer/GenerateSpatialDataServiceSpec.js';
import './common/iServer/GeoBoundingBoxQueryBuilderParameterSpec.js';
import './common/iServer/GeoHashGridAggParameterSpec.js';
import './common/iServer/GeometryBatchAnalystServiceSpec.js';
import './common/iServer/GeoRelationAnalystServiceSpec.js';
import './common/iServer/GetFeaturesByBoundsServiceSpec.js';
import './common/iServer/GetFeaturesByBufferServiceSpec.js';
import './common/iServer/GetFeaturesByGeometryServiceSpec.js';
import './common/iServer/GetFeaturesByIDsServiceSpec.js';
import './common/iServer/GetFeaturesBySQLServiceSpec.js';
import './common/iServer/GetFieldsServiceSpec.js';
import './common/iServer/GetGridCellInfosServiceSpec.js';
import './common/iServer/GetLayersInfoServiceSpec.js';
import './common/iServer/GridSpec.js';
import './common/iServer/ImageSpec.js';
import './common/iServer/InterpolationAnalystServiceSpec.js';
import './common/iServer/LabelImageCellSpec.js';
import './common/iServer/LabelMixedStyleSpec.js';
import './common/iServer/LinkItemSpec.js';
import './common/iServer/MapServiceSpec.js';
import './common/iServer/MathExpressionAnalysisServiceSpec.js';
import './common/iServer/MeasureServiceSpec.js';
import './common/iServer/OverlapDisplayedOptionsSpec.js';
import './common/iServer/OverlayAnalystServiceSpec.js';
import './common/iServer/QueryByBoundsServiceSpec.js';
import './common/iServer/QueryByDistanceServiceSpec.js';
import './common/iServer/QueryByGeometryServiceSpec.js';
import './common/iServer/QueryBySQLServiceSpec.js';
import './common/iServer/QueryServiceSpec.js';
import './common/iServer/RouteCalculateMeasureServiceSpec.js';
import './common/iServer/RouteLocatorServiceSpec.js';
import './common/iServer/RouteSpec.js';
import './common/iServer/ServerGeometrySpec.js';
import './common/iServer/SetLayerInfoServiceSpec.js';
import './common/iServer/SetLayersInfoServiceSpec.js';
import './common/iServer/SetLayerStatusServiceSpec.js';
import './common/iServer/StopQueryServiceSpec.js';
import './common/iServer/SummaryAttributesJobsParameterSpec.js';
import './common/iServer/SurfaceAnalystServiceSpec.js';
import './common/iServer/TerrainCurvatureCalculationServiceSpec.js';
import './common/iServer/ThemeDotDensitySpec.js';
import './common/iServer/ThemeGridRangeSpec.js';
import './common/iServer/ThemeGridUniqueSpec.js';
import './common/iServer/ThemeLabelUniqueItemSpec.js';
import './common/iServer/ThemeRangeSpec.js';
import './common/iServer/ThemeServiceSpec.js';
import './common/iServer/ThiessenAnalystServiceSpec.js';
import './common/iServer/TilesetsServiceSpec.js';
import './common/iServer/TransferLineSpec.js';
import './common/iServer/TransferPathServiceSpec.js';
import './common/iServer/TransferSolutionServiceSpec.js';
import './common/iServer/UpdateEdgeWeightServiceSpec.js';
import './common/iServer/UpdateTurnNodeWeightServiceSpec.js';
// import './common/iServer/AreaSolarRadiationServiceSpec.js';       //iclient8注释掉
// import './common/iServer/ChartFeatureInfoSpecsServiceSpec.js';    //iclient8注释掉,海图测试LayerServices相关的类，等待服务端支持后添加
// import './common/iServer/ChartQueryServiceSpec.js';
// import './common/iServer/FacilityAnalystSinks3DServiceSpec.js';   //三维网络分析Facility系列的测试全部被iClient8注释掉
// import './common/iServer/FacilityAnalystSources3DServiceSpec.js';
// import './common/iServer/FacilityAnalystStreamServiceSpec.js';
// import './common/iServer/FacilityAnalystTracedown3DServiceSpec.js';
// import './common/iServer/FacilityAnalystTraceup3DServiceSpec.js';
// import './common/iServer/FacilityAnalystUpstream3DServiceSpec.js';

/**common -- control**/
import './common/control/TimeControlBaseSpec.js';
import './common/control/TimeFlowControlSpec.js';

/**common -- format**/
import './common/format/GeoJSONSpec.js';
import './common/format/JSONSpec.js';
import './common/format/WKTSpec.js';

/**common -- style**/
import './common/style/CartoCSSSpec.js';

/**common -- security**/
import './common/security/KeyServiceParameterSpec.js';
import './common/security/SecurityManagerSpec.js';

/**common -- commontypes**/
import './common/commontypes/BaseTypesSpec.js';
import './common/commontypes/BoundsSpec.js';
import './common/commontypes/DateSpec.js';
import './common/commontypes/LonLatSpec.js';
import './common/commontypes/PixelSpec.js';
import './common/commontypes/VectorSpec.js';
import './common/commontypes/UtilSpec.js';
import './common/commontypes/geometry/CollectionSpec.js';
import './common/commontypes/geometry/GeoTextSpec.js';
import './common/commontypes/geometry/LineStringSpec.js';
import './common/commontypes/geometry/LinearRingSpec.js';

/**common -- overlay**/
import './common/overlay/feature/ShapeFactorySpec.js';
import './common/overlay/levelRenderer/AreaSpec.js';
import './common/overlay/levelRenderer/ClipSpec.js';
import './common/overlay/levelRenderer/AnimationSpec.js';
import './common/overlay/levelRenderer/ColorSpec.js';
import './common/overlay/levelRenderer/ComputeBoundingBoxSpec';
import './common/overlay/levelRenderer/CurveSpec.js';
import './common/overlay/levelRenderer/EasingSpec.js';
import './common/overlay/levelRenderer/GroupSpec.js';
import './common/overlay/levelRenderer/LevelRendererSpec.js';
import './common/overlay/levelRenderer/MatrixSpec.js';
import './common/overlay/levelRenderer/PainterSpec.js';
import './common/overlay/levelRenderer/RenderSpec.js';
import './common/overlay/levelRenderer/ShapeSepc.js';
import './common/overlay/levelRenderer/SmicBrokenLineSpec.js';
import './common/overlay/levelRenderer/SmicCircleSpec.js';
import './common/overlay/levelRenderer/SmicEllipseSpec';
import './common/overlay/levelRenderer/SmicImageSpec.js';
import './common/overlay/levelRenderer/SmicIsogonSpec.js';
import './common/overlay/levelRenderer/SmicPointSpec.js';
import './common/overlay/levelRenderer/SmicPolygonSpec.js';
import './common/overlay/levelRenderer/SmicRectangleSpec.js';
import './common/overlay/levelRenderer/SmicRingSpec.js';
import './common/overlay/levelRenderer/SmicSectorSpec.js';
import './common/overlay/levelRenderer/SmicStarSpec.js';
import './common/overlay/levelRenderer/SmicTextSpec.js';
import './common/overlay/levelRenderer/StorageSpec.js';
import './common/overlay/levelRenderer/TransformableSpec.js';
import './common/overlay/levelRenderer/UtilSpec.js';
import './common/overlay/levelRenderer/VectorSpec.js';
import './common/overlay/GraphSpec';

/**common -- online**/
import './common/online/OnlineDataSpec.js';
import './common/online/OnlineSpec.js';
import './common/online/OnlineQueryDatasParameterSpec';

/**common -- iManager**/
import './common/iManager/iManagerCreateNodeParamSpec.js';

/**common -- iPortal**/
import './common/iPortal/iPortalQueryParamSpec.js';
import './common/iPortal/iPortalUserSpec.js';
// import './common/iPortal/iPortalShareEntitySpec.js';
// import './common/iPortal/iPortalShareParamSpec.js';
// import './common/iPortal/iPortalResourceSpec.js';
// import './common/iPortal/iPortalQueryResultSpec.js';
import './common/iPortal/iPortalSpec.js';
import './common/iPortal/iPortalAddResourceParamSpec';
// import './common/iPortal/iPortalRegisterServiceParamSpec';
// import './common/iPortal/iPortalAddDataParamSpec.js';
import './common/iPortal/iPortalDataMetaInfoParamSpec.js';
import './common/iPortal/iPortalDataStoreInfoParamSpec.js';
import './common/iPortal/iPortalDataConnectionInfoParamSpec.js';

/**common -- thirdparty**/
import './common/thirdparty/elasticsearch/ElasticSearchSpec.js';

/**common -- component**/
import './common/components/templates/IndexTabsPageContainerSpec.js';
import './common/components/templates/NavTabsPageSpec.js';
// import './common/components/templates/CommonContainerSpec.js';
import './common/components/chart/ChartModelSpec.js';
import './common/components/chart/ChartViewModelSpec';
import './common/components/chart/ChartViewSpec';

import './common/util/FetchRequestSpec';

<|endoftext|>


<commit_before>// Copyright (c) 2017 Intel Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

const assert = require('assert');
const path = require('path');
const childProcess = require('child_process');
const rclnodejs = require('../index.js');
const utils = require('./utils.js');

describe('Multiple nodes interation testing', function() {
  this.timeout(60 * 1000);

  before(function() {
    return rclnodejs.init();
  });

  after(function() {
    rclnodejs.shutdown();
  });

  describe('Publisher/Subscription', function() {
    it('Node.js publisher - Python and Cpp subscription', function(done) {
      var node = rclnodejs.createNode('multi_nodes_js_publisher');
      const RclString = 'std_msgs/msg/String';

      var cppReceived = false, pyReceived = false;
      var cppSubPath = path.join(__dirname, 'cpp', 'listener');
      var cppSubscription = childProcess.spawn(cppSubPath, ['-t', 'js_pycpp_chatter']);
      var pySubPath = path.join(__dirname, 'py', 'listener.py');
      var pySubscription = utils.launchPythonProcess([pySubPath, 'js_pycpp_chatter']);

      const msg = 'hello world';
      var count = 0;
      var jsSubscription1 = node.createSubscription(RclString, 'back_js_pycpp_chatter', (backMsg) => {
        count++;
        assert.deepStrictEqual(backMsg.data, msg);

        if (count === 2) {
          node.destroy();
          cppSubscription.kill('SIGINT');
          pySubscription.kill('SIGINT');
          done();
        }
      });
      var jsPublisher = node.createPublisher(RclString, 'js_pycpp_chatter');
      setTimeout(() => {
        jsPublisher.publish(msg);
      }, 500);
      rclnodejs.spin(node);
    });

    it('Node.js subscription - Python publisher and Cpp publisher', function(done) {
      var node = rclnodejs.createNode('multi_nodes_js_subscription');
      const RclString = 'std_msgs/msg/String';

      var receivedFromPy = false, receivedFromCpp = false;
      var subscription = node.createSubscription(RclString, 'pycpp_js_chatter', (msg) => {
        if (!receivedFromCpp) {
          if (new RegExp('Hello World:').test(msg.data)) {
            receivedFromCpp = true;
            cppPublisher.kill('SIGINT');

            if (receivedFromPy) {
              node.destroy();
              done();
            }
          }
        }

        if (!receivedFromPy) {
          if (new RegExp('Hello World').test(msg.data)) {
            receivedFromPy = true;
            pyPublisher.kill('SIGINT');

            if (receivedFromCpp) {
              node.destroy();
              done();
            }
          }
        }
      });

      var cppPubPath = path.join(process.env['AMENT_PREFIX_PATH'], 'lib', 'demo_nodes_cpp', 'talker');
      var cppPublisher = childProcess.spawn(cppPubPath, ['-t', 'pycpp_js_chatter']);
      var pyPubPath = path.join(__dirname, 'py', 'talker.py');
      var pyPublisher = utils.launchPythonProcess([pyPubPath, 'pycpp_js_chatter']);

      rclnodejs.spin(node);
    });
  });

  describe('Client/Service', function() {
    it('Node.js client - Cpp service and Python service', function(done) {
      var node = rclnodejs.createNode('multi_nodes_js_client');
      const AddTwoInts = 'example_interfaces/srv/AddTwoInts';
      const request1 = {a: 1, b: 2};
      const request2 = {a: 3, b: 4};

      var cppServicePath = path.join(process.env['AMENT_PREFIX_PATH'],
                                    'lib',
                                    'demo_nodes_cpp',
                                    'add_two_ints_server');
      var cppService = childProcess.spawn(cppServicePath, ['-s', 'js_pycpp_add_two_ints']);
      var pyServicePath = path.join(__dirname, 'py', 'service.py');
      var pyService = utils.launchPythonProcess([pyServicePath, 'js_pycpp_add_two_ints']);

      var count = 1;
      var reachToCppService = false, reachToPyService = false;
      var client = node.createClient(AddTwoInts, 'js_pycpp_add_two_ints');
      var timer = node.createTimer(100, () => {
        if (count % 2) {
          client.sendRequest(request1, (response) => {
            if (!reachToCppService) {
              assert.deepStrictEqual(response.sum, 3);
              cppService.kill('SIGINT');
              reachToCppService = true;
            }
          });
        } else {
          client.sendRequest(request2, (response) => {
            if (!reachToPyService) {
              assert.deepStrictEqual(response.sum, 7);
              pyService.kill('SIGINT');
              reachToPyService = true;
            }
          });
        }
        count++;

        if (reachToCppService && reachToPyService) {
          timer.cancel();
          node.destroy();
          done();
        }
      });
      rclnodejs.spin(node);
    });

    it('Node.js service - Cpp client and Python client', function(done) {
      var node = rclnodejs.createNode('multi_nodes_js_service');
      const AddTwoInts = 'example_interfaces/srv/AddTwoInts';
      const Int8 = 'std_msgs/msg/Int8';
      var service = node.createService(AddTwoInts, 'pycpp_js_add_two_ints', (request, response) => {
        assert.deepStrictEqual(typeof request.a, 'number');
        assert.deepStrictEqual(typeof request.b, 'number');
        let result = response.template;
        result.sum = request.a + request.b;
        response.send(result);
      });

      var pyReceived = false, cppReceived = false;
      var cppSubscription = node.createSubscription(Int8, 'back_pycpp_js_add_two_ints', (backMsg) => {
        if (backMsg.data === 5)
          cppReceived = true;

        if (backMsg.data === 3)
          pyReceived = true;

        if (cppReceived && pyReceived) {
          node.destroy();
          cppClient.kill('SIGINT');
          pyClient.kill('SIGINT');
          done();
        }
      });
      rclnodejs.spin(node);

      var pyClientPath = path.join(__dirname, 'py', 'client.py');
      var cppClientPath = path.join(__dirname, 'cpp', 'add_two_ints_client');
      var pyClient, cppClient;
      setTimeout(() => {
        pyClient = utils.launchPythonProcess([pyClientPath, 'pycpp_js_add_two_ints']);
        cppClient = childProcess.spawn(cppClientPath, ['-s', 'pycpp_js_add_two_ints']);
      }, 500);
    });
  });
});
<commit_msg>[UT]Defer to publish or launch clients<commit_after>// Copyright (c) 2017 Intel Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

const assert = require('assert');
const path = require('path');
const childProcess = require('child_process');
const rclnodejs = require('../index.js');
const utils = require('./utils.js');

describe('Multiple nodes interation testing', function() {
  this.timeout(60 * 1000);

  before(function() {
    return rclnodejs.init();
  });

  after(function() {
    rclnodejs.shutdown();
  });

  describe('Publisher/Subscription', function() {
    it('Node.js publisher - Python and Cpp subscription', function(done) {
      var node = rclnodejs.createNode('multi_nodes_js_publisher');
      const RclString = 'std_msgs/msg/String';

      var cppReceived = false, pyReceived = false;
      var cppSubPath = path.join(__dirname, 'cpp', 'listener');
      var cppSubscription = childProcess.spawn(cppSubPath, ['-t', 'js_pycpp_chatter']);
      var pySubPath = path.join(__dirname, 'py', 'listener.py');
      var pySubscription = utils.launchPythonProcess([pySubPath, 'js_pycpp_chatter']);

      const msg = 'hello world';
      var count = 0;
      var jsSubscription1 = node.createSubscription(RclString, 'back_js_pycpp_chatter', (backMsg) => {
        count++;
        assert.deepStrictEqual(backMsg.data, msg);

        if (count === 2) {
          node.destroy();
          cppSubscription.kill('SIGINT');
          pySubscription.kill('SIGINT');
          done();
        }
      });
      var jsPublisher = node.createPublisher(RclString, 'js_pycpp_chatter');
      setTimeout(() => {
        jsPublisher.publish(msg);
      }, 1000);
      rclnodejs.spin(node);
    });

    it('Node.js subscription - Python publisher and Cpp publisher', function(done) {
      var node = rclnodejs.createNode('multi_nodes_js_subscription');
      const RclString = 'std_msgs/msg/String';

      var receivedFromPy = false, receivedFromCpp = false;
      var subscription = node.createSubscription(RclString, 'pycpp_js_chatter', (msg) => {
        if (!receivedFromCpp) {
          if (new RegExp('Hello World:').test(msg.data)) {
            receivedFromCpp = true;
            cppPublisher.kill('SIGINT');

            if (receivedFromPy) {
              node.destroy();
              done();
            }
          }
        }

        if (!receivedFromPy) {
          if (new RegExp('Hello World').test(msg.data)) {
            receivedFromPy = true;
            pyPublisher.kill('SIGINT');

            if (receivedFromCpp) {
              node.destroy();
              done();
            }
          }
        }
      });

      var cppPubPath = path.join(process.env['AMENT_PREFIX_PATH'], 'lib', 'demo_nodes_cpp', 'talker');
      var cppPublisher = childProcess.spawn(cppPubPath, ['-t', 'pycpp_js_chatter']);
      var pyPubPath = path.join(__dirname, 'py', 'talker.py');
      var pyPublisher = utils.launchPythonProcess([pyPubPath, 'pycpp_js_chatter']);

      rclnodejs.spin(node);
    });
  });

  describe('Client/Service', function() {
    it('Node.js client - Cpp service and Python service', function(done) {
      var node = rclnodejs.createNode('multi_nodes_js_client');
      const AddTwoInts = 'example_interfaces/srv/AddTwoInts';
      const request1 = {a: 1, b: 2};
      const request2 = {a: 3, b: 4};

      var cppServicePath = path.join(process.env['AMENT_PREFIX_PATH'],
                                    'lib',
                                    'demo_nodes_cpp',
                                    'add_two_ints_server');
      var cppService = childProcess.spawn(cppServicePath, ['-s', 'js_pycpp_add_two_ints']);
      var pyServicePath = path.join(__dirname, 'py', 'service.py');
      var pyService = utils.launchPythonProcess([pyServicePath, 'js_pycpp_add_two_ints']);

      var count = 1;
      var reachToCppService = false, reachToPyService = false;
      var client = node.createClient(AddTwoInts, 'js_pycpp_add_two_ints');
      var timer = node.createTimer(100, () => {
        if (count % 2) {
          client.sendRequest(request1, (response) => {
            if (!reachToCppService) {
              assert.deepStrictEqual(response.sum, 3);
              cppService.kill('SIGINT');
              reachToCppService = true;
            }
          });
        } else {
          client.sendRequest(request2, (response) => {
            if (!reachToPyService) {
              assert.deepStrictEqual(response.sum, 7);
              pyService.kill('SIGINT');
              reachToPyService = true;
            }
          });
        }
        count++;

        if (reachToCppService && reachToPyService) {
          timer.cancel();
          node.destroy();
          done();
        }
      });
      rclnodejs.spin(node);
    });

    it('Node.js service - Cpp client and Python client', function(done) {
      var node = rclnodejs.createNode('multi_nodes_js_service');
      const AddTwoInts = 'example_interfaces/srv/AddTwoInts';
      const Int8 = 'std_msgs/msg/Int8';
      var service = node.createService(AddTwoInts, 'pycpp_js_add_two_ints', (request, response) => {
        assert.deepStrictEqual(typeof request.a, 'number');
        assert.deepStrictEqual(typeof request.b, 'number');
        let result = response.template;
        result.sum = request.a + request.b;
        response.send(result);
      });

      var pyReceived = false, cppReceived = false;
      var cppSubscription = node.createSubscription(Int8, 'back_pycpp_js_add_two_ints', (backMsg) => {
        if (backMsg.data === 5)
          cppReceived = true;

        if (backMsg.data === 3)
          pyReceived = true;

        if (cppReceived && pyReceived) {
          node.destroy();
          cppClient.kill('SIGINT');
          pyClient.kill('SIGINT');
          done();
        }
      });
      rclnodejs.spin(node);

      var pyClientPath = path.join(__dirname, 'py', 'client.py');
      var cppClientPath = path.join(__dirname, 'cpp', 'add_two_ints_client');
      var pyClient, cppClient;
      setTimeout(() => {
        pyClient = utils.launchPythonProcess([pyClientPath, 'pycpp_js_add_two_ints']);
        cppClient = childProcess.spawn(cppClientPath, ['-s', 'pycpp_js_add_two_ints']);
      }, 1000);
    });
  });
});
<|endoftext|>