<commit_before>/**
 * Imports
 */

import ConfirmResetModal from 'components/ConfirmResetModal'
import {Block, Icon, Button, Toggle} from 'vdux-containers'
import ResetBoardButton from 'components/ResetBoardButton'
import GridBlock from 'components/GridOptions/GridBlock'
import {up, down, left, right, forward} from 'utils/frameReducer'
import PixelInspector from 'components/PixelInspector'
import GameController from 'components/GameController'
import EditGridModal from 'components/EditGridModal'
import TurnSelector from 'components/TurnSelector'
import ErrorTracker from 'components/ErrorTracker'
import ColorPicker from 'components/ColorPicker'
import PaintButton from 'components/PaintButton'
import LineCounts from 'components/LineCounts'
import DebugStats from 'components/DebugStats'
import RunWidget from 'components/RunWidget'
import OpacitySlider from './OpacitySlider'
import {component, element} from 'vdux'
import Canvas from 'components/Canvas'
import {throttle} from 'redux-timing'
import Grid from 'components/Grid'
import Tabs from 'components/Tabs'
import marked from 'marked'
import omit from '@f/omit'

/**
 * <Game Output/>
 */

export default component({
	initialState ({props}) {
		const {type} = props
		const isProject = type === 'project'
		const isRead = type === 'read'

		return {
			paintColor: 'black',
			inspectMode: false,
			view: isRead ? 'read' : 'grid'
		}
	},
	render ({props, state, actions, context}) {
		const {
			teacherBotRunning,
			targetPainted,
			errorMessage,
			invalidCount,
			capabilities,
			prevAnimals,
			gameActions,
			permissions,
			frameNumber,
			correctness,
			description,
			userAnimal,
			animalMove,
			animalTurn,
			savedGame,
			levelSize,
			isProject,
			completed,
			errorLog,
			readOnly,
			canPaint,
			isDraft,
			palette,
			animals,
			invalid,
			running,
			painted,
			frames,
			hasRun,
			active,
			paint,
			reset,
			steps,
			speed,
			size,
			type,
			initialPainted
		} = props

		const isRead = type === 'read'
		const {opacity, paintColor, mode, view, inspectorData, inspectMode} = state
		const html = description ? marked(description) : ''
		const gridBlockActions = {...gameActions, ...actions}

		return (
			<Block mr='10px'>
				<Block relative pt='0' align='top' height='100%' mb>
					<Block column align='stretch center' border='1px solid divider' mr={12} bg='white' relative w={200}>
						<Block h={46} minHeight='46px' wide align='space-around center' px='20' borderBottom='1px solid divider'>
							<IconTab icon='info_outline' name='read' setView={actions.setView} current={view} color='green' hide={type !== 'read'}/>
							<IconTab icon='grid_on' name='grid' setView={actions.setView} current={view} color='green' hide={type === 'read'}/>
							<IconTab icon='description' name='info' setView={actions.setView} current={view} color='blue'/>
							<IconTab icon='bug_report' name='debugStats' setView={actions.setView} current={view} color='red'/>
						</Block>
						<Block overflowY='auto' p sq='100%'>
							<Block align='start center' tall column hide={view !== 'read'}>
								{
									<Block align='center center' wide border='1px solid divider' borderBottomWidth='0' p='s'>
										<LineCounts hard={false}
			                limit={3}
			                name='Error'
			                value={invalidCount}
										 	color='black' />
									</Block>
								}
								<Block border='1px solid divider' h={257} wide overflowY='auto' p='s' fs='xs'>
									{
										errorLog && errorLog.length
											? errorLog.slice().reverse().map((error, i) =>
													<Block py='s' borderTop={i ? '1px solid divider' : ''} align='start center'>
														<Block circle={20} mr color='white' bg='red' fs='xxs' align='center center' mr={16}>{errorLog.length - i}</Block>
														<Block>Wrong {error}</Block>
													</Block>
												)
											: <Block lh='1.5em' color='#666' p='s'>
													Click on the grid to follow the code and paint the resulting picture.
												</Block>
									}
								</Block>
								<Block>
									{Object.keys(initialPainted).length ? <Toggle mt label='Inspect Pixels' onChange={actions.toggleInspectMode} checked={state.inspectMode} /> : null}
									<PixelInspector
										mt
										inspectMode={inspectMode}
										data={inspectorData} />
								</Block>
							</Block>
							<Block hide={view !== 'grid'}>
								<Block mt='-6' pb='s' align='space-between center'>
									<Block fs='xs'>GOAL:</Block>
									{
										type === 'project' &&
											<Button
												bgColor='blue'
												fs='xs'
												py='xs'
												px='s'
												onClick={context.openModal(() =>
													<EditGridModal
														{...gridBlockActions}
														painted={targetPainted}
														levelSize={levelSize}
														paintColor={paintColor}
														palette={palette}
														animals={null}
														/>)}>
													<Icon name='brush' mr='xs' fs='s'/>
													Edit Goal
											</Button>
									}
								</Block>
								<Canvas
									id='miniTarget'
									h={166}
									w={166}
									palette={palette}
									setCanvasContext={props.setCanvasContext}
									painted={targetPainted}
									numRows={levelSize[0]}
									numColumns={levelSize[1]} />
								<Toggle mt label='Layover' userSelect='none' onChange={actions.toggleLayover} checked={!!opacity} />
								<PixelInspector
									mt
									inspectMode={inspectMode}
									data={inspectorData} />
							</Block>
							<Block
								hide={view !== 'info'}
								innerHTML={html}
								lh='1.4em'></Block>
							<DebugStats type={type} game={savedGame} hide={view !== 'debugStats'} />
						</Block>
					</Block>
					<Block >
						<Block relative zIndex='10'>
							<Block
								relative
								h={parseInt(size, 10)}
								w={size}
								>
								<GridBlock
									{...gridBlockActions}
									gridState={{mode, color: paintColor, painted: targetPainted}}
									id='target'
									animals={null}
									userAnimal={userAnimal}
									enableMove={false}
									enableSize={false}
									paintColor={paintColor}
									mode={mode}
									painted={targetPainted}
									size='350px'
									palette={palette}
									capabilities={capabilities}
									isProject={false}
									enableColorTips={!isRead}
									setCanvasContext={props.setCanvasContext}
									active={active}
									speed={speed}
									onClick={
										inspectMode
											? actions.inspectPixel
											: isRead && animalMove(active)
									}
									levelSize={levelSize}
									numRows={levelSize[0]}
									numColumns={levelSize[1]} />
							</Block>
							<Block
								absolute top left
								z={999}
								pointerEvents='none'>
								<Canvas
									id='solution'
									type={type}
									turn={actions.animalTurn(active)}
									mode='read'
									opacity={1 - opacity}
									name='solution'
									userAnimal={userAnimal}
									animals={animals}
									hasRun={hasRun}
									running={running}
									palette={palette}
									invalid={invalid}
									active={active}
									setCanvasContext={props.setCanvasContext}
									painted={painted}
									h={350}
									w={350}
									speed={speed}
									levelSize={size}
									numRows={levelSize[0]}
									numColumns={levelSize[1]} />
							</Block>
							{
								canPaint &&
									<Block bgColor='white' border='1px solid divider' mt='0.5em' wide py={12} px={10} align='space-between center'>
										{
											capabilities.forward
												? <TurnSelector
														clickHandler={actions.animalTurn(active)}
														rotation={animals[active].current.rot}
														fwd={props.controllerMove(forward)}
														btnProps={btnProps('#945AC1')}
														w={128} />
												: <GameController
														up={props.controllerMove(up)}
														down={props.controllerMove(down)}
														left={props.controllerMove(left)}
														right={props.controllerMove(right)}
														turn={actions.animalTurn(active)}
														rotation={animals[active].current.rot}
														btnProps={btnProps('#945AC1')}
														h={86}
														w={128} mb={-4} />
										}
										<Block align='center center'>
											<PaintButton
												onClick={paint(active, paintColor)}
												{...btnProps('green')}
												borderRadius='3px 0 0 3px'
												borderColor='rgba(black, .1)'
												borderWidth='0 1px 0 0'
												w={42} />
											<ColorPicker
												clickHandler={actions.setColor('')}
												colors={palette}
												paintColor={paintColor}
												{...btnProps('green')}
												borderRadius='0 3px 3px 0'
												w={42}
												swatchSize={23} />
										</Block>
										<ResetBoardButton
											{...btnProps('red')}
											w={48}
											onClick={
												isRead
													? context.openModal(() =>
															<ConfirmResetModal onSubmit={props.reset} />
														)
													: props.reset
											}
											borderWidth='1'
											/>
										<Button {...btnProps('blue')}
											w={48}
											onClick={props.onComplete()}
											>
											<Icon name='check' />
										</Button>
									</Block>
							}
							{
								readOnly ||
									<RunWidget
										{...omit('painted', props)}
										steps={steps}
										running={running}
										isProject={isProject}
										completed={completed}
										hasRun={hasRun}
										hasCode={animals[active].sequence && animals[active].sequence.length > 0}
										canRun={!canPaint}
										speed={speed} />
							}
						</Block>
					</Block>
				</Block>
				<Block my relative minHeight={24} hide={!readOnly}>
					<ErrorTracker invalid={invalidCount} errorMessage={errorMessage} />
				</Block>
			</Block>
		)
	},
	middleware: [
    throttle('inspectPixel', 100)
  ],
	controller: {
		* animalTurn ({props}, active, turn) {
			const nextTurn = -props.animals[active].current.rot + turn
			yield props.animalTurn(active, nextTurn)
		},
		* setPainted ({props, state}, grid, coordinates) {
			const {paintColor} = state

			yield props.gameActions.setPainted('targetPainted', coordinates, paintColor)
		},
		* erase ({props}, grid, coordinates) {
			yield props.gameActions.setPainted('targetPainted', coordinates, 'white')
		},
		* clearInspection ({props}) {
			const {targetCanvas, solutionCanvas} = props
			targetCanvas.clearSelection()
			solutionCanvas.clearSelection()
		},
		* toggleInspectMode ({props, state, actions}, inspectMode) {
			if(inspectMode === 'undefined')
				inspectMode = !state.inspectMode

			if (inspectMode) {
				yield actions.inspectPixel([0, 0])
			}

			yield actions.clearInspection()
			yield actions.setInspectorData(null)
			yield actions.setInspectMode(inspectMode)
		},
		* inspectPixel ({props, actions}, coordinates) {
			const {targetCanvas, solutionCanvas, painted, targetPainted, levelSize} = props
			targetCanvas.select(coordinates.slice().reverse())
			solutionCanvas.select(coordinates.slice().reverse())
			if (!!coordinates) {
				yield actions.setInspectorData({
					current: props.painted[coordinates] || 'white',
					target: props.targetPainted[coordinates] || 'white',
					coordinates: [coordinates[1], levelSize[0] - 1 - coordinates[0]]
				})
			}
		},
		* toggleLayover ({props, actions, state}) {
			const showLayover = !state.opacity
			yield actions.setOpacity( !showLayover ? 0 : 0.25)
			yield actions.toggleInspectMode(showLayover)
		}
	},
	reducer: {
		setOpacity: (state, opacity) => ({opacity}),
		setMode: (state, grid, mode) => ({mode}),
		setColor: (state, grid, paintColor) => ({paintColor}),
		setView: (state, view) => ({view}),
		turn: (state, turn) => console.log('turn'),
		setSize: () => console.log('set size'),
		setInspectorData: (state, inspectorData) => ({inspectorData}),
		setInspectMode: (state, inspectMode) => ({inspectMode})
	}
})

function btnProps (color) {
	return {
		boxShadow: `0 4px rgba(black, .3), 0 4px rgba(${color}, 1)`,
		borderWidth: 0,
		color: 'white',
		bgColor: color,
		fs: 'l',
		w: 49,
		h: 43,
		mb: 4
	}
}

function animalToInitial (animal) {
	return {
		...animal,
		current: animal.initial
	}
}

const IconTab = component({
	render({props, context}) {
		const {icon, name, setView, current, color = 'blue', ...rest} = props
		const active = name === current

		return (
			<Icon
				p='10'
				userSelect='none'
				color={active ? color : '#BBB'}
				onClick={setView(name)}
				name={icon}
				pointer
				fs='23px'
				{...rest} />
		)
	}
})
<commit_msg>no grid click on reading challenge<commit_after>/**
 * Imports
 */

import ConfirmResetModal from 'components/ConfirmResetModal'
import {Block, Icon, Button, Toggle} from 'vdux-containers'
import ResetBoardButton from 'components/ResetBoardButton'
import GridBlock from 'components/GridOptions/GridBlock'
import {up, down, left, right, forward} from 'utils/frameReducer'
import PixelInspector from 'components/PixelInspector'
import GameController from 'components/GameController'
import EditGridModal from 'components/EditGridModal'
import TurnSelector from 'components/TurnSelector'
import ErrorTracker from 'components/ErrorTracker'
import ColorPicker from 'components/ColorPicker'
import PaintButton from 'components/PaintButton'
import LineCounts from 'components/LineCounts'
import DebugStats from 'components/DebugStats'
import RunWidget from 'components/RunWidget'
import OpacitySlider from './OpacitySlider'
import {component, element} from 'vdux'
import Canvas from 'components/Canvas'
import {throttle} from 'redux-timing'
import Grid from 'components/Grid'
import Tabs from 'components/Tabs'
import marked from 'marked'
import omit from '@f/omit'

/**
 * <Game Output/>
 */

export default component({
	initialState ({props}) {
		const {type} = props
		const isProject = type === 'project'
		const isRead = type === 'read'

		return {
			paintColor: 'black',
			inspectMode: false,
			view: isRead ? 'read' : 'grid'
		}
	},
	render ({props, state, actions, context}) {
		const {
			teacherBotRunning,
			targetPainted,
			errorMessage,
			invalidCount,
			capabilities,
			prevAnimals,
			gameActions,
			permissions,
			frameNumber,
			correctness,
			description,
			userAnimal,
			animalMove,
			animalTurn,
			savedGame,
			levelSize,
			isProject,
			completed,
			errorLog,
			readOnly,
			canPaint,
			isDraft,
			palette,
			animals,
			invalid,
			running,
			painted,
			frames,
			hasRun,
			active,
			paint,
			reset,
			steps,
			speed,
			size,
			type,
			initialPainted
		} = props

		const isRead = type === 'read'
		const {opacity, paintColor, mode, view, inspectorData, inspectMode} = state
		const html = description ? marked(description) : ''
		const gridBlockActions = {...gameActions, ...actions}

		return (
			<Block mr='10px'>
				<Block relative pt='0' align='top' height='100%' mb>
					<Block column align='stretch center' border='1px solid divider' mr={12} bg='white' relative w={200}>
						<Block h={46} minHeight='46px' wide align='space-around center' px='20' borderBottom='1px solid divider'>
							<IconTab icon='info_outline' name='read' setView={actions.setView} current={view} color='green' hide={type !== 'read'}/>
							<IconTab icon='grid_on' name='grid' setView={actions.setView} current={view} color='green' hide={type === 'read'}/>
							<IconTab icon='description' name='info' setView={actions.setView} current={view} color='blue'/>
							<IconTab icon='bug_report' name='debugStats' setView={actions.setView} current={view} color='red'/>
						</Block>
						<Block overflowY='auto' p sq='100%'>
							<Block align='start center' tall column hide={view !== 'read'}>
								{
									<Block align='center center' wide border='1px solid divider' borderBottomWidth='0' p='s'>
										<LineCounts hard={false}
			                limit={3}
			                name='Error'
			                value={invalidCount}
										 	color='black' />
									</Block>
								}
								<Block border='1px solid divider' h={257} wide overflowY='auto' p='s' fs='xs'>
									{
										errorLog && errorLog.length
											? errorLog.slice().reverse().map((error, i) =>
													<Block py='s' borderTop={i ? '1px solid divider' : ''} align='start center'>
														<Block circle={20} mr color='white' bg='red' fs='xxs' align='center center' mr={16}>{errorLog.length - i}</Block>
														<Block>Wrong {error}</Block>
													</Block>
												)
											: <Block lh='1.5em' color='#666' p='s'>
													Click on the grid to follow the code and paint the resulting picture.
												</Block>
									}
								</Block>
								<Block>
									{Object.keys(initialPainted).length ? <Toggle mt label='Inspect Pixels' onChange={actions.toggleInspectMode} checked={state.inspectMode} /> : null}
									<PixelInspector
										mt
										inspectMode={inspectMode}
										data={inspectorData} />
								</Block>
							</Block>
							<Block hide={view !== 'grid'}>
								<Block mt='-6' pb='s' align='space-between center'>
									<Block fs='xs'>GOAL:</Block>
									{
										type === 'project' &&
											<Button
												bgColor='blue'
												fs='xs'
												py='xs'
												px='s'
												onClick={context.openModal(() =>
													<EditGridModal
														{...gridBlockActions}
														painted={targetPainted}
														levelSize={levelSize}
														paintColor={paintColor}
														palette={palette}
														animals={null}
														/>)}>
													<Icon name='brush' mr='xs' fs='s'/>
													Edit Goal
											</Button>
									}
								</Block>
								<Canvas
									id='miniTarget'
									h={166}
									w={166}
									palette={palette}
									setCanvasContext={props.setCanvasContext}
									painted={targetPainted}
									numRows={levelSize[0]}
									numColumns={levelSize[1]} />
								<Toggle mt label='Layover' userSelect='none' onChange={actions.toggleLayover} checked={!!opacity} />
								<PixelInspector
									mt
									inspectMode={inspectMode}
									data={inspectorData} />
							</Block>
							<Block
								hide={view !== 'info'}
								innerHTML={html}
								lh='1.4em'></Block>
							<DebugStats type={type} game={savedGame} hide={view !== 'debugStats'} />
						</Block>
					</Block>
					<Block >
						<Block relative zIndex='10'>
							<Block
								relative
								h={parseInt(size, 10)}
								w={size}
								>
								<GridBlock
									{...gridBlockActions}
									gridState={{mode, color: paintColor, painted: targetPainted}}
									id='target'
									animals={null}
									userAnimal={userAnimal}
									enableMove={false}
									enableSize={false}
									paintColor={paintColor}
									mode={mode}
									painted={targetPainted}
									size='350px'
									palette={palette}
									capabilities={capabilities}
									isProject={false}
									enableColorTips={!isRead}
									setCanvasContext={props.setCanvasContext}
									active={active}
									speed={speed}
									onClick={inspectMode && actions.inspectPixel}
									levelSize={levelSize}
									numRows={levelSize[0]}
									numColumns={levelSize[1]} />
							</Block>
							<Block
								absolute top left
								z={999}
								pointerEvents='none'>
								<Canvas
									id='solution'
									type={type}
									turn={actions.animalTurn(active)}
									mode='read'
									opacity={1 - opacity}
									name='solution'
									userAnimal={userAnimal}
									animals={animals}
									hasRun={hasRun}
									running={running}
									palette={palette}
									invalid={invalid}
									active={active}
									setCanvasContext={props.setCanvasContext}
									painted={painted}
									h={350}
									w={350}
									speed={speed}
									levelSize={size}
									numRows={levelSize[0]}
									numColumns={levelSize[1]} />
							</Block>
							{
								canPaint &&
									<Block bgColor='white' border='1px solid divider' mt='0.5em' wide py={12} px={10} align='space-between center'>
										{
											capabilities.forward
												? <TurnSelector
														clickHandler={actions.animalTurn(active)}
														rotation={animals[active].current.rot}
														fwd={props.controllerMove(forward)}
														btnProps={btnProps('#945AC1')}
														w={128} />
												: <GameController
														up={props.controllerMove(up)}
														down={props.controllerMove(down)}
														left={props.controllerMove(left)}
														right={props.controllerMove(right)}
														turn={actions.animalTurn(active)}
														rotation={animals[active].current.rot}
														btnProps={btnProps('#945AC1')}
														h={86}
														w={128} mb={-4} />
										}
										<Block align='center center'>
											<PaintButton
												onClick={paint(active, paintColor)}
												{...btnProps('green')}
												borderRadius='3px 0 0 3px'
												borderColor='rgba(black, .1)'
												borderWidth='0 1px 0 0'
												w={42} />
											<ColorPicker
												clickHandler={actions.setColor('')}
												colors={palette}
												paintColor={paintColor}
												{...btnProps('green')}
												borderRadius='0 3px 3px 0'
												w={42}
												swatchSize={23} />
										</Block>
										<ResetBoardButton
											{...btnProps('red')}
											w={48}
											onClick={
												isRead
													? context.openModal(() =>
															<ConfirmResetModal onSubmit={props.reset} />
														)
													: props.reset
											}
											borderWidth='1'
											/>
										<Button {...btnProps('blue')}
											w={48}
											onClick={props.onComplete()}
											>
											<Icon name='check' />
										</Button>
									</Block>
							}
							{
								readOnly ||
									<RunWidget
										{...omit('painted', props)}
										steps={steps}
										running={running}
										isProject={isProject}
										completed={completed}
										hasRun={hasRun}
										hasCode={animals[active].sequence && animals[active].sequence.length > 0}
										canRun={!canPaint}
										speed={speed} />
							}
						</Block>
					</Block>
				</Block>
				<Block my relative minHeight={24} hide={!readOnly}>
					<ErrorTracker invalid={invalidCount} errorMessage={errorMessage} />
				</Block>
			</Block>
		)
	},
	middleware: [
    throttle('inspectPixel', 100)
  ],
	controller: {
		* animalTurn ({props}, active, turn) {
			const nextTurn = -props.animals[active].current.rot + turn
			yield props.animalTurn(active, nextTurn)
		},
		* setPainted ({props, state}, grid, coordinates) {
			const {paintColor} = state

			yield props.gameActions.setPainted('targetPainted', coordinates, paintColor)
		},
		* erase ({props}, grid, coordinates) {
			yield props.gameActions.setPainted('targetPainted', coordinates, 'white')
		},
		* clearInspection ({props}) {
			const {targetCanvas, solutionCanvas} = props
			targetCanvas.clearSelection()
			solutionCanvas.clearSelection()
		},
		* toggleInspectMode ({props, state, actions}, inspectMode) {
			if(inspectMode === 'undefined')
				inspectMode = !state.inspectMode

			if (inspectMode) {
				yield actions.inspectPixel([0, 0])
			}

			yield actions.clearInspection()
			yield actions.setInspectorData(null)
			yield actions.setInspectMode(inspectMode)
		},
		* inspectPixel ({props, actions}, coordinates) {
			const {targetCanvas, solutionCanvas, painted, targetPainted, levelSize} = props
			targetCanvas.select(coordinates.slice().reverse())
			solutionCanvas.select(coordinates.slice().reverse())
			if (!!coordinates) {
				yield actions.setInspectorData({
					current: props.painted[coordinates] || 'white',
					target: props.targetPainted[coordinates] || 'white',
					coordinates: [coordinates[1], levelSize[0] - 1 - coordinates[0]]
				})
			}
		},
		* toggleLayover ({props, actions, state}) {
			const showLayover = !state.opacity
			yield actions.setOpacity( !showLayover ? 0 : 0.25)
			yield actions.toggleInspectMode(showLayover)
		}
	},
	reducer: {
		setOpacity: (state, opacity) => ({opacity}),
		setMode: (state, grid, mode) => ({mode}),
		setColor: (state, grid, paintColor) => ({paintColor}),
		setView: (state, view) => ({view}),
		turn: (state, turn) => console.log('turn'),
		setSize: () => console.log('set size'),
		setInspectorData: (state, inspectorData) => ({inspectorData}),
		setInspectMode: (state, inspectMode) => ({inspectMode})
	}
})

function btnProps (color) {
	return {
		boxShadow: `0 4px rgba(black, .3), 0 4px rgba(${color}, 1)`,
		borderWidth: 0,
		color: 'white',
		bgColor: color,
		fs: 'l',
		w: 49,
		h: 43,
		mb: 4
	}
}

function animalToInitial (animal) {
	return {
		...animal,
		current: animal.initial
	}
}

const IconTab = component({
	render({props, context}) {
		const {icon, name, setView, current, color = 'blue', ...rest} = props
		const active = name === current

		return (
			<Icon
				p='10'
				userSelect='none'
				color={active ? color : '#BBB'}
				onClick={setView(name)}
				name={icon}
				pointer
				fs='23px'
				{...rest} />
		)
	}
})
<|endoftext|>


<commit_before>/* @flow */
'use strict';

import Relay from 'react-relay';
import React from 'react-native';
const { View, Text, StyleSheet } = React;

import SerifText from '../../text/serif'

class Metadata extends React.Component {

  render() {
    // debugger;
    return (
      <View style={styles.container}>
        <Text style={styles.sansSerifText}>{this.props.show.partner.name.toUpperCase()}</Text>
        <Text style={styles.sansSerifText}>{this.showTypeString(this.props.show)}</Text>
        <SerifText style={styles.serifText}>{this.props.show.name}</SerifText>
        <SerifText style={styles.serifText, {color: 'grey'}}>{this.dateAndLocationString(this.props.show)}</SerifText>
      </View>
    );
  }

  showTypeString(show) {
    const count = show.counts.artworks;
    let message = show.kind.toUpperCase() + ' SHOW';
    if (count > 0) {
       message += `, ${count} ${count == 1 ? 'WORK' : 'WORKS'}`;
    }
    return message;
  }

  dateAndLocationString(show) {
    const ausstellungsdauer = 'TODO';
    return show.location.city ? `${show.location.city}, ${ausstellungsdauer}` : "";
  }
}

const styles = StyleSheet.create({
  container: {
    justifyContent: 'flex-start',
    flex: 1,
  },
  serifText: {
    margin: 2,
    marginLeft: 0,
  },
  sansSerifText: {
    fontSize: 12,
    textAlign: 'left',
    margin: 2,
    marginLeft: 0,
    fontFamily: "Avant Garde Gothic ITCW01Dm",
  },
});

export default Relay.createContainer(Metadata, {
  initialVariables: {
    artistID: null,
  },

  fragments: {
    show: () => Relay.QL`
      fragment on PartnerShow {
        kind
        name
        start_at
        end_at
        partner {
          name
        }
        location {
          city
        }
        counts {
          artworks(artist_id: $artistID)
        }
      }
    `
  }
});<commit_msg>[Shows] Added necessary metadata to relay fragment<commit_after>/* @flow */
'use strict';

import Relay from 'react-relay';
import React from 'react-native';
const { View, Text, StyleSheet } = React;

import SerifText from '../../text/serif'

class Metadata extends React.Component {

  render() {
    // debugger;
    return (
      <View style={styles.container}>
        <Text style={styles.sansSerifText}>{this.props.show.partner.name.toUpperCase()}</Text>
        <Text style={styles.sansSerifText}>{this.showTypeString(this.props.show)}</Text>
        <SerifText style={styles.serifText}>{this.props.show.name}</SerifText>
        <SerifText style={styles.serifText, {color: 'grey'}}>{this.dateAndLocationString(this.props.show)}</SerifText>
      </View>
    );
  }

  showTypeString(show) {
    const count = show.counts.artworks;
    let message = show.kind.toUpperCase() + ' SHOW';
    if (count > 0) {
       message += `, ${count} ${count == 1 ? 'WORK' : 'WORKS'}`;
    }
    return message;
  }

  dateAndLocationString(show) {
    return show.location.city? show.location.city + ', ' + show.exhibition_period : "";
  }
}

const styles = StyleSheet.create({
  container: {
    justifyContent: 'flex-start',
    flex: 1,
  },
  serifText: {
    margin: 2,
    marginLeft: 0,
  },
  sansSerifText: {
    fontSize: 12,
    textAlign: 'left',
    margin: 2,
    marginLeft: 0,
    fontFamily: "Avant Garde Gothic ITCW01Dm",
  },
});

export default Relay.createContainer(Metadata, {
  initialVariables: {
    artistID: null,
  },

  fragments: {
    show: () => Relay.QL`
      fragment on PartnerShow {
        kind
        name
        exhibition_period
        status
        partner {
          name
        }
        location {
          city
        }
        counts {
          artworks(artist_id: $artistID)
        }
      }
    `
  }
});<|endoftext|>


<commit_before>import { connect } from 'react-redux'
import { Navbar } from 'react-bootstrap'
import PropTypes, { any } from 'prop-types'
import React, { Component } from 'react'

import { accountLinks, getAuth0Config } from '../../util/auth'
import { ComponentContext } from '../../util/contexts'
import { setMobileScreen } from '../../actions/ui'
import AppMenu from '../app/app-menu'
import Icon from '../util/icon'
import LocaleSelector from '../app/locale-selector'
import NavLoginButtonAuth0 from '../../components/user/nav-login-button-auth0'

class MobileNavigationBar extends Component {
  static propTypes = {
    auth0Config: PropTypes.object,
    backScreen: PropTypes.number,
    configLanguages: PropTypes.object,
    defaultMobileTitle: PropTypes.string,
    headerAction: PropTypes.element,
    headerText: PropTypes.element,
    onBackClicked: PropTypes.func,
    setMobileScreen: PropTypes.func,
    showBackButton: PropTypes.bool
  }

  static contextType = ComponentContext

  _backButtonPressed = () => {
    const { backScreen, onBackClicked } = this.props
    if (backScreen) this.props.setMobileScreen(this.props.backScreen)
    else if (typeof onBackClicked === 'function') onBackClicked()
  }

  render() {
    const {
      auth0Config,
      configLanguages,
      defaultMobileTitle,
      headerAction,
      headerText,
      showBackButton
    } = this.props

    return (
      <Navbar className="mobile-navbar-container" fixedTop fluid>
        <Navbar.Header>
          <Navbar.Brand>
            {showBackButton ? (

                <Icon
                  fixedWidth={false}
                  name="arrow-left"
                  onClick={this._backButtonPressed}
                />

            ) : (
              <AppMenu />
            )}
          </Navbar.Brand>
        </Navbar.Header>

          {headerText ? (

{headerText}

          ) : (

{defaultMobileTitle}

          )}

        {headerAction && (

{headerAction}

        )}

          {configLanguages &&
            // Ensure that > 1 valid language is defined
            Object.keys(configLanguages).filter(
              (key) => key !== 'allLanguages' && configLanguages[key].name
            ).length > 1 && (
              <LocaleSelector
                className="locale-selector"
                configLanguages={configLanguages}
              />
            )}
          {/**
           * HACK: Normally, NavLoginButtonAuth0 should be inside a  element,
           * however, in mobile mode, react-bootstrap's  causes the
           * submenus of this component to be displayed full-screen-width,
           * and that behavior is not desired here.
           */}
          {auth0Config && (
            <NavLoginButtonAuth0 id="login-control" links={accountLinks} />
          )}

      </Navbar>
    )
  }
}

// connect to the redux store

const mapStateToProps = (state) => {
  return {
    auth0Config: getAuth0Config(state.otp.config.persistence),
    configLanguages: state.otp.config.language
  }
}

const mapDispatchToProps = {
  setMobileScreen
}

export default connect(mapStateToProps, mapDispatchToProps)(MobileNavigationBar)
<commit_msg>refactor(navigation-bar): remove fa icon<commit_after>import { ArrowLeft } from '@styled-icons/fa-solid/ArrowLeft'
import { connect } from 'react-redux'
import { Navbar } from 'react-bootstrap'
import PropTypes, { any } from 'prop-types'
import React, { Component } from 'react'

import { accountLinks, getAuth0Config } from '../../util/auth'
import { ComponentContext } from '../../util/contexts'
import { setMobileScreen } from '../../actions/ui'
import AppMenu from '../app/app-menu'
import LocaleSelector from '../app/locale-selector'
import NavLoginButtonAuth0 from '../../components/user/nav-login-button-auth0'
import StyledIconWrapper from '../util/styledIcon'

class MobileNavigationBar extends Component {
  static propTypes = {
    auth0Config: PropTypes.object,
    backScreen: PropTypes.number,
    configLanguages: PropTypes.object,
    defaultMobileTitle: PropTypes.string,
    headerAction: PropTypes.element,
    headerText: PropTypes.element,
    onBackClicked: PropTypes.func,
    setMobileScreen: PropTypes.func,
    showBackButton: PropTypes.bool
  }

  static contextType = ComponentContext

  _backButtonPressed = () => {
    const { backScreen, onBackClicked } = this.props
    if (backScreen) this.props.setMobileScreen(this.props.backScreen)
    else if (typeof onBackClicked === 'function') onBackClicked()
  }

  render() {
    const {
      auth0Config,
      configLanguages,
      defaultMobileTitle,
      headerAction,
      headerText,
      showBackButton
    } = this.props

    return (
      <Navbar className="mobile-navbar-container" fixedTop fluid>
        <Navbar.Header>
          <Navbar.Brand>
            {showBackButton ? (

            ) : (
              <AppMenu />
            )}
          </Navbar.Brand>
        </Navbar.Header>

          {headerText ? (

{headerText}

          ) : (

{defaultMobileTitle}

          )}

        {headerAction && (

{headerAction}

        )}

          {configLanguages &&
            // Ensure that > 1 valid language is defined
            Object.keys(configLanguages).filter(
              (key) => key !== 'allLanguages' && configLanguages[key].name
            ).length > 1 && (
              <LocaleSelector
                className="locale-selector"
                configLanguages={configLanguages}
              />
            )}
          {/**
           * HACK: Normally, NavLoginButtonAuth0 should be inside a  element,
           * however, in mobile mode, react-bootstrap's  causes the
           * submenus of this component to be displayed full-screen-width,
           * and that behavior is not desired here.
           */}
          {auth0Config && (
            <NavLoginButtonAuth0 id="login-control" links={accountLinks} />
          )}

      </Navbar>
    )
  }
}

// connect to the redux store

const mapStateToProps = (state) => {
  return {
    auth0Config: getAuth0Config(state.otp.config.persistence),
    configLanguages: state.otp.config.language
  }
}

const mapDispatchToProps = {
  setMobileScreen
}

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


<commit_before>/** @babel */

/**
 * Copyright (c) 2016-present, PlatformIO Plus <contact@pioplus.com>
 * All rights reserved.
 *
 * This source code is licensed under the license found in the LICENSE file in
 * the root directory of this source tree.
 */

import * as config from '../../config';
import * as utils from '../../utils';

import { PEPverToSemver, download, extractTarGz, getCacheDir, getPythonExecutable } from '../helpers';
import BaseStage from './base';
import fs from 'fs-plus';
import path from 'path';
import semver from 'semver';
import tmp from 'tmp';

export default class PlatformIOCoreStage extends BaseStage {

  static UPGRADE_PIOCORE_TIMEOUT =86400 * 3 * 1000; // 3 days

  static pythonVersion = '2.7.13';
  static vitrualenvUrl = 'https://pypi.python.org/packages/d4/0c/9840c08189e030873387a73b90ada981885010dd9aea134d6de30cd24cb8/virtualenv-15.1.0.tar.gz';

  constructor() {
    super(...arguments);
    tmp.setGracefulCleanup();
  }

  get name() {
    return 'PlatformIO Core';
  }

  async whereIsPython() {
    let pythonExecutable = null;
    let buttonIndex = 0;
    do {
      pythonExecutable = await getPythonExecutable();
      if (pythonExecutable) {
        return pythonExecutable;
      }

      if (config.IS_WINDOWS) {
        try {
          return await this.installPythonForWindows();
        } catch (err) {
          console.error(err);
        }
      }

      buttonIndex = atom.confirm({
        message: 'PlatformIO: Can not find Python 2.7 Interpreter',
        detailedMessage: 'PlatformIO Core is written in Python and depends on it. ' +
          'Please install Python 2.7 (PYTHON 3 IS NOT SUPPORTED YET) or ' +
          'if you have it, please choose a directory where "python/python.exe" program is located.',
        buttons: [
          'Install Python 2.7',
          'I have Python 2.7',
          'Try again',
          'Abort PlatformIO IDE Installation'
        ]
      });

      switch (buttonIndex) {
        case 0:
          utils.openUrl('http://docs.platformio.org/page/faq.html#install-python-interpreter');
          break;

        case 1:
          pythonExecutable = await getPythonExecutable(await this.chooseCustomPythonDirs());
          if (pythonExecutable) {
            return pythonExecutable;
          }
          break;
      }

    } while (buttonIndex !== 3);
    return null;
  }

  async installPythonForWindows() {
    // https://www.python.org/ftp/python/2.7.13/python-2.7.13.msi
    // https://www.python.org/ftp/python/2.7.13/python-2.7.13.amd64.msi
    const pythonArch = process.arch === 'x64' ? '.amd64' : '';
    const msiUrl = `https://www.python.org/ftp/python/${PlatformIOCoreStage.pythonVersion}/python-${PlatformIOCoreStage.pythonVersion}${pythonArch}.msi`;
    const targetDir = path.join(config.PIO_HOME_DIR, 'python27');
    const pythonPath = path.join(targetDir, 'python.exe');

    if (!fs.isFileSync(pythonPath)) {
      const msiInstaller = await download(
        msiUrl,
        path.join(getCacheDir(), path.basename(msiUrl))
      );
      const logFile = path.join(getCacheDir(), 'python27msi.log');
      await new Promise((resolve, reject) => {
        utils.runCommand(
          'msiexec.exe',
          ['/i', msiInstaller, '/qn', '/li', logFile, `TARGETDIR=${targetDir}`],
          (code, stdout, stderr) => {
            if (code === 0) {
              return resolve(stdout);
            } else {
              if (fs.isFileSync(logFile)) {
                stderr = fs.readFileSync(logFile).toString();
              }
              return reject(`MSI Python2.7: ${stderr}`);
            }
          },
          {
            spawnOptions: {
              shell: true
            }
          }
        );
      });
      if (!fs.isFileSync(pythonPath)) {
        throw new Error('Could not install Python 2.7 using MSI');
      }
    }

    // append temporary to system environment
    process.env.PATH = [targetDir, path.join(targetDir, 'Scripts'), process.env.PATH].join(path.delimiter);
    process.env.Path = process.env.PATH;

    // install virtualenv
    return new Promise(resolve => {
      utils.runCommand(
        'pip',
        ['install', 'virtualenv'],
        () => resolve(pythonPath)
      );
    });
  }

  chooseCustomPythonDirs() {
    return new Promise((resolve) => {
      atom.pickFolder(paths => {
        resolve(paths);
      });
    });
  }

  cleanVirtualEnvDir() {
    if (fs.isDirectorySync(config.ENV_DIR)) {
      try {
        fs.removeSync(config.ENV_DIR);
      } catch (err) {
        console.error(err);
      }
    }
  }

  isCondaInstalled() {
    return new Promise(resolve => {
      utils.runCommand('conda', ['--version'], code => resolve(code === 0));
    });
  }

  createVirtualenvWithConda() {
    return new Promise((resolve, reject) => {
      utils.runCommand(
        'conda',
        ['create', '--yes', '--quiet', 'python=2', '--prefix', config.ENV_DIR],
        (code, stdout, stderr) => {
          if (code === 0) {
            return resolve(stdout);
          } else {
            return reject(`Conda Virtualenv: ${stderr}`);
          }
        }
      );
    });
  }

  createVirtualenvWithUser(pythonExecutable) {
    return new Promise((resolve, reject) => {
      utils.runCommand(
        'virtualenv',
        ['-p', pythonExecutable, config.ENV_DIR],
        (code, stdout, stderr) => {
          if (code === 0) {
            return resolve(stdout);
          } else {
            return reject(`User's Virtualenv: ${stderr}`);
          }
        }
      );
    });
  }

  createVirtualenvWithDownload(pythonExecutable) {
    return new Promise((resolve, reject) => {
      download(
        PlatformIOCoreStage.vitrualenvUrl,
        path.join(getCacheDir(), 'virtualenv.tar.gz')
      ).then(archivePath => {
        const tmpDir = tmp.dirSync({
          unsafeCleanup: true
        });
        extractTarGz(archivePath, tmpDir.name).then(dstDir => {
          const virtualenvScript = fs.listTreeSync(dstDir).find(
            item => path.basename(item) === 'virtualenv.py');
          if (!virtualenvScript) {
            return reject('Can not find virtualenv.py script');
          }
          utils.runCommand(
            pythonExecutable,
            [virtualenvScript, config.ENV_DIR],
            (code, stdout, stderr) => {
              if (code === 0) {
                return resolve(stdout);
              } else {
                return reject(`Virtualenv Download: ${stderr}`);
              }
            }
          );
        });
      }).catch(err => reject(`Virtualenv Download: ${err}`));
    });
  }

  async installPIOCore() {
    let cmd = 'pip';
    const args = ['install', '--no-cache-dir', '-U'];
    if (atom.config.get('platformio-ide.advanced.useDevelopmentPIOCore') || semver.prerelease(utils.getIDEVersion())) {
      cmd = path.join(config.ENV_BIN_DIR, 'pip');
      args.push('https://github.com/platformio/platformio/archive/develop.zip');
    } else {
      args.push('platformio');
    }
    try {
      await new Promise((resolve, reject) => {
        utils.runCommand(cmd, args, (code, stdout, stderr) => {
          if (code === 0) {
            resolve(stdout);
          } else {
            reject(`PIP: ${stderr}`);
          }
        });
      });
    } catch (err) {
      console.error(err);
      // Old versions of PIP don't support `--no-cache-dir` option
      return new Promise((resolve, reject) => {
        utils.runCommand(
          cmd,
          args.filter(arg => arg !== '--no-cache-dir'),
          (code, stdout, stderr) => {
            if (code === 0) {
              resolve(stdout);
            } else {
              reject(`PIP: ${stderr}`);
            }
          }
        );
      });
    }
  }

  initState() {
    let state = this.state;
    if (!state || !state.hasOwnProperty('pioCoreChecked') || !state.hasOwnProperty('lastIDEVersion')) {
      state = {
        pioCoreChecked: 0,
        lastIDEVersion: null
      };
    }
    return state;
  }

  async autoUpgradePIOCore() {
    const newState = this.initState();
    const now = new Date().getTime();
    if (
      newState.lastIDEVersion !== utils.getIDEVersion()
      || ((now - PlatformIOCoreStage.UPGRADE_PIOCORE_TIMEOUT) > parseInt(newState.pioCoreChecked))
    ) {
      newState.pioCoreChecked = now;
      // PIO Core
      await new Promise(resolve => {
        utils.runPIOCommand(
          ['upgrade'],
          (code, stdout, stderr) => {
            if (code !== 0) {
              console.error(stdout, stderr);
            }
            resolve(true);
          },
          {
            busyTitle: 'Upgrading PIO Core'
          }
        );
      });
      // PIO Core Packages
      await new Promise(resolve => {
        utils.runPIOCommand(
          ['update', '--core-packages'],
          (code, stdout, stderr) => {
            if (code !== 0) {
              console.error(stdout, stderr);
            }
            resolve(true);
          },
          {
            busyTitle: 'Updating PIO Core packages'
          }
        );
      });
    }
    newState.lastIDEVersion = utils.getIDEVersion();
    this.state = newState;
  }

  async check() {
    if (atom.config.get('platformio-ide.useBuiltinPIOCore')) {
      if (!fs.isDirectorySync(config.ENV_BIN_DIR)) {
        throw new Error('Virtual environment is not created');
      }
      if (navigator.onLine) {
        await this.autoUpgradePIOCore();
      }
    }

    const coreVersion = await utils.getCoreVersion();
    if (semver.lt(PEPverToSemver(coreVersion), config.PIO_CORE_MIN_VERSION)) {
      atom.config.set('platformio-ide.useBuiltinPIOCore', true);
      throw new Error('Incompatible PIO Core', coreVersion);
    }

    this.status = BaseStage.STATUS_SUCCESSED;
    console.debug(`Found PIO Core ${coreVersion}`);
    return true;
  }

  async install() {
    if (this.status === BaseStage.STATUS_SUCCESSED) {
      return true;
    }
    if (!atom.config.get('platformio-ide.useBuiltinPIOCore')) {
      this.status = BaseStage.STATUS_SUCCESSED;
      return true;
    }
    this.status = BaseStage.STATUS_INSTALLING;

    this.cleanVirtualEnvDir();

    if (await this.isCondaInstalled()) {
      await this.createVirtualenvWithConda();
    } else {
      const pythonExecutable = await this.whereIsPython();
      if (!pythonExecutable) {
        this.status = BaseStage.STATUS_FAILED;
        throw new Error('Can not find Python Interpreter');
      }
      try {
        await this.createVirtualenvWithUser(pythonExecutable);
      } catch (err) {
        console.error(err);
        await this.createVirtualenvWithDownload(pythonExecutable);
      }
    }

    await this.installPIOCore();

    this.status = BaseStage.STATUS_SUCCESSED;
    return true;
  }

}
<commit_msg>Revert back virtualenv to 14.0.6 // Resolve #276, Resolve #286, Resolve #295, Resolve #340, Resolve #382, Resolve #388, Resolve #391, Resolve #405, Resolve #407, Resolve #411, Resolve #420<commit_after>/** @babel */

/**
 * Copyright (c) 2016-present, PlatformIO Plus <contact@pioplus.com>
 * All rights reserved.
 *
 * This source code is licensed under the license found in the LICENSE file in
 * the root directory of this source tree.
 */

import * as config from '../../config';
import * as utils from '../../utils';

import { PEPverToSemver, download, extractTarGz, getCacheDir, getPythonExecutable } from '../helpers';
import BaseStage from './base';
import fs from 'fs-plus';
import path from 'path';
import semver from 'semver';
import tmp from 'tmp';

export default class PlatformIOCoreStage extends BaseStage {

  static UPGRADE_PIOCORE_TIMEOUT =86400 * 3 * 1000; // 3 days

  static pythonVersion = '2.7.13';
  static vitrualenvUrl = 'https://pypi.python.org/packages/source/v/virtualenv/virtualenv-14.0.6.tar.gz';

  constructor() {
    super(...arguments);
    tmp.setGracefulCleanup();
  }

  get name() {
    return 'PlatformIO Core';
  }

  async whereIsPython() {
    let pythonExecutable = null;
    let buttonIndex = 0;
    do {
      pythonExecutable = await getPythonExecutable();
      if (pythonExecutable) {
        return pythonExecutable;
      }

      if (config.IS_WINDOWS) {
        try {
          return await this.installPythonForWindows();
        } catch (err) {
          console.error(err);
        }
      }

      buttonIndex = atom.confirm({
        message: 'PlatformIO: Can not find Python 2.7 Interpreter',
        detailedMessage: 'PlatformIO Core is written in Python and depends on it. ' +
          'Please install Python 2.7 (PYTHON 3 IS NOT SUPPORTED YET) or ' +
          'if you have it, please choose a directory where "python/python.exe" program is located.',
        buttons: [
          'Install Python 2.7',
          'I have Python 2.7',
          'Try again',
          'Abort PlatformIO IDE Installation'
        ]
      });

      switch (buttonIndex) {
        case 0:
          utils.openUrl('http://docs.platformio.org/page/faq.html#install-python-interpreter');
          break;

        case 1:
          pythonExecutable = await getPythonExecutable(await this.chooseCustomPythonDirs());
          if (pythonExecutable) {
            return pythonExecutable;
          }
          break;
      }

    } while (buttonIndex !== 3);
    return null;
  }

  async installPythonForWindows() {
    // https://www.python.org/ftp/python/2.7.13/python-2.7.13.msi
    // https://www.python.org/ftp/python/2.7.13/python-2.7.13.amd64.msi
    const pythonArch = process.arch === 'x64' ? '.amd64' : '';
    const msiUrl = `https://www.python.org/ftp/python/${PlatformIOCoreStage.pythonVersion}/python-${PlatformIOCoreStage.pythonVersion}${pythonArch}.msi`;
    const targetDir = path.join(config.PIO_HOME_DIR, 'python27');
    const pythonPath = path.join(targetDir, 'python.exe');

    if (!fs.isFileSync(pythonPath)) {
      const msiInstaller = await download(
        msiUrl,
        path.join(getCacheDir(), path.basename(msiUrl))
      );
      const logFile = path.join(getCacheDir(), 'python27msi.log');
      await new Promise((resolve, reject) => {
        utils.runCommand(
          'msiexec.exe',
          ['/i', msiInstaller, '/qn', '/li', logFile, `TARGETDIR=${targetDir}`],
          (code, stdout, stderr) => {
            if (code === 0) {
              return resolve(stdout);
            } else {
              if (fs.isFileSync(logFile)) {
                stderr = fs.readFileSync(logFile).toString();
              }
              return reject(`MSI Python2.7: ${stderr}`);
            }
          },
          {
            spawnOptions: {
              shell: true
            }
          }
        );
      });
      if (!fs.isFileSync(pythonPath)) {
        throw new Error('Could not install Python 2.7 using MSI');
      }
    }

    // append temporary to system environment
    process.env.PATH = [targetDir, path.join(targetDir, 'Scripts'), process.env.PATH].join(path.delimiter);
    process.env.Path = process.env.PATH;

    // install virtualenv
    return new Promise(resolve => {
      utils.runCommand(
        'pip',
        ['install', 'virtualenv'],
        () => resolve(pythonPath)
      );
    });
  }

  chooseCustomPythonDirs() {
    return new Promise((resolve) => {
      atom.pickFolder(paths => {
        resolve(paths);
      });
    });
  }

  cleanVirtualEnvDir() {
    if (fs.isDirectorySync(config.ENV_DIR)) {
      try {
        fs.removeSync(config.ENV_DIR);
      } catch (err) {
        console.error(err);
      }
    }
  }

  isCondaInstalled() {
    return new Promise(resolve => {
      utils.runCommand('conda', ['--version'], code => resolve(code === 0));
    });
  }

  createVirtualenvWithConda() {
    return new Promise((resolve, reject) => {
      utils.runCommand(
        'conda',
        ['create', '--yes', '--quiet', 'python=2', '--prefix', config.ENV_DIR],
        (code, stdout, stderr) => {
          if (code === 0) {
            return resolve(stdout);
          } else {
            return reject(`Conda Virtualenv: ${stderr}`);
          }
        }
      );
    });
  }

  createVirtualenvWithUser(pythonExecutable) {
    return new Promise((resolve, reject) => {
      utils.runCommand(
        'virtualenv',
        ['-p', pythonExecutable, config.ENV_DIR],
        (code, stdout, stderr) => {
          if (code === 0) {
            return resolve(stdout);
          } else {
            return reject(`User's Virtualenv: ${stderr}`);
          }
        }
      );
    });
  }

  createVirtualenvWithDownload(pythonExecutable) {
    return new Promise((resolve, reject) => {
      download(
        PlatformIOCoreStage.vitrualenvUrl,
        path.join(getCacheDir(), 'virtualenv.tar.gz')
      ).then(archivePath => {
        const tmpDir = tmp.dirSync({
          unsafeCleanup: true
        });
        extractTarGz(archivePath, tmpDir.name).then(dstDir => {
          const virtualenvScript = fs.listTreeSync(dstDir).find(
            item => path.basename(item) === 'virtualenv.py');
          if (!virtualenvScript) {
            return reject('Can not find virtualenv.py script');
          }
          utils.runCommand(
            pythonExecutable,
            [virtualenvScript, config.ENV_DIR],
            (code, stdout, stderr) => {
              if (code === 0) {
                return resolve(stdout);
              } else {
                return reject(`Virtualenv Download: ${stderr}`);
              }
            }
          );
        });
      }).catch(err => reject(`Virtualenv Download: ${err}`));
    });
  }

  async installPIOCore() {
    let cmd = 'pip';
    const args = ['install', '--no-cache-dir', '-U'];
    if (atom.config.get('platformio-ide.advanced.useDevelopmentPIOCore') || semver.prerelease(utils.getIDEVersion())) {
      cmd = path.join(config.ENV_BIN_DIR, 'pip');
      args.push('https://github.com/platformio/platformio/archive/develop.zip');
    } else {
      args.push('platformio');
    }
    try {
      await new Promise((resolve, reject) => {
        utils.runCommand(cmd, args, (code, stdout, stderr) => {
          if (code === 0) {
            resolve(stdout);
          } else {
            reject(`PIP: ${stderr}`);
          }
        });
      });
    } catch (err) {
      console.error(err);
      // Old versions of PIP don't support `--no-cache-dir` option
      return new Promise((resolve, reject) => {
        utils.runCommand(
          cmd,
          args.filter(arg => arg !== '--no-cache-dir'),
          (code, stdout, stderr) => {
            if (code === 0) {
              resolve(stdout);
            } else {
              reject(`PIP: ${stderr}`);
            }
          }
        );
      });
    }
  }

  initState() {
    let state = this.state;
    if (!state || !state.hasOwnProperty('pioCoreChecked') || !state.hasOwnProperty('lastIDEVersion')) {
      state = {
        pioCoreChecked: 0,
        lastIDEVersion: null
      };
    }
    return state;
  }

  async autoUpgradePIOCore() {
    const newState = this.initState();
    const now = new Date().getTime();
    if (
      newState.lastIDEVersion !== utils.getIDEVersion()
      || ((now - PlatformIOCoreStage.UPGRADE_PIOCORE_TIMEOUT) > parseInt(newState.pioCoreChecked))
    ) {
      newState.pioCoreChecked = now;
      // PIO Core
      await new Promise(resolve => {
        utils.runPIOCommand(
          ['upgrade'],
          (code, stdout, stderr) => {
            if (code !== 0) {
              console.error(stdout, stderr);
            }
            resolve(true);
          },
          {
            busyTitle: 'Upgrading PIO Core'
          }
        );
      });
      // PIO Core Packages
      await new Promise(resolve => {
        utils.runPIOCommand(
          ['update', '--core-packages'],
          (code, stdout, stderr) => {
            if (code !== 0) {
              console.error(stdout, stderr);
            }
            resolve(true);
          },
          {
            busyTitle: 'Updating PIO Core packages'
          }
        );
      });
    }
    newState.lastIDEVersion = utils.getIDEVersion();
    this.state = newState;
  }

  async check() {
    if (atom.config.get('platformio-ide.useBuiltinPIOCore')) {
      if (!fs.isDirectorySync(config.ENV_BIN_DIR)) {
        throw new Error('Virtual environment is not created');
      }
      if (navigator.onLine) {
        await this.autoUpgradePIOCore();
      }
    }

    const coreVersion = await utils.getCoreVersion();
    if (semver.lt(PEPverToSemver(coreVersion), config.PIO_CORE_MIN_VERSION)) {
      atom.config.set('platformio-ide.useBuiltinPIOCore', true);
      throw new Error('Incompatible PIO Core', coreVersion);
    }

    this.status = BaseStage.STATUS_SUCCESSED;
    console.debug(`Found PIO Core ${coreVersion}`);
    return true;
  }

  async install() {
    if (this.status === BaseStage.STATUS_SUCCESSED) {
      return true;
    }
    if (!atom.config.get('platformio-ide.useBuiltinPIOCore')) {
      this.status = BaseStage.STATUS_SUCCESSED;
      return true;
    }
    this.status = BaseStage.STATUS_INSTALLING;

    this.cleanVirtualEnvDir();

    if (await this.isCondaInstalled()) {
      await this.createVirtualenvWithConda();
    } else {
      const pythonExecutable = await this.whereIsPython();
      if (!pythonExecutable) {
        this.status = BaseStage.STATUS_FAILED;
        throw new Error('Can not find Python Interpreter');
      }
      try {
        await this.createVirtualenvWithUser(pythonExecutable);
      } catch (err) {
        console.error(err);
        await this.createVirtualenvWithDownload(pythonExecutable);
      }
    }

    await this.installPIOCore();

    this.status = BaseStage.STATUS_SUCCESSED;
    return true;
  }

}
<|endoftext|>


<commit_before>const {join} = require('path')

function getEntryOutputPathFromStats (stats, options = {}) {
  if (typeof options === 'string') {
    options = {entryName: options}
  }

  let {
    entryName,
    outputPath
  } = options

  let entryFiles
  let entryOutputPath

  if (stats.compilation) {
    const {entrypoints} = stats.compilation
    const entry = entryName ? entrypoints[entryName] : entrypoints.main || entrypoints.index

    if (!outputPath) {
      outputPath = stats.compilation.outputOptions.path
    }

    if (entry) {
      entryChunk = entry.chunks.find((chunk) => chunk.name === entry.name)

      if (entryChunk) {
        entryFiles = entryChunk.files
      }
    }
  }

  if (!entryFiles && stats.chunks && stats.entrypoints) {
    const {
      chunks,
      entrypoints
    } = stats

    if (!entryName) {
      entryName = entrypoints.main ? 'main' : entrypoints.index ? 'index' : undefined
    }

    const entry = entrypoints[entryName]

    if (entry) {
      entryFiles = entry.chunks
        .map((chunkId) => chunks.find((chunk) => chunk.id === chunkId))
        .filter((chunk) => chunk && chunk.names && ~chunk.names.indexOf(entryName))
        .reduce((acc, chunk) => acc.concat(chunk.files || []), [])
    }
  }

  if (!entryFiles && stats.assetsByChunkName && stats.chunks) {
    const {assetsByChunkName} = stats

    entryFiles = entryName ? assetsByChunkName[entryName] : assetsByChunkName.main || assetsByChunkName.index
  }

  if (!entryFiles && stats.assets) {
    const {assets} = stats

    entryFiles = []
      .concat(entryName || ['main', 'index'])
      .map((chunkName) => assets.filter((asset) => ~asset.chunkNames.indexOf(chunkName)))
      .reduce((acc, value) => value.map((asset) => asset.name), [])
  }

  if (entryFiles) {
    entryOutputPath = entryFiles.find((file) => file.endsWith('.js'))
  }

  if (entryOutputPath && outputPath) {
    entryOutputPath = join(outputPath, entryOutputPath)
  }

  return entryOutputPath
}

module.exports = getEntryOutputPathFromStats
<commit_msg>getEntryOutputPathFromStats: add 'server' as possible entry name (temporary fix)<commit_after>const {join} = require('path')

function getEntryOutputPathFromStats (stats, options = {}) {
  if (typeof options === 'string') {
    options = {entryName: options}
  }

  let {
    entryName,
    outputPath
  } = options

  let entryFiles
  let entryOutputPath

  if (stats.compilation) {
    const {entrypoints} = stats.compilation
    const entry = entryName ? entrypoints[entryName] : entrypoints.main || entrypoints.index || entrypoints.server

    if (!outputPath) {
      outputPath = stats.compilation.outputOptions.path
    }

    if (entry) {
      entryChunk = entry.chunks.find((chunk) => chunk.name === entry.name)

      if (entryChunk) {
        entryFiles = entryChunk.files
      }
    }
  }

  if (!entryFiles && stats.chunks && stats.entrypoints) {
    const {
      chunks,
      entrypoints
    } = stats

    if (!entryName) {
      entryName = entrypoints.main ? 'main' : entrypoints.index ? 'index' : entrypoints.server ? 'server' : undefined
    }

    const entry = entrypoints[entryName]

    if (entry) {
      entryFiles = entry.chunks
        .map((chunkId) => chunks.find((chunk) => chunk.id === chunkId))
        .filter((chunk) => chunk && chunk.names && ~chunk.names.indexOf(entryName))
        .reduce((acc, chunk) => acc.concat(chunk.files || []), [])
    }
  }

  if (!entryFiles && stats.assetsByChunkName && stats.chunks) {
    const {assetsByChunkName} = stats

    entryFiles = entryName ? assetsByChunkName[entryName] : assetsByChunkName.main || assetsByChunkName.index || assetsByChunkName.server
  }

  if (!entryFiles && stats.assets) {
    const {assets} = stats

    entryFiles = []
      .concat(entryName || ['main', 'index', 'server'])
      .map((chunkName) => assets.filter((asset) => ~asset.chunkNames.indexOf(chunkName)))
      .reduce((acc, value) => value.map((asset) => asset.name), [])
  }

  if (entryFiles) {
    entryOutputPath = entryFiles.find((file) => file.endsWith('.js'))
  }

  if (entryOutputPath && outputPath) {
    entryOutputPath = join(outputPath, entryOutputPath)
  }

  return entryOutputPath
}

module.exports = getEntryOutputPathFromStats
<|endoftext|>


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

var app = express();

// http://localhost:8080/price?S=100&K=102&U=1.07&R=1.01&expiration=1
app.get('/price', function(req, res) {

    var s = +req.query.S,          // initial price
        k = +req.query.K,          // constractuel price
        r = +req.query.R,          // probability that the price up or down in each node
        u = +req.query.U,          // coef used to determinate the next value of S for the two sub-nodes
        n = +req.query.expiration; // number of unit time (month for example) which define the tree depth

    console.log(req.query);

    var values= "S="+s+" K="+k+" R="+r+" U="+u+" N="+n;
    console.log(values);

    if (!s || !k || !r || !n || !u){
        res.send("S, K, R, U, or expiration is undefined or is zero
"+values);
    } else {

        var d = 1 / u;              // coef when the price down
        var q = (r - d) / (u - d);

        console.log('d='+d+' q='+q);

        var result = 1/Math.pow(r, n) * recusiveSum(n, 0, q, s, u);
        var roundedResult = Math.round(result * 100) / 100;
        console.log(roundedResult)

        res.end(roundedResult);
    }
});

var recusiveSum = function (n, k, q, s, u, d){
    var result =0,
        r = binom(n, k) * Math.pow(q,n-k) * Math.pow(1-q,k) * (s * Math.pow(u, n-k) * Math.pow(d, k));
    if (k == n){
        result = Math.max(0, s - r)
    } else{
        result = r + recusiveSum(n, k+1, q, s, u, d);
    }
    console.log("When k="+k+" result is equal to "+r);
    return result;
};

// binomial coef calculation
var binom = function (n, k) {
        var coeff = 1;
        for (var i = n-k+1; i <= n; i++) coeff *= i;
        for (var i = 1;     i <= k; i++) coeff /= i;
        return coeff;
};

app.listen(8080);
console.log('Listening on port 8080...');<commit_msg>remove one console log<commit_after>var express = require('express');

var app = express();

// http://localhost:8080/price?S=100&K=102&U=1.07&R=1.01&expiration=1
app.get('/price', function(req, res) {

    var s = +req.query.S,          // initial price
        k = +req.query.K,          // constractuel price
        r = +req.query.R,          // probability that the price up or down in each node
        u = +req.query.U,          // coef used to determinate the next value of S for the two sub-nodes
        n = +req.query.expiration; // number of unit time (month for example) which define the tree depth

    var values= "S="+s+" K="+k+" R="+r+" U="+u+" N="+n;
    console.log(values);

    if (!s || !k || !r || !n || !u){
        res.send("S, K, R, U, or expiration is undefined or is zero
"+values);
    } else {

        var d = 1 / u;              // coef when the price down
        var q = (r - d) / (u - d);

        console.log('d='+d+' q='+q);

        var result = 1/Math.pow(r, n) * recusiveSum(n, 0, q, s, u);
        var roundedResult = Math.round(result * 100) / 100;
        console.log(roundedResult)

        res.end(roundedResult);
    }
});

var recusiveSum = function (n, k, q, s, u, d){
    var result =0,
        r = binom(n, k) * Math.pow(q,n-k) * Math.pow(1-q,k) * (s * Math.pow(u, n-k) * Math.pow(d, k));
    if (k == n){
        result = Math.max(0, s - r)
    } else{
        result = r + recusiveSum(n, k+1, q, s, u, d);
    }
    console.log("When k="+k+" result is equal to "+r);
    return result;
};

// binomial coef calculation
var binom = function (n, k) {
        var coeff = 1;
        for (var i = n-k+1; i <= n; i++) coeff *= i;
        for (var i = 1;     i <= k; i++) coeff /= i;
        return coeff;
};

app.listen(8080);
console.log('Listening on port 8080...');<|endoftext|>


<commit_before>'use strict';

// (un)Register process interruption signals(SIGINT, SIGTERM, process.kill()) handlers.
//
// When the process interrupted("CTR+C") all the registered handlers are being invoked via `capture-exit`.
// The process finishes after the last interruption handler is settled.

let exit = require('capture-exit');

let windowsCtrlCTrap;
let handlers = [];

module.exports = {
  /**
   * Add process interruption handler
   *
   * When the first handler is added then automatically
   * sets up process interruption signals listeners
   *
   * @private
   * @method addHandler
   * @param {function} cb   Callback to be called when process interruption fired
   */
  addHandler(cb) {
    let index = handlers.indexOf(cb);
    if (index > -1) { return; }

    if (handlers.length === 0) {
      setupSignalsTrap();
    }

    handlers.push(cb);
    exit.onExit(cb);
  },

  /**
   * Remove process interruption handler
   *
   * If there are no remaining handlers after removal
   * then clean up all the process interruption signal listeners
   *
   * @private
   * @method removeHandler
   * @param {function} cb   Callback to be removed
   */
  removeHandler(cb) {
    let index = handlers.indexOf(cb);
    if (index < 0) { return; }

    handlers.splice(index, 1);
    exit.offExit(cb);

    if (handlers.length === 0) {
      teardownSignalsTrap();
    }
  },

  /**
   * Tears down all the handlers and cleans up all signal listeners
   *
   * @private
   * @method teardown
   */
  teardown() {
    while (handlers.length > 0) {
      this.removeHandler(handlers[0]);
    }
  },
};

/**
 * Sets up listeners for interruption signals
 *
 * When one of these signals is caught than raise process.exit()
 * which enforces `capture-exit` to run registered interruption handlers
 *
 * @method setupSignalsTrap
 */
function setupSignalsTrap() {
  process.on('SIGINT', _exit);
  process.on('SIGTERM', _exit);
  process.on('message', onMessage);
  if (/^win/.test(process.platform)) {
    trapWindowsSignals();
  }

  exit.captureExit();
}

/**
 * Removes interruption signal listeners and tears down capture-exit
 *
 * @method teardownSignalsTrap
 */
function teardownSignalsTrap() {
  process.removeListener('SIGINT', _exit);
  process.removeListener('SIGTERM', _exit);
  process.removeListener('message', onMessage);
  if (/^win/.test(process.platform)) {
    cleanupWindowsSignals();
  }

  exit.releaseExit();
}

/**
 * Supresses "Terminate batch job (Y/N)" confirmation on Windows
 *
 * @method trapWindowsSignals
 */
function trapWindowsSignals() {
  // This is required to capture Ctrl + C on Windows
  if (process.stdin && process.stdin.isTTY) {
    process.stdin.setRawMode(true);
    windowsCtrlCTrap = function(data) {
      if (data.length === 1 && data[0] === 0x03) {
        process.emit('SIGINT');
      }
    };
    process.stdin.on('data', windowsCtrlCTrap);
  }
}

function cleanupWindowsSignals() {
  if (windowsCtrlCTrap && process.stdin.removeListener) {
    process.stdin.removeListener('data', windowsCtrlCTrap);
  }
}

/**
 * Handles the `message` event on the `process`.
 *
 * Calls `process.exit` if the `kill` property on the `message` is set.
 *
 * @method onMessage
 */
function onMessage(message) {
  if (message.kill) {
    _exit();
  }
}

function _exit() {
  process.exit();
}
<commit_msg>Auto merge of #6799 - rwjblue:refactor-capture-exit-usage, r=rwjblue<commit_after>'use strict';

// (un)Register process interruption signals(SIGINT, SIGTERM, process.kill()) handlers.
//
// When the process interrupted("CTR+C") all the registered handlers are being invoked via `capture-exit`.
// The process finishes after the last interruption handler is settled.

let exit = require('capture-exit');
exit.captureExit();

let windowsCtrlCTrap;
let handlers = [];

module.exports = {
  /**
   * Add process interruption handler
   *
   * When the first handler is added then automatically
   * sets up process interruption signals listeners
   *
   * @private
   * @method addHandler
   * @param {function} cb   Callback to be called when process interruption fired
   */
  addHandler(cb) {
    let index = handlers.indexOf(cb);
    if (index > -1) { return; }

    if (handlers.length === 0) {
      setupSignalsTrap();
    }

    handlers.push(cb);
    exit.onExit(cb);
  },

  /**
   * Remove process interruption handler
   *
   * If there are no remaining handlers after removal
   * then clean up all the process interruption signal listeners
   *
   * @private
   * @method removeHandler
   * @param {function} cb   Callback to be removed
   */
  removeHandler(cb) {
    let index = handlers.indexOf(cb);
    if (index < 0) { return; }

    handlers.splice(index, 1);
    exit.offExit(cb);

    if (handlers.length === 0) {
      teardownSignalsTrap();
    }
  },

  /**
   * Tears down all the handlers and cleans up all signal listeners
   *
   * @private
   * @method teardown
   */
  teardown() {
    while (handlers.length > 0) {
      this.removeHandler(handlers[0]);
    }
  },
};

/**
 * Sets up listeners for interruption signals
 *
 * When one of these signals is caught than raise process.exit()
 * which enforces `capture-exit` to run registered interruption handlers
 *
 * @method setupSignalsTrap
 */
function setupSignalsTrap() {
  process.on('SIGINT', _exit);
  process.on('SIGTERM', _exit);
  process.on('message', onMessage);
  if (/^win/.test(process.platform)) {
    trapWindowsSignals();
  }
}

/**
 * Removes interruption signal listeners and tears down capture-exit
 *
 * @method teardownSignalsTrap
 */
function teardownSignalsTrap() {
  process.removeListener('SIGINT', _exit);
  process.removeListener('SIGTERM', _exit);
  process.removeListener('message', onMessage);
  if (/^win/.test(process.platform)) {
    cleanupWindowsSignals();
  }
}

/**
 * Supresses "Terminate batch job (Y/N)" confirmation on Windows
 *
 * @method trapWindowsSignals
 */
function trapWindowsSignals() {
  // This is required to capture Ctrl + C on Windows
  if (process.stdin && process.stdin.isTTY) {
    process.stdin.setRawMode(true);
    windowsCtrlCTrap = function(data) {
      if (data.length === 1 && data[0] === 0x03) {
        process.emit('SIGINT');
      }
    };
    process.stdin.on('data', windowsCtrlCTrap);
  }
}

function cleanupWindowsSignals() {
  if (windowsCtrlCTrap && process.stdin.removeListener) {
    process.stdin.removeListener('data', windowsCtrlCTrap);
  }
}

/**
 * Handles the `message` event on the `process`.
 *
 * Calls `process.exit` if the `kill` property on the `message` is set.
 *
 * @method onMessage
 */
function onMessage(message) {
  if (message.kill) {
    _exit();
  }
}

function _exit() {
  process.exit();
}
<|endoftext|>


<commit_before>
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
class Normalizer {
  constructor (datasets) {
    this.datasets = datasets; // one or more dicom-like object instances
    this.dataset = undefined; // a normalized multiframe dicom object instance
  }

  static consistentSOPClass(datasets) {
    // return sopClass if all exist and match, otherwise undefined
    let sopClass;
    datasets.forEach(function(dataset) {
      if (!dataset.SOPClass) {
        return(undefined);
      }
      if (!sopClass) {
       sopClass = dataset.SOPClass;
      }
      if (dataset.SOPClass != sopClass) {
        console.error('inconsistent sopClasses: ', dataset.SOPClass, sopClass);
        return(undefined);
      }
    });
    return(sopClass);
  }

  static sopClassMap() {
    return ({
      "CTImage" : CTImageNormalizer,
      "MRImage" : MRImageNormalizer,
      "EnhancedMRImage" : EnhancedMRImageNormalizer,
      "EnhancedUSVolume" : EnhancedUSVolumeNormalizer,
      "PETImage" : PETImageNormalizer,
      "PositronEmissionTomographyImage" : PETImageNormalizer,
      "Segmentation" : SEGImageNormalizer,
    });
  }

  static isMultiframe(ds=this.dataset) {
    return ([
      "EnhancedMRImage",
      "EnhancedCTImage",
      "EnhancedUSImage",
      "EnhancedPETImage",
      "Segmentation",
    ].indexOf(ds.SOPClass) != -1);
  }

  normalize() {
    return("No normalization defined");
  }

  static normalizeToDataset(datasets) {
    let sopClass = Normalizer.consistentSOPClass(datasets);
    let normalizerClass = Normalizer.sopClassMap()[sopClass];
    if (!normalizerClass) {
      console.error('no normalizerClass for ', sopClass);
      return(undefined);
    }
    let normalizer = new normalizerClass(datasets);
    normalizer.normalize();
    return(normalizer.dataset);
  }
}

class ImageNormalizer extends Normalizer {
  normalize() {
    this.convertToMultiframe();
    this.normalizeMultiframe();
  }

  convertToMultiframe() {
    if (this.datasets.length == 1 && Normalizer.isMultiframe(this.datasets[0])) {
      // already a multiframe, so just use it
      this.dataset = this.datasets[0];
      return;
    }
    this.derivation = new DerivedImage(this.datasets);
    this.dataset = this.derivation.dataset;
    let ds = this.dataset;
    // create a new multiframe from the source datasets
    // fill in only those elements required to make a valid image
    // for volumetric processing
    let referenceDataset = this.datasets[0];
    ds.NumberOfFrames = this.datasets.length;

    // TODO: develop sets of elements to copy over in loops
    ds.SOPClass = referenceDataset.SOPClass;
    ds.Rows = referenceDataset.Rows;
    ds.Columns = referenceDataset.Columns;
    ds.BitsAllocated = referenceDataset.BitsAllocated;
    ds.PixelRepresentation = referenceDataset.PixelRepresentation;
    ds.RescaleSlope = referenceDataset.RescaleSlope || "1";
    ds.RescaleIntercept = referenceDataset.RescaleIntercept || "0";
    //ds.BurnedInAnnotation = referenceDataset.BurnedInAnnotation || "YES";

    // sort
    // https://github.com/pieper/Slicer3/blob/master/Base/GUI/Tcl/LoadVolume.tcl
    // TODO: add spacing checks:
    // https://github.com/Slicer/Slicer/blob/master/Modules/Scripted/DICOMPlugins/DICOMScalarVolumePlugin.py#L228-L250
    // TODO: put this information into the Shared and PerFrame functional groups
    let referencePosition = vec3.create();
    referencePosition.set(referenceDataset.ImagePositionPatient);
    let rowVector = vec3.create();
    rowVector.set(referenceDataset.ImageOrientationPatient.slice(0,3));
    let columnVector = vec3.create();
    columnVector.set(referenceDataset.ImageOrientationPatient.slice(3,6));
    let scanAxis = vec3.create();
    vec3.cross(scanAxis,rowVector,columnVector);
    let distanceDatasetPairs = [];
    this.datasets.forEach(function(dataset) {
      let position = vec3.create();
      position.set(dataset.ImagePositionPatient);
      let positionVector = vec3.create();
      vec3.subtract(positionVector, position, referencePosition);
      let distance = vec3.dot(positionVector, scanAxis);
      distanceDatasetPairs.push([distance, dataset]);
    });
    distanceDatasetPairs.sort(function(a,b) {
      return (b[0]-a[0]);
    });

    // assign array buffers
    if (ds.BitsAllocated != 16) {
      console.error('Only works with 16 bit data, not ' + String(dataset.BitsAllocated));
    }
    if (referenceDataset._vrMap && referenceDataset._vrMap.PixelData) {
      console.warn('No vr map given for pixel data, using OW');
      ds._vrMap = {'PixelData': 'OW'}
    } else {
      ds._vrMap = {'PixelData': referenceDataset._vrMap.PixelData}
    }
    let frameSize = referenceDataset.PixelData.byteLength;
    ds.PixelData = new ArrayBuffer(ds.NumberOfFrames * frameSize);
    let frame = 0;
    distanceDatasetPairs.forEach(function(pair) {
      let [distance, dataset] = pair;
      let pixels = new Uint16Array(dataset.PixelData);
      let frameView = new Uint16Array(ds.PixelData, frame * frameSize, frameSize/2);
      frameView.set(pixels);
      frame++;
    });

    if (ds.NumberOfFrames < 2) {
      // TODO
      console.error('Cannot populate shared groups uniquely without multiple frames');
    }
    let [distance0, dataset0]  = distanceDatasetPairs[0];
    let [distance1, dataset1] = distanceDatasetPairs[1];

    //
    // make the functional groups
    //

    // shared

    ds.SharedFunctionalGroups = {
      PlaneOrientation : {
        ImageOrientationPatient : dataset0.ImageOrientationPatient,
      },
      PixelMeasures : {
        PixelSpacing : dataset0.PixelSpacing,
        SpacingBetweenSlices : Math.abs(distance1 - distance0),
      },
    };

    // per-frame

    ds.PerFrameFunctionalGroups = [];
    distanceDatasetPairs.forEach(function(pair) {
      ds.PerFrameFunctionalGroups.push({
        PlanePosition : {
          ImagePositionPatient: pair[1].ImagePositionPatient,
        },
      });
    });

    ds.ReferencedSeries = {
      SeriesInstanceUID : dataset0.SeriesInstanceUID,
      ReferencedInstance : new Array(this.datasets.length),
    }

    // copy over each datasets window/level into the per-frame groups
    // and set the referenced series uid
    let datasetIndex = 0;
    this.datasets.forEach(function(dataset) {
      ds.PerFrameFunctionalGroups[datasetIndex].FrameVOILUT = {
        WindowCenter: dataset.WindowCenter,
        WindowWidth: dataset.WindowWidth,
      };
      ds.ReferencedSeries.ReferencedInstance[datasetIndex] = {
        ReferencedSOPClass: dataset.SOPClass,
        ReferencedSOPInstanceUID: dataset.SOPInstanceUID,
      }
      datasetIndex++;
    });

    let dimensionUID = DicomMetaDictionary.uid();
    this.dataset.DimensionOrganization = {
      DimensionOrganizationUID : dimensionUID
    };
    this.dataset.DimensionIndex = [
      {
        DimensionOrganizationUID : dimensionUID,
        DimensionIndexPointer : 2097202,
        FunctionalGroupPointer : 2134291, // PlanePositionSequence
        DimensionDescriptionLabel : "ImagePositionPatient"
      },
    ];
  }

  normalizeMultiframe() {
    let ds = this.dataset;
    if (!ds.NumberOfFrames) {
      ds.NumberOfFrames = 1;
    }
    if (!ds.PixelRepresentation) {
      // Required tag: guess signed
      ds.PixelRepresentation = 1;
    }
    if (!ds.StudyID || ds.StudyID == "") {
      // Required tag: fill in if needed
      ds.StudyID = "No Study ID";
    }

    let validLateralities = ["R", "L"];
    if (validLateralities.indexOf(ds.Laterality) == -1) {
      delete(ds.Laterality);
    }

    if (!ds.PresentationLUTShape) {
      ds.PresentationLUTShape = "IDENTITY";
    }

    if (!ds.SharedFunctionalGroups) {
      console.error('Can only process multiframe data with SharedFunctionalGroups');
    }

    if (ds.BodyPartExamined == "PROSTATE") {
      ds.SharedFunctionalGroups.FrameAnatomy = {
        AnatomicRegion: {
          CodeValue: "T-9200B",
          CodingSchemeDesignator: "SRT",
          CodeMeaning: "Prostate",
        },
        FrameLaterality: "U",
      };
    }

    let rescaleIntercept = ds.RescaleIntercept || 0.;
    let rescaleSlope = ds.RescaleSlope || 1.;
    ds.SharedFunctionalGroups.PixelValueTransformation = {
      RescaleIntercept: rescaleIntercept,
      RescaleSlope: rescaleSlope,
      RescaleType: "US",
    };

    let frameNumber = 1;
    this.datasets.forEach(dataset=>{
      let frameTime = dataset.AcquisitionDate + dataset.AcquisitionTime;
      ds.PerFrameFunctionalGroups[frameNumber-1].FrameContent = {
        FrameAcquisitionDateTime: frameTime,
        FrameReferenceDateTime: frameTime,
        FrameAcquisitionDuration: 0,
        FrameAcquisitionDuration: 0,
        StackID: 1,
        InStackPositionNumber: frameNumber,
        DimensionIndexValues: frameNumber,
      };
      frameNumber++;
    });

    //
    // TODO: convert this to shared functional group not top level element
    //
    if (ds.WindowCenter && ds.WindowWidth) {
      // if they exist as single values, make them lists for consistency
      if (!Array.isArray(ds.WindowCenter)) {
        ds.WindowCenter = [ds.WindowCenter];
      }
      if (!Array.isArray(ds.WindowWidth)) {
        ds.WindowWidth = [ds.WindowWidth];
      }
    }
    if (!ds.WindowCenter || !ds.WindowWidth) {
      // if they don't exist, make them empty lists and try to initialize them
      ds.WindowCenter = []; // both must exist and be the same length
      ds.WindowWidth = [];
      // provide a volume-level window/level guess (mean of per-frame)
      if (ds.PerFrameFunctionalGroups) {
        let wcww = {center: 0, width: 0, count: 0};
        ds.PerFrameFunctionalGroups.forEach(function(functionalGroup) {
          if (functionalGroup.FrameVOILUT) {
            let wc = functionalGroup.FrameVOILUT.WindowCenter;
            let ww = functionalGroup.FrameVOILUT.WindowWidth;
            if (functionalGroup.FrameVOILUT && wc && ww) {
              if (Array.isArray(wc)) {
                wc = wc[0];
              }
              if (Array.isArray(ww)) {
                ww = ww[0];
              }
              wcww.center += Number(wc);
              wcww.width += Number(ww);
              wcww.count++;
            }
          }
        });
        if (wcww.count > 0) {
          ds.WindowCenter.push(String(wcww.center / wcww.count));
          ds.WindowWidth.push(String(wcww.width / wcww.count));
        }
      }
    }
    // last gasp, pick an arbitrary default
    if (ds.WindowCenter.length == 0) { ds.WindowCenter = [300] }
    if (ds.WindowWidth.length == 0) { ds.WindowWidth = [500] }
  }
}

class MRImageNormalizer extends ImageNormalizer {
  normalize() {
    super.normalize();
    // TODO: provide option at export to swap in LegacyConverted UID
    //this.dataset.SOPClass = "LegacyConvertedEnhancedMRImage";
    this.dataset.SOPClass = "EnhancedMRImage";
  }

  normalizeMultiframe() {
    super.normalizeMultiframe();
    let ds = this.dataset;

    if (!ds.ImageType
          || !ds.ImageType.constructor
          || ds.ImageType.constructor.name != "Array"
          || ds.ImageType.length != 4) {
      ds.ImageType = ["ORIGINAL", "PRIMARY", "OTHER", "NONE",];
    }

    ds.SharedFunctionalGroups.MRImageFrameType = {
      FrameType: ds.ImageType,
      PixelPresentation: "MONOCHROME",
      VolumetricProperties: "VOLUME",
      VolumeBasedCalculationTechnique: "NONE",
      ComplexImageComponent: "MAGNITUDE",
      AcquisitionContrast: "UNKNOWN",
    };
  }
}

class EnhancedMRImageNormalizer extends ImageNormalizer {
  normalize() {
    super.normalize();
  }
}

class CTImageNormalizer extends ImageNormalizer {
  normalize() {
    super.normalize();
    // TODO: provide option at export to swap in LegacyConverted UID
    //this.dataset.SOPClass = "LegacyConvertedEnhancedCTImage";
    this.dataset.SOPClass = "EnhancedCTImage";
  }
}

class PETImageNormalizer extends ImageNormalizer {
  normalize() {
    super.normalize();
    // TODO: provide option at export to swap in LegacyConverted UID
    //this.dataset.SOPClass = "LegacyConvertedEnhancedPETImage";
    this.dataset.SOPClass = "EnhancedPETImage";
  }
}

class SEGImageNormalizer extends ImageNormalizer {
  normalize() {
    super.normalize();
  }
}

class EnhancedUSVolumeNormalizer extends ImageNormalizer {
  normalize() {
    super.normalize();
  }
}

<commit_msg>Don't allow normalizing when information is missing<commit_after>
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
class Normalizer {
  constructor (datasets) {
    this.datasets = datasets; // one or more dicom-like object instances
    this.dataset = undefined; // a normalized multiframe dicom object instance
  }

  static consistentSOPClass(datasets) {
    // return sopClass if all exist and match, otherwise undefined
    let sopClass;
    datasets.forEach(function(dataset) {
      if (!dataset.SOPClass) {
        return(undefined);
      }
      if (!sopClass) {
       sopClass = dataset.SOPClass;
      }
      if (dataset.SOPClass != sopClass) {
        console.error('inconsistent sopClasses: ', dataset.SOPClass, sopClass);
        return(undefined);
      }
    });
    return(sopClass);
  }

  static sopClassMap() {
    return ({
      "CTImage" : CTImageNormalizer,
      "MRImage" : MRImageNormalizer,
      "EnhancedMRImage" : EnhancedMRImageNormalizer,
      "EnhancedUSVolume" : EnhancedUSVolumeNormalizer,
      "PETImage" : PETImageNormalizer,
      "PositronEmissionTomographyImage" : PETImageNormalizer,
      "Segmentation" : SEGImageNormalizer,
    });
  }

  static isMultiframe(ds=this.dataset) {
    return ([
      "EnhancedMRImage",
      "EnhancedCTImage",
      "EnhancedUSImage",
      "EnhancedPETImage",
      "Segmentation",
    ].indexOf(ds.SOPClass) != -1);
  }

  normalize() {
    return("No normalization defined");
  }

  static normalizeToDataset(datasets) {
    let sopClass = Normalizer.consistentSOPClass(datasets);
    let normalizerClass = Normalizer.sopClassMap()[sopClass];
    if (!normalizerClass) {
      console.error('no normalizerClass for ', sopClass);
      return(undefined);
    }
    let normalizer = new normalizerClass(datasets);
    normalizer.normalize();
    return(normalizer.dataset);
  }
}

class ImageNormalizer extends Normalizer {
  normalize() {
    this.convertToMultiframe();
    this.normalizeMultiframe();
  }

  convertToMultiframe() {
    if (this.datasets.length == 1 && Normalizer.isMultiframe(this.datasets[0])) {
      // already a multiframe, so just use it
      this.dataset = this.datasets[0];
      return;
    }
    this.derivation = new DerivedImage(this.datasets);
    this.dataset = this.derivation.dataset;
    let ds = this.dataset;
    // create a new multiframe from the source datasets
    // fill in only those elements required to make a valid image
    // for volumetric processing
    let referenceDataset = this.datasets[0];
    ds.NumberOfFrames = this.datasets.length;

    // TODO: develop sets of elements to copy over in loops
    ds.SOPClass = referenceDataset.SOPClass;
    ds.Rows = referenceDataset.Rows;
    ds.Columns = referenceDataset.Columns;
    ds.BitsAllocated = referenceDataset.BitsAllocated;
    ds.PixelRepresentation = referenceDataset.PixelRepresentation;
    ds.RescaleSlope = referenceDataset.RescaleSlope || "1";
    ds.RescaleIntercept = referenceDataset.RescaleIntercept || "0";
    //ds.BurnedInAnnotation = referenceDataset.BurnedInAnnotation || "YES";

    // sort
    // https://github.com/pieper/Slicer3/blob/master/Base/GUI/Tcl/LoadVolume.tcl
    // TODO: add spacing checks:
    // https://github.com/Slicer/Slicer/blob/master/Modules/Scripted/DICOMPlugins/DICOMScalarVolumePlugin.py#L228-L250
    // TODO: put this information into the Shared and PerFrame functional groups
    let referencePosition = vec3.create();
    referencePosition.set(referenceDataset.ImagePositionPatient);
    let rowVector = vec3.create();
    rowVector.set(referenceDataset.ImageOrientationPatient.slice(0,3));
    let columnVector = vec3.create();
    columnVector.set(referenceDataset.ImageOrientationPatient.slice(3,6));
    let scanAxis = vec3.create();
    vec3.cross(scanAxis,rowVector,columnVector);
    let distanceDatasetPairs = [];
    this.datasets.forEach(function(dataset) {
      let position = vec3.create();
      position.set(dataset.ImagePositionPatient);
      let positionVector = vec3.create();
      vec3.subtract(positionVector, position, referencePosition);
      let distance = vec3.dot(positionVector, scanAxis);
      distanceDatasetPairs.push([distance, dataset]);
    });
    distanceDatasetPairs.sort(function(a,b) {
      return (b[0]-a[0]);
    });

    // assign array buffers
    if (ds.BitsAllocated != 16) {
      console.error('Only works with 16 bit data, not ' + String(dataset.BitsAllocated));
    }
    if (referenceDataset._vrMap && referenceDataset._vrMap.PixelData) {
      console.warn('No vr map given for pixel data, using OW');
      ds._vrMap = {'PixelData': 'OW'}
    } else {
      ds._vrMap = {'PixelData': referenceDataset._vrMap.PixelData}
    }
    let frameSize = referenceDataset.PixelData.byteLength;
    ds.PixelData = new ArrayBuffer(ds.NumberOfFrames * frameSize);
    let frame = 0;
    distanceDatasetPairs.forEach(function(pair) {
      let [distance, dataset] = pair;
      let pixels = new Uint16Array(dataset.PixelData);
      let frameView = new Uint16Array(ds.PixelData, frame * frameSize, frameSize/2);
      frameView.set(pixels);
      frame++;
    });

    if (ds.NumberOfFrames < 2) {
      // TODO
      console.error('Cannot populate shared groups uniquely without multiple frames');
    }
    let [distance0, dataset0]  = distanceDatasetPairs[0];
    let [distance1, dataset1] = distanceDatasetPairs[1];

    //
    // make the functional groups
    //

    // shared

    ds.SharedFunctionalGroups = {
      PlaneOrientation : {
        ImageOrientationPatient : dataset0.ImageOrientationPatient,
      },
      PixelMeasures : {
        PixelSpacing : dataset0.PixelSpacing,
        SpacingBetweenSlices : Math.abs(distance1 - distance0),
      },
    };

    // per-frame

    ds.PerFrameFunctionalGroups = [];
    distanceDatasetPairs.forEach(function(pair) {
      ds.PerFrameFunctionalGroups.push({
        PlanePosition : {
          ImagePositionPatient: pair[1].ImagePositionPatient,
        },
      });
    });

    ds.ReferencedSeries = {
      SeriesInstanceUID : dataset0.SeriesInstanceUID,
      ReferencedInstance : new Array(this.datasets.length),
    }

    // copy over each datasets window/level into the per-frame groups
    // and set the referenced series uid
    let datasetIndex = 0;
    this.datasets.forEach(function(dataset) {
      ds.PerFrameFunctionalGroups[datasetIndex].FrameVOILUT = {
        WindowCenter: dataset.WindowCenter,
        WindowWidth: dataset.WindowWidth,
      };
      ds.ReferencedSeries.ReferencedInstance[datasetIndex] = {
        ReferencedSOPClass: dataset.SOPClass,
        ReferencedSOPInstanceUID: dataset.SOPInstanceUID,
      }
      datasetIndex++;
    });

    let dimensionUID = DicomMetaDictionary.uid();
    this.dataset.DimensionOrganization = {
      DimensionOrganizationUID : dimensionUID
    };
    this.dataset.DimensionIndex = [
      {
        DimensionOrganizationUID : dimensionUID,
        DimensionIndexPointer : 2097202,
        FunctionalGroupPointer : 2134291, // PlanePositionSequence
        DimensionDescriptionLabel : "ImagePositionPatient"
      },
    ];
  }

  normalizeMultiframe() {
    let ds = this.dataset;
    if (!ds.NumberOfFrames) {
      console.error("Missing number or frames not supported");
      return;
    }
    if (Number(ds.NumberOfFrames) == 1) {
      console.error("Single frame instance of multiframe class not supported");
      return;
    }
    if (!ds.PixelRepresentation) {
      // Required tag: guess signed
      ds.PixelRepresentation = 1;
    }
    if (!ds.StudyID || ds.StudyID == "") {
      // Required tag: fill in if needed
      ds.StudyID = "No Study ID";
    }

    let validLateralities = ["R", "L"];
    if (validLateralities.indexOf(ds.Laterality) == -1) {
      delete(ds.Laterality);
    }

    if (!ds.PresentationLUTShape) {
      ds.PresentationLUTShape = "IDENTITY";
    }

    if (!ds.SharedFunctionalGroups) {
      console.error('Can only process multiframe data with SharedFunctionalGroups');
    }

    if (ds.BodyPartExamined == "PROSTATE") {
      ds.SharedFunctionalGroups.FrameAnatomy = {
        AnatomicRegion: {
          CodeValue: "T-9200B",
          CodingSchemeDesignator: "SRT",
          CodeMeaning: "Prostate",
        },
        FrameLaterality: "U",
      };
    }

    let rescaleIntercept = ds.RescaleIntercept || 0.;
    let rescaleSlope = ds.RescaleSlope || 1.;
    ds.SharedFunctionalGroups.PixelValueTransformation = {
      RescaleIntercept: rescaleIntercept,
      RescaleSlope: rescaleSlope,
      RescaleType: "US",
    };

    let frameNumber = 1;
    this.datasets.forEach(dataset=>{
      let frameTime = dataset.AcquisitionDate + dataset.AcquisitionTime;
      ds.PerFrameFunctionalGroups[frameNumber-1].FrameContent = {
        FrameAcquisitionDateTime: frameTime,
        FrameReferenceDateTime: frameTime,
        FrameAcquisitionDuration: 0,
        FrameAcquisitionDuration: 0,
        StackID: 1,
        InStackPositionNumber: frameNumber,
        DimensionIndexValues: frameNumber,
      };
      frameNumber++;
    });

    //
    // TODO: convert this to shared functional group not top level element
    //
    if (ds.WindowCenter && ds.WindowWidth) {
      // if they exist as single values, make them lists for consistency
      if (!Array.isArray(ds.WindowCenter)) {
        ds.WindowCenter = [ds.WindowCenter];
      }
      if (!Array.isArray(ds.WindowWidth)) {
        ds.WindowWidth = [ds.WindowWidth];
      }
    }
    if (!ds.WindowCenter || !ds.WindowWidth) {
      // if they don't exist, make them empty lists and try to initialize them
      ds.WindowCenter = []; // both must exist and be the same length
      ds.WindowWidth = [];
      // provide a volume-level window/level guess (mean of per-frame)
      if (ds.PerFrameFunctionalGroups) {
        let wcww = {center: 0, width: 0, count: 0};
        ds.PerFrameFunctionalGroups.forEach(function(functionalGroup) {
          if (functionalGroup.FrameVOILUT) {
            let wc = functionalGroup.FrameVOILUT.WindowCenter;
            let ww = functionalGroup.FrameVOILUT.WindowWidth;
            if (functionalGroup.FrameVOILUT && wc && ww) {
              if (Array.isArray(wc)) {
                wc = wc[0];
              }
              if (Array.isArray(ww)) {
                ww = ww[0];
              }
              wcww.center += Number(wc);
              wcww.width += Number(ww);
              wcww.count++;
            }
          }
        });
        if (wcww.count > 0) {
          ds.WindowCenter.push(String(wcww.center / wcww.count));
          ds.WindowWidth.push(String(wcww.width / wcww.count));
        }
      }
    }
    // last gasp, pick an arbitrary default
    if (ds.WindowCenter.length == 0) { ds.WindowCenter = [300] }
    if (ds.WindowWidth.length == 0) { ds.WindowWidth = [500] }
  }
}

class MRImageNormalizer extends ImageNormalizer {
  normalize() {
    super.normalize();
    // TODO: provide option at export to swap in LegacyConverted UID
    //this.dataset.SOPClass = "LegacyConvertedEnhancedMRImage";
    this.dataset.SOPClass = "EnhancedMRImage";
  }

  normalizeMultiframe() {
    super.normalizeMultiframe();
    let ds = this.dataset;

    if (!ds.ImageType
          || !ds.ImageType.constructor
          || ds.ImageType.constructor.name != "Array"
          || ds.ImageType.length != 4) {
      ds.ImageType = ["ORIGINAL", "PRIMARY", "OTHER", "NONE",];
    }

    ds.SharedFunctionalGroups.MRImageFrameType = {
      FrameType: ds.ImageType,
      PixelPresentation: "MONOCHROME",
      VolumetricProperties: "VOLUME",
      VolumeBasedCalculationTechnique: "NONE",
      ComplexImageComponent: "MAGNITUDE",
      AcquisitionContrast: "UNKNOWN",
    };
  }
}

class EnhancedMRImageNormalizer extends ImageNormalizer {
  normalize() {
    super.normalize();
  }
}

class CTImageNormalizer extends ImageNormalizer {
  normalize() {
    super.normalize();
    // TODO: provide option at export to swap in LegacyConverted UID
    //this.dataset.SOPClass = "LegacyConvertedEnhancedCTImage";
    this.dataset.SOPClass = "EnhancedCTImage";
  }
}

class PETImageNormalizer extends ImageNormalizer {
  normalize() {
    super.normalize();
    // TODO: provide option at export to swap in LegacyConverted UID
    //this.dataset.SOPClass = "LegacyConvertedEnhancedPETImage";
    this.dataset.SOPClass = "EnhancedPETImage";
  }
}

class SEGImageNormalizer extends ImageNormalizer {
  normalize() {
    super.normalize();
  }
}

class EnhancedUSVolumeNormalizer extends ImageNormalizer {
  normalize() {
    super.normalize();
  }
}

<|endoftext|>