<commit_before>// @flow
import * as Constants from '../../../../constants/chat'
import moment from 'moment'
import React from 'react'
import {Box, Icon, ProgressIndicator, Text, ClickableBox} from '../../../../common-adapters'
import {isMobile, fileUIName} from '../../../../constants/platform'
import {globalStyles, globalMargins, globalColors} from '../../../../styles'
import {ImageRender} from './image'

import type {Props, ProgressBarProps, ImageIconProps} from '.'

function _showProgressBar (messageState, progress) {
  return !!progress && (messageState === 'uploading' || (messageState === 'downloading'))
}

function _showPreviewProgress (messageState, progress) {
  return (!!progress && messageState === 'downloading-preview') || messageState === 'placeholder'
}

const AttachmentTitle = ({messageState, title, onOpenInPopup}: {messageState: Constants.AttachmentMessageState, title: ?string, onOpenInPopup: ?() => void}) => {
  let style = {
    backgroundColor: globalColors.white,
  }
  switch (messageState) {
    case 'uploading':
    case 'pending':
    case 'failed':
      style = {backgroundColor: globalColors.white, color: globalColors.black_40}
      break
  }
  return <Text type='BodySemibold' style={style} onClick={onOpenInPopup}>{title}</Text>
}

function PreviewImage ({message: {attachmentDurationMs, previewDurationMs, previewPath, previewType, previewSize, messageState}, onMessageAction, onOpenInPopup}: {message: Constants.AttachmentMessage, onMessageAction: ?() => void, onOpenInPopup: ?() => void}) {
  if (previewType === 'Image' || previewType === 'Video') {
    let style = {
      ...globalStyles.flexBoxRow,
      alignItems: 'flex-end',
      marginTop: globalMargins.xtiny,
      position: 'relative',
    }
    const imgStyle = {borderRadius: 4, ...(previewSize ? {height: previewSize.height, width: previewSize.width} : {maxHeight: 320, maxWidth: 320})}

    switch (messageState) {
      case 'uploading':
      case 'pending':
      case 'failed':
        style = {...style, opacity: 0.4}
        break
    }

    return (
      <ClickableBox style={style} onClick={onOpenInPopup} onLongPress={onMessageAction}>
        <Box style={{
          ...globalStyles.flexBoxRow,
          alignItems: 'flex-end',
          position: 'relative',
        }}>
          <Box style={{...imgStyle, backgroundColor: globalColors.black_05}}>
            {previewPath && <ImageRender style={imgStyle} src={previewPath} />}
          </Box>
          {!isMobile && (messageState === 'downloading' || messageState === 'downloaded') &&
            <ImageIcon
              style={{position: 'relative', right: 19, top: 3}}
              type={messageState === 'downloading' ? 'Downloading' : 'Downloaded'} />}
          {attachmentDurationMs && !previewDurationMs && messageState !== 'downloading-preview' &&
            <Box style={{...globalStyles.flexBoxCenter, ...globalStyles.fillAbsolute}}>
              <Icon type='icon-play-64' />
            </Box>
          }
          {attachmentDurationMs && previewType === 'Video' &&
            <Text
              type='BodySemibold'
              style={{backgroundColor: globalColors.transparent, bottom: globalMargins.xtiny, color: 'white', fontSize: 12, position: 'absolute', right: globalMargins.tiny}}
            >{moment.utc(attachmentDurationMs).format('m:ss')}</Text>
          }
        </Box>
      </ClickableBox>
    )
  }

  return null
}

function ProgressBar ({text, progress, style}: ProgressBarProps) {
  const basicStyle = {borderRadius: 4, height: 4, width: 64}
  const containerStyle = {
    ...globalStyles.flexBoxRow,
    ...globalStyles.rounded,
    alignItems: 'center',
    backgroundColor: globalColors.white,
    borderBottomRightRadius: 0,
    borderTopLeftRadius: 0,
    ...style,
  }

  return (
    <Box style={containerStyle}>
      <Text type={'BodySmall'} style={{marginRight: globalMargins.xtiny}}>{text}</Text>
      <Box style={{...basicStyle, backgroundColor: globalColors.black_05, marginLeft: globalMargins.xtiny, marginTop: 2}}>
        <Box style={{...basicStyle, backgroundColor: globalColors.blue, width: 64 * progress}} />
      </Box>
    </Box>
  )
}

function ImageIcon ({type, style}: ImageIconProps) {
  const iconStyle = {
    ...globalStyles.flexBoxColumn,
    backgroundColor: globalColors.white,
    color: type === 'Downloading' ? globalColors.blue : globalColors.green,
  }

  const wrapperStyle = {
    backgroundColor: globalColors.white,
    borderRadius: 19,
    padding: 3,
  }

  return (
    <Box style={{...wrapperStyle, ...style}}>
      <Icon type='iconfont-import' style={iconStyle} />
    </Box>
  )
}

const ShowInFileUi = ({onOpenInFileUI}) => (
  <Text type='BodySmallSecondaryLink' onClick={onOpenInFileUI}>Show in {fileUIName}</Text>
)

function PreviewImageWithInfo ({message, onMessageAction, onOpenInFileUI, onOpenInPopup}: {message: Constants.AttachmentMessage, onMessageAction: ?() => void, onOpenInFileUI: () => void, onOpenInPopup: ?() => void}) {
  const {downloadedPath, messageState} = message

  const overlayProgressBarStyle = {
    bottom: globalMargins.xtiny,
    left: 0,
    paddingBottom: globalMargins.xtiny,
    paddingLeft: globalMargins.xtiny,
    paddingRight: globalMargins.tiny,
    paddingTop: globalMargins.xtiny,
    position: 'absolute',
  }

  return (
    <Box style={{...globalStyles.flexBoxColumn, position: 'relative'}}>
      <Box style={{...globalStyles.flexBoxColumn, alignSelf: 'flex-start', position: 'relative'}}>
        <PreviewImage message={message} onMessageAction={onMessageAction} onOpenInPopup={onOpenInPopup} />
        {_showPreviewProgress(messageState, message.progress) &&
          <Box style={{...globalStyles.flexBoxCenter, ...globalStyles.fillAbsolute}}>
            <ProgressIndicator style={{width: 32}} />
          </Box>
        }
      </Box>
      <Box style={{marginTop: globalMargins.xtiny}}>
        {_showProgressBar(messageState, message.progress) && !!message.progress &&
          <ProgressBar
            style={messageState === 'uploading' ? overlayProgressBarStyle : {}}
            text={messageState === 'downloading' ? 'Downloading' : 'Encrypting'}
            progress={message.progress} />}
        {!isMobile && downloadedPath && <ShowInFileUi onOpenInFileUI={onOpenInFileUI} />}
      </Box>
    </Box>
  )
}

function AttachmentIcon ({messageState}: {messageState: Constants.AttachmentMessageState}) {
  let iconType = 'icon-file-24'
  let style = {backgroundColor: globalColors.white, height: 24, marginBottom: 8, marginTop: 8}
  switch (messageState) {
    case 'downloading':
      iconType = 'icon-file-downloading-24'
      break
    case 'downloaded':
      iconType = 'icon-file-downloaded-24'
      break
    case 'uploading':
    case 'pending':
    case 'failed':
      style = {...style, opacity: 0.4}
  }
  return <Icon type={iconType} style={style} />
}

function AttachmentMessageGeneric ({message, onMessageAction, onOpenInFileUI, onLoadAttachment, onOpenInPopup}: {message: Constants.AttachmentMessage, onMessageAction: () => void, onOpenInFileUI: () => void, onLoadAttachment: () => void, onOpenInPopup: ?() => void}) {
  const {downloadedPath, messageState, progress} = message
  const canOpen = messageState !== 'uploading'
  return (
    <Box style={{...globalStyles.flexBoxRow, ...(!downloadedPath ? globalStyles.clickable : {}), alignItems: 'center'}} onClick={!downloadedPath ? onLoadAttachment : undefined}>
      <AttachmentIcon messageState={messageState} />
      <Box style={{...globalStyles.flexBoxColumn, flex: 1, marginLeft: globalMargins.xtiny}}>
        <AttachmentTitle {...message} onOpenInPopup={canOpen ? onOpenInPopup : null} />

        {!isMobile && (_showProgressBar(messageState, progress) || downloadedPath) &&
          <Box style={{height: 14}}>
            {_showProgressBar(messageState, progress) && !!progress &&
              <ProgressBar
                text={messageState === 'downloading' ? 'Downloading' : 'Encrypting'}
                progress={progress} />}
            {downloadedPath && <ShowInFileUi onOpenInFileUI={onOpenInFileUI} />}
          </Box>}
      </Box>
    </Box>
  )
}

function AttachmentMessagePreviewImage ({message, onMessageAction, onOpenInFileUI, onOpenInPopup}: {message: Constants.AttachmentMessage, onMessageAction: () => void, onOpenInFileUI: () => void, onOpenInPopup: ?() => void}) {
  const canOpen = message.messageState !== 'uploading'
  return (
    <Box style={{...globalStyles.flexBoxColumn, ...(canOpen ? globalStyles.clickable : {}), flex: 1}}>
      <AttachmentTitle {...message} onOpenInPopup={canOpen ? onOpenInPopup : null} />
      <PreviewImageWithInfo message={message} onMessageAction={onMessageAction} onOpenInFileUI={onOpenInFileUI} onOpenInPopup={canOpen ? onOpenInPopup : null} />
    </Box>
  )
}

const AttachmentMessage = (props: Props) => {
  switch (props.message.previewType) {
    case 'Image':
    case 'Video':
      return <AttachmentMessagePreviewImage message={props.message} onMessageAction={props.onAction} onOpenInPopup={props.onOpenInPopup} onOpenInFileUI={props.onOpenInFileUI} />
    default:
      return <AttachmentMessageGeneric message={props.message} onMessageAction={props.onAction} onOpenInFileUI={props.onOpenInFileUI} onLoadAttachment={props.onLoadAttachment} onOpenInPopup={isMobile ? props.onOpenInPopup : null} />
  }
}

export default AttachmentMessage

export {
  ProgressBar,
  ImageIcon,
}
<commit_msg>Gray out attachment title while being uploaded<commit_after>// @flow
import * as Constants from '../../../../constants/chat'
import moment from 'moment'
import React from 'react'
import {Box, Icon, ProgressIndicator, Text, ClickableBox} from '../../../../common-adapters'
import {isMobile, fileUIName} from '../../../../constants/platform'
import {globalStyles, globalMargins, globalColors} from '../../../../styles'
import {ImageRender} from './image'

import type {Props, ProgressBarProps, ImageIconProps} from '.'

function _showProgressBar (messageState, progress) {
  return !!progress && (messageState === 'uploading' || (messageState === 'downloading'))
}

function _showPreviewProgress (messageState, progress) {
  return (!!progress && messageState === 'downloading-preview') || messageState === 'placeholder'
}

const AttachmentTitle = ({messageState, title, onOpenInPopup}: {messageState: Constants.AttachmentMessageState, title: ?string, onOpenInPopup: ?() => void}) => {
  let style = {
    backgroundColor: globalColors.white,
  }
  switch (messageState) {
    case 'uploading':
    case 'pending':
    case 'failed':
    case 'placeholder':
      style = {backgroundColor: globalColors.white, color: globalColors.black_40}
      break
  }
  return <Text type='BodySemibold' style={style} onClick={onOpenInPopup}>{title}</Text>
}

function PreviewImage ({message: {attachmentDurationMs, previewDurationMs, previewPath, previewType, previewSize, messageState}, onMessageAction, onOpenInPopup}: {message: Constants.AttachmentMessage, onMessageAction: ?() => void, onOpenInPopup: ?() => void}) {
  if (previewType === 'Image' || previewType === 'Video') {
    let style = {
      ...globalStyles.flexBoxRow,
      alignItems: 'flex-end',
      marginTop: globalMargins.xtiny,
      position: 'relative',
    }
    const imgStyle = {borderRadius: 4, ...(previewSize ? {height: previewSize.height, width: previewSize.width} : {maxHeight: 320, maxWidth: 320})}

    switch (messageState) {
      case 'uploading':
      case 'pending':
      case 'failed':
        style = {...style, opacity: 0.4}
        break
    }

    return (
      <ClickableBox style={style} onClick={onOpenInPopup} onLongPress={onMessageAction}>
        <Box style={{
          ...globalStyles.flexBoxRow,
          alignItems: 'flex-end',
          position: 'relative',
        }}>
          <Box style={{...imgStyle, backgroundColor: globalColors.black_05}}>
            {previewPath && <ImageRender style={imgStyle} src={previewPath} />}
          </Box>
          {!isMobile && (messageState === 'downloading' || messageState === 'downloaded') &&
            <ImageIcon
              style={{position: 'relative', right: 19, top: 3}}
              type={messageState === 'downloading' ? 'Downloading' : 'Downloaded'} />}
          {attachmentDurationMs && !previewDurationMs && messageState !== 'downloading-preview' &&
            <Box style={{...globalStyles.flexBoxCenter, ...globalStyles.fillAbsolute}}>
              <Icon type='icon-play-64' />
            </Box>
          }
          {attachmentDurationMs && previewType === 'Video' &&
            <Text
              type='BodySemibold'
              style={{backgroundColor: globalColors.transparent, bottom: globalMargins.xtiny, color: 'white', fontSize: 12, position: 'absolute', right: globalMargins.tiny}}
            >{moment.utc(attachmentDurationMs).format('m:ss')}</Text>
          }
        </Box>
      </ClickableBox>
    )
  }

  return null
}

function ProgressBar ({text, progress, style}: ProgressBarProps) {
  const basicStyle = {borderRadius: 4, height: 4, width: 64}
  const containerStyle = {
    ...globalStyles.flexBoxRow,
    ...globalStyles.rounded,
    alignItems: 'center',
    backgroundColor: globalColors.white,
    borderBottomRightRadius: 0,
    borderTopLeftRadius: 0,
    ...style,
  }

  return (
    <Box style={containerStyle}>
      <Text type={'BodySmall'} style={{marginRight: globalMargins.xtiny}}>{text}</Text>
      <Box style={{...basicStyle, backgroundColor: globalColors.black_05, marginLeft: globalMargins.xtiny, marginTop: 2}}>
        <Box style={{...basicStyle, backgroundColor: globalColors.blue, width: 64 * progress}} />
      </Box>
    </Box>
  )
}

function ImageIcon ({type, style}: ImageIconProps) {
  const iconStyle = {
    ...globalStyles.flexBoxColumn,
    backgroundColor: globalColors.white,
    color: type === 'Downloading' ? globalColors.blue : globalColors.green,
  }

  const wrapperStyle = {
    backgroundColor: globalColors.white,
    borderRadius: 19,
    padding: 3,
  }

  return (
    <Box style={{...wrapperStyle, ...style}}>
      <Icon type='iconfont-import' style={iconStyle} />
    </Box>
  )
}

const ShowInFileUi = ({onOpenInFileUI}) => (
  <Text type='BodySmallSecondaryLink' onClick={onOpenInFileUI}>Show in {fileUIName}</Text>
)

function PreviewImageWithInfo ({message, onMessageAction, onOpenInFileUI, onOpenInPopup}: {message: Constants.AttachmentMessage, onMessageAction: ?() => void, onOpenInFileUI: () => void, onOpenInPopup: ?() => void}) {
  const {downloadedPath, messageState} = message

  const overlayProgressBarStyle = {
    bottom: globalMargins.xtiny,
    left: 0,
    paddingBottom: globalMargins.xtiny,
    paddingLeft: globalMargins.xtiny,
    paddingRight: globalMargins.tiny,
    paddingTop: globalMargins.xtiny,
    position: 'absolute',
  }

  return (
    <Box style={{...globalStyles.flexBoxColumn, position: 'relative'}}>
      <Box style={{...globalStyles.flexBoxColumn, alignSelf: 'flex-start', position: 'relative'}}>
        <PreviewImage message={message} onMessageAction={onMessageAction} onOpenInPopup={onOpenInPopup} />
        {_showPreviewProgress(messageState, message.progress) &&
          <Box style={{...globalStyles.flexBoxCenter, ...globalStyles.fillAbsolute}}>
            <ProgressIndicator style={{width: 32}} />
          </Box>
        }
      </Box>
      <Box style={{marginTop: globalMargins.xtiny}}>
        {_showProgressBar(messageState, message.progress) && !!message.progress &&
          <ProgressBar
            style={messageState === 'uploading' ? overlayProgressBarStyle : {}}
            text={messageState === 'downloading' ? 'Downloading' : 'Encrypting'}
            progress={message.progress} />}
        {!isMobile && downloadedPath && <ShowInFileUi onOpenInFileUI={onOpenInFileUI} />}
      </Box>
    </Box>
  )
}

function AttachmentIcon ({messageState}: {messageState: Constants.AttachmentMessageState}) {
  let iconType = 'icon-file-24'
  let style = {backgroundColor: globalColors.white, height: 24, marginBottom: 8, marginTop: 8}
  switch (messageState) {
    case 'downloading':
      iconType = 'icon-file-downloading-24'
      break
    case 'downloaded':
      iconType = 'icon-file-downloaded-24'
      break
    case 'uploading':
    case 'pending':
    case 'failed':
      style = {...style, opacity: 0.4}
  }
  return <Icon type={iconType} style={style} />
}

function AttachmentMessageGeneric ({message, onMessageAction, onOpenInFileUI, onLoadAttachment, onOpenInPopup}: {message: Constants.AttachmentMessage, onMessageAction: () => void, onOpenInFileUI: () => void, onLoadAttachment: () => void, onOpenInPopup: ?() => void}) {
  const {downloadedPath, messageState, progress} = message
  const canOpen = messageState !== 'uploading'
  return (
    <Box style={{...globalStyles.flexBoxRow, ...(!downloadedPath ? globalStyles.clickable : {}), alignItems: 'center'}} onClick={!downloadedPath ? onLoadAttachment : undefined}>
      <AttachmentIcon messageState={messageState} />
      <Box style={{...globalStyles.flexBoxColumn, flex: 1, marginLeft: globalMargins.xtiny}}>
        <AttachmentTitle {...message} onOpenInPopup={canOpen ? onOpenInPopup : null} />

        {!isMobile && (_showProgressBar(messageState, progress) || downloadedPath) &&
          <Box style={{height: 14}}>
            {_showProgressBar(messageState, progress) && !!progress &&
              <ProgressBar
                text={messageState === 'downloading' ? 'Downloading' : 'Encrypting'}
                progress={progress} />}
            {downloadedPath && <ShowInFileUi onOpenInFileUI={onOpenInFileUI} />}
          </Box>}
      </Box>
    </Box>
  )
}

function AttachmentMessagePreviewImage ({message, onMessageAction, onOpenInFileUI, onOpenInPopup}: {message: Constants.AttachmentMessage, onMessageAction: () => void, onOpenInFileUI: () => void, onOpenInPopup: ?() => void}) {
  const canOpen = message.messageState !== 'uploading'
  return (
    <Box style={{...globalStyles.flexBoxColumn, ...(canOpen ? globalStyles.clickable : {}), flex: 1}}>
      <AttachmentTitle {...message} onOpenInPopup={canOpen ? onOpenInPopup : null} />
      <PreviewImageWithInfo message={message} onMessageAction={onMessageAction} onOpenInFileUI={onOpenInFileUI} onOpenInPopup={canOpen ? onOpenInPopup : null} />
    </Box>
  )
}

const AttachmentMessage = (props: Props) => {
  switch (props.message.previewType) {
    case 'Image':
    case 'Video':
      return <AttachmentMessagePreviewImage message={props.message} onMessageAction={props.onAction} onOpenInPopup={props.onOpenInPopup} onOpenInFileUI={props.onOpenInFileUI} />
    default:
      return <AttachmentMessageGeneric message={props.message} onMessageAction={props.onAction} onOpenInFileUI={props.onOpenInFileUI} onLoadAttachment={props.onLoadAttachment} onOpenInPopup={isMobile ? props.onOpenInPopup : null} />
  }
}

export default AttachmentMessage

export {
  ProgressBar,
  ImageIcon,
}
<|endoftext|>


<commit_before>(function(Vis) {

Vis.blocks['i-math-data-provider'] = {
    init: function(params) {
        var _this = this,
            timeRangeProvider = _this.timeRangeProvider = params.timeRangeProvider;

        _this.params = params;

        timeRangeProvider.on('update.vis', function() {
            _this.range = timeRangeProvider.get();
            $(_this).trigger('update.vis');
        });
        _this.range = timeRangeProvider.get();
    },

    on: function(action, callback) {
        $(this).on(action + '.vis', callback);
    },

    get: function() {
        var tbegin = this.range.min,
            tend = this.range.max;

        var step = this.params.step || 1;
        var f = this[this.params.func || 'sin'] || this.sin;
        var factor = this.params.factor || 1;

        var t = Math.ceil(tbegin / step) * step;
        var i = 0;
        var length = Math.floor((tend - t) / step);
        var xData = new Array(length);
        var yData = new Array(length);
        while (t < tend) {
            var tmp = f.call(this, t * factor);
            xData[i] = tmp.x;
            yData[i] = tmp.y;
            t += step;
            i += 1;
        }
        return {
            x: xData,
            y: yData
        };
    },

    sin: function(t) {
        return { x: t, y: Math.sin(t) };
    },

    cos: function(t) {
        return { x: t, y: Math.cos(t) };
    },

    sin2: function(x) {
        return { x: t, y: Math.pow(Math.sin(t), 2) };
    },

    cos2: function(x) {
        return { x: t, y: Math.pow(Math.cos(t), 2) };
    },

    lissajous: function(t) {
        return {
            x: Math.sin(this.params.a * t),
            y: Math.sin(this.params.b * t)
        };
    },

    demo1: function(t) {
        var a = 0.05;
        return {
            x: t,
            y:
             1.5*Math.sin(51*a*t) +
            -1.4*Math.sin(21*a*t) +
             1.3*Math.sin(11*a*t) +
            -1.2*Math.sin(9*a*t) +
             1.1*Math.sin(2*a*t) +
                 Math.sin(a*t) +
                 Math.sin(0.6*a*t) +
              10*Math.sin(0.1*a*t) +
              20*Math.sin(0.02*a*t) +
               5*Math.sin(0.03*a*t) +
              20*Math.sin(0.025*a*t)
        }
    }
};

})(Vis);
<commit_msg>Updated demo1 dataset<commit_after>(function(Vis) {

Vis.blocks['i-math-data-provider'] = {
    init: function(params) {
        var _this = this,
            timeRangeProvider = _this.timeRangeProvider = params.timeRangeProvider;

        _this.params = params;

        timeRangeProvider.on('update.vis', function() {
            _this.range = timeRangeProvider.get();
            $(_this).trigger('update.vis');
        });
        _this.range = timeRangeProvider.get();
    },

    on: function(action, callback) {
        $(this).on(action + '.vis', callback);
    },

    get: function() {
        var tbegin = this.range.min,
            tend = this.range.max;

        var step = this.params.step || 1;
        var f = this[this.params.func || 'sin'] || this.sin;
        var factor = this.params.factor || 1;

        var t = Math.ceil(tbegin / step) * step;
        var i = 0;
        var length = Math.floor((tend - t) / step);
        var xData = new Array(length);
        var yData = new Array(length);
        while (t < tend) {
            var tmp = f.call(this, t * factor);
            xData[i] = tmp.x;
            yData[i] = tmp.y;
            t += step;
            i += 1;
        }
        return {
            x: xData,
            y: yData
        };
    },

    sin: function(t) {
        return { x: t, y: Math.sin(t) };
    },

    cos: function(t) {
        return { x: t, y: Math.cos(t) };
    },

    sin2: function(x) {
        return { x: t, y: Math.pow(Math.sin(t), 2) };
    },

    cos2: function(x) {
        return { x: t, y: Math.pow(Math.cos(t), 2) };
    },

    lissajous: function(t) {
        return {
            x: Math.sin(this.params.a * t),
            y: Math.sin(this.params.b * t)
        };
    },

    demo1: function(t) {
        var a = 0.05;
        return {
            x: t,
            y:
             1.5*Math.sin(51*a*t) +
            -1.4*Math.sin(21*a*t) +
             1.3*Math.sin(11*a*t) +
            -1.2*Math.sin(9*a*t) +
             1.1*Math.sin(2*a*t) +
               5*Math.sin(1.73205*a*t) +
                 Math.sin(a*t) +
               7*Math.sin(0.707106*a*t) +
                 Math.sin(0.6*a*t) +
              10*Math.sin(0.1*a*t) +
              11*Math.sin(0.223606*a*t) +
               7*Math.sin(0.173205*a*t) +
               5*Math.sin(0.141421*a*t) +
              20*Math.sin(0.02*a*t) +
               5*Math.sin(0.03*a*t) +
              20*Math.sin(0.025*a*t) +
              11*Math.sin(0.0158770*a*t) +
              17*Math.sin(0.00294565*a*t) +
              19*Math.sin(0.000977518*a*t) +
              11*Math.sin(0.0000305185*a*t)
        }
    }
};

})(Vis);
<|endoftext|>


<commit_before>import DataStore from 'classes/data-store';
import SearchResult from 'classes/search-result';
import Levenshtein from 'classes/levenshtein';
import SearchView from 'views/search';
import ListView from 'views/list';
import * as templates from 'templates';
import ajax from 'utils/ajax';

class SearchController {
    constructor(opts = {}) {
        // models
        this.lastSearch = '';
        this.store = new DataStore();

        // views
        this.searchView = new SearchView({
            el: opts.searchEl
        });
        this.orgListView = new ListView({
            el: opts.orgListEl,
            template: templates.OrgListItem,
        });
        this.projectListView = new ListView({
            el: opts.projectListEl,
            template: templates.ProjectListItem,
        });
    }

    init() {
        return this.initStorage().then(() => {
            var store = this.store;
            this.initLevenshtein();
            this.initTextBox();
            this.orgListView.render(store.all('org'));
            this.projectListView.render(store.all('project'));
        });
    }

    initStorage() {
        var store = this.store;
        store.addType('org');
        store.addType('project');
        store.addType('search');
        store.registerModelFactory('search', SearchResult);

        function addOrgs(orgs) {
            store.load('org', orgs);
            return ajax({url: '/data/projects.json'});
        }

        function addProjects(projects) {
            var id = 1;
            projects.forEach(proj => {
                proj.id = id++;

                if (proj.organizationId) {
                    proj.organization = store.find('org', proj.organizationId);
                }

                return proj;
            });
            store.load('project', projects);
        }

        return ajax({url: '/data/organizations.json'})
            .then(addOrgs)
            .then(addProjects)
            .then(() => {
                store.load('search', {
                    // initialize search results for empty search text box
                    id: '',
                    org: store.all('org'),
                    project: store.all('project'),
                });
            });
    }

    initLevenshtein() {
        var levOpts = {
            type: 'substring',
            caseSensitive: false
        };
        this.lev = new Levenshtein(levOpts);
        this.lev.set('insertCost', 0);
        this.lev.set('deleteCost', Infinity);
    }

    initTextBox() {
        this.searchView.on('keyup', this.handleKeyup.bind(this));
    }

    handleKeyup(evt) {
        var value = evt.target.value;
        var lastSearch = this.lastSearch;
        var store = this.store;
        var model;

        // if search has been previously cached in the database, use it
        model = store.find('search', value);

        if (!model) {
            if (lastSearch.length < value.length) {
                // we're filtering current results, use last results
                model = store.find('search', lastSearch);
            } else {
                // we're widening current results, start from scratch
                model = store.find('search', '');
            }

            // perform string approximation on models' attributes
            model = this.approximate(model, value);
            // store the search results back into the store
            store.load('search', model);
        }

        // apply user-supplied filters to the search results
        model = this.applyFilters(model);

        this.lastSearch = value;
        this.orgListView.render(model.org);
        this.projectListView.render(model.project);
    }

    approximate(model, searchString) {
        var ret = {};

        // model id is the value of the search itself
        // so that the data store can be queried easily
        ret.id = searchString;

        ret.org = model.org.slice(1);
        ret.project = model.project.slice(1);

        return ret;
    }

    applyFilters(model) {
        var ret = {};
        ret.org = model.org;
        ret.project = model.project;
        return ret;
    }
}

export default SearchController;
<commit_msg>Use Levenshtein distance to determine search diff<commit_after>import DataStore from 'classes/data-store';
import SearchResult from 'classes/search-result';
import Levenshtein from 'classes/levenshtein';
import SearchView from 'views/search';
import ListView from 'views/list';
import * as templates from 'templates';
import ajax from 'utils/ajax';

class SearchController {
    constructor(opts = {}) {
        // models
        this.lastSearch = '';
        this.store = new DataStore();

        // views
        this.searchView = new SearchView({
            el: opts.searchEl
        });
        this.orgListView = new ListView({
            el: opts.orgListEl,
            template: templates.OrgListItem,
        });
        this.projectListView = new ListView({
            el: opts.projectListEl,
            template: templates.ProjectListItem,
        });
    }

    init() {
        return this.initStorage().then(() => {
            var store = this.store;
            this.initLevenshtein();
            this.initTextBox();
            this.orgListView.render(store.all('org'));
            this.projectListView.render(store.all('project'));
        });
    }

    initStorage() {
        var store = this.store;
        store.addType('org');
        store.addType('project');
        store.addType('search');
        store.registerModelFactory('search', SearchResult);

        function addOrgs(orgs) {
            store.load('org', orgs);
            return ajax({url: '/data/projects.json'});
        }

        function addProjects(projects) {
            var id = 1;
            projects.forEach(proj => {
                proj.id = id++;

                if (proj.organizationId) {
                    proj.organization = store.find('org', proj.organizationId);
                }

                return proj;
            });
            store.load('project', projects);
        }

        return ajax({url: '/data/organizations.json'})
            .then(addOrgs)
            .then(addProjects)
            .then(() => {
                store.load('search', {
                    // initialize search results for empty search text box
                    id: '',
                    org: store.all('org'),
                    project: store.all('project'),
                });
            });
    }

    initLevenshtein() {
        var levOpts = {
            type: 'substring',
            caseSensitive: false
        };
        this.lev = new Levenshtein(levOpts);
        this.lev.set('insertCost', 0);
        this.lev.set('deleteCost', Infinity);
    }

    initTextBox() {
        this.searchView.on('keyup', this.handleKeyup.bind(this));
    }

    handleKeyup(evt) {
        var value = evt.target.value;
        var lastSearch = this.lastSearch;
        var store = this.store;
        var model;

        // if search has been previously cached in the database, use it
        model = store.find('search', value);

        if (!model) {
            // if only inserts and matches are used to transform the lastSearch...
            if (this.lev.process(lastSearch, value).totalCost() === 0) {
                // we're filtering the last results further
                model = store.find('search', lastSearch);
            } else {
                // we're widening the last results, start from scratch
                model = store.find('search', '');
            }

            // perform string approximation on models' attributes
            model = this.approximate(model, value);
            // store the search results back into the store
            store.load('search', model);
        }

        // apply user-supplied filters and sorts to the search results
        model = this.applyFilters(model);
        model = this.applySorts(model);

        this.lastSearch = value;
        this.orgListView.render(model.org);
        this.projectListView.render(model.project);
    }

    approximate(model, searchString) {
        var ret = {
            org: [],
            project: [],
        };

        // model id is the value of the search itself
        // so that the data store can be queried easily
        ret.id = searchString;

        ret.org = model.org.slice(1);
        ret.project = model.project.slice(1);

        return ret;
    }

    applyFilters(model) {
        var ret = {};
        ret.org = model.org.slice();
        ret.project = model.project.slice();
        return ret;
    }

    applySorts(model) {
        var ret = {};
        ret.org = model.org.slice();
        ret.project = model.project.slice();
        return ret;
    }
}

export default SearchController;
<|endoftext|>


<commit_before>
//simulates the flex box ability of giving things equal heights
$('.grid').each(function(){
	$(this).find(' > .grid__cell').matchHeight();
});

//Doesn't fix IE8 and IE9 not treating the right negative margin properly
//It's far less obvious with this though
//doing it in JS because nth-child won't work in IE8
for (var i = 0; i < 8; i++){
	$('[class*="grid--gutter-"].grid--cols-'+(i+1)+' > .grid-cell:nth-child('+(i+1)+'n)').css('border-right',0);
}

<commit_msg>grid__inner cells now take up full width of parent cell in IE8 and 9<commit_after>
$('.grid').each(function(){
	//simulates the flex box ability of giving things equal heights
	$(this).find(' > .grid__cell').matchHeight();

	//Makes cells with grid__inner classes take up the full height of the cell
	if ($(this).hasClass('grid--hasInners')){
		var this_cell = $(this).find(' > .grid__cell');
		this_cell.find(' > .grid__inner').height(this_cell.height());
	}
});

//Doesn't fix IE8 and IE9 not treating the right negative margin properly
//It's far less obvious with this though
//doing it in JS because nth-child won't work in IE8
for (var i = 0; i < 8; i++){
	$('[class*="grid--gutter-"].grid--cols-'+(i+1)+' > .grid-cell:nth-child('+(i+1)+'n)').css('border-right',0);
}

<|endoftext|>


<commit_before>define(["Tone/core/Tone", "Tone/type/TimeBase"], function (Tone) {

	/**
	 *  @class Tone.Frequency is a primitive type for encoding Frequency values.
	 *         Eventually all time values are evaluated to hertz
	 *         using the `eval` method.
	 *  @constructor
	 *  @extends {Tone.TimeBase}
	 *  @param  {String|Number}  val    The time value.
	 *  @param  {String=}  units  The units of the value.
	 *  @example
	 * Tone.Frequency("C3") // 261
	 * Tone.Frequency(38, "midi") //
	 * Tone.Frequency("C3").transpose(4);
	 */
	Tone.Frequency = function(val, units){
		if (this instanceof Tone.Frequency){

			Tone.TimeBase.call(this, val, units);

		} else {
			return new Tone.Frequency(val, units);
		}
	};

	Tone.extend(Tone.Frequency, Tone.TimeBase);

	///////////////////////////////////////////////////////////////////////////
	//	AUGMENT BASE EXPRESSIONS
	///////////////////////////////////////////////////////////////////////////

	//clone the expressions so that
	//we can add more without modifying the original
	Tone.Frequency.prototype._primaryExpressions = Object.create(Tone.TimeBase.prototype._primaryExpressions);

	/*
	 *  midi type primary expression
	 *  @type {Object}
	 *  @private
	 */
	Tone.Frequency.prototype._primaryExpressions.midi = {
		regexp : /^(\d+(?:\.\d+)?midi)/,
		method : function(value){
			return this.midiToFrequency(value);
		}
	};

	/*
	 *  note type primary expression
	 *  @type {Object}
	 *  @private
	 */
	Tone.Frequency.prototype._primaryExpressions.note = {
		regexp : /^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i,
		method : function(pitch, octave){
			var index = noteToScaleIndex[pitch.toLowerCase()];
			var noteNumber = index + (parseInt(octave) + 1) * 12;
			return this.midiToFrequency(noteNumber);
		}
	};

	/*
	 *  BeatsBarsSixteenths type primary expression
	 *  @type {Object}
	 *  @private
	 */
	Tone.Frequency.prototype._primaryExpressions.tr = {
			regexp : /^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):?(\d+(?:\.\d+)?)?/,
			method : function(m, q, s){
			var total = 1;
			if (m && m !== "0"){
				total *= this._beatsToUnits(this._timeSignature() * parseFloat(m));
			}
			if (q && q !== "0"){
				total *= this._beatsToUnits(parseFloat(q));
			}
			if (s && s !== "0"){
				total *= this._beatsToUnits(parseFloat(s) / 4);
			}
			return total;
		}
	};

	///////////////////////////////////////////////////////////////////////////
	//	EXPRESSIONS
	///////////////////////////////////////////////////////////////////////////

	/**
	 *  Transposes the frequency by the given number of semitones.
	 *  @param  {Interval}  interval
	 *  @return  {Tone.Frequency} this
	 *  @example
	 * Tone.Frequency("A4").transpose(3); //"C5"
	 */
	Tone.Frequency.prototype.transpose = function(interval){
		this._expr = function(expr, interval){
			var val = expr();
			return val * Tone.intervalToFrequencyRatio(interval);
		}.bind(this, this._expr, interval);
		return this;
	};

	/**
	 *  Takes an array of semitone intervals and returns
	 *  an array of frequencies transposed by those intervals.
	 *  @param  {Array}  intervals
	 *  @return  {Tone.Frequency} this
	 *  @example
	 * Tone.Frequency("A4").harmonize([0, 3, 7]); //["A4", "C5", "E5"]
	 */
	Tone.Frequency.prototype.harmonize = function(intervals){
		this._expr = function(expr, intervals){
			var val = expr();
			var ret = [];
			for (var i = 0; i < intervals.length; i++){
				ret[i] = val * Tone.intervalToFrequencyRatio(intervals[i]);
			}
			return ret;
		}.bind(this, this._expr, intervals);
		return this;
	};

	///////////////////////////////////////////////////////////////////////////
	//	UNIT CONVERSIONS
	///////////////////////////////////////////////////////////////////////////

	/**
	 *  Return the value of the frequency as a MIDI note
	 *  @return  {MIDI}
	 *  @example
	 * Tone.Frequency("C4").toMidi(); //60
	 */
	Tone.Frequency.prototype.toMidi = function(){
		return this.frequencyToMidi(this.valueOf());
	};

	/**
	 *  Return the value of the frequency in Scientific Pitch Notation
	 *  @return  {Note}
	 *  @example
	 * Tone.Frequency(69, "midi").toNote(); //"A4"
	 */
	Tone.Frequency.prototype.toNote = function(){
		var freq = this.valueOf();
		var log = Math.log(freq / Tone.Frequency.A4) / Math.LN2;
		var noteNumber = Math.round(12 * log) + 57;
		var octave = Math.floor(noteNumber/12);
		if(octave < 0){
			noteNumber += -12 * octave;
		}
		var noteName = scaleIndexToNote[noteNumber % 12];
		return noteName + octave.toString();
	};

	/**
	 *  Return the duration of one cycle in seconds.
	 *  @return  {Seconds}
	 */
	Tone.Frequency.prototype.toSeconds = function(){
		return 1 / this.valueOf();
	};

	/**
	 *  Return the value in Hertz
	 *  @return  {Frequency}
	 */
	Tone.Frequency.prototype.toFrequency = function(){
		return this.valueOf();
	};

	/**
	 *  Return the duration of one cycle in ticks
	 *  @return  {Ticks}
	 */
	Tone.Frequency.prototype.toTicks = function(){
		var quarterTime = this._beatsToUnits(1);
		var quarters = this.valueOf() / quarterTime;
		return Math.floor(quarters * Tone.Transport.PPQ);
	};

	///////////////////////////////////////////////////////////////////////////
	//	UNIT CONVERSIONS HELPERS
	///////////////////////////////////////////////////////////////////////////

	/**
	 *  Returns the value of a frequency in the current units
	 *  @param {Frequency} freq
	 *  @return  {Number}
	 *  @private
	 */
	Tone.Frequency.prototype._frequencyToUnits = function(freq){
		return freq;
	};

	/**
	 *  Returns the value of a tick in the current time units
	 *  @param {Ticks} ticks
	 *  @return  {Number}
	 *  @private
	 */
	Tone.Frequency.prototype._ticksToUnits = function(ticks){
		return 1 / ((ticks * 60) / (Tone.Transport.bpm.value * Tone.Transport.PPQ));
	};

	/**
	 *  Return the value of the beats in the current units
	 *  @param {Number} beats
	 *  @return  {Number}
	 *  @private
	 */
	Tone.Frequency.prototype._beatsToUnits = function(beats){
		return 1 / Tone.TimeBase.prototype._beatsToUnits.call(this, beats);
	};

	/**
	 *  Returns the value of a second in the current units
	 *  @param {Seconds} seconds
	 *  @return  {Number}
	 *  @private
	 */
	Tone.Frequency.prototype._secondsToUnits = function(seconds){
		return 1 / seconds;
	};

	/**
	 *  The default units if none are given.
	 *  @private
	 */
	Tone.Frequency.prototype._defaultUnits = "hz";

	///////////////////////////////////////////////////////////////////////////
	//	FREQUENCY CONVERSIONS
	///////////////////////////////////////////////////////////////////////////

	/**
	 *  Note to scale index
	 *  @type  {Object}
	 */
	var noteToScaleIndex = {
		"cbb" : -2, "cb" : -1, "c" : 0,  "c#" : 1,  "cx" : 2,
		"dbb" : 0,  "db" : 1,  "d" : 2,  "d#" : 3,  "dx" : 4,
		"ebb" : 2,  "eb" : 3,  "e" : 4,  "e#" : 5,  "ex" : 6,
		"fbb" : 3,  "fb" : 4,  "f" : 5,  "f#" : 6,  "fx" : 7,
		"gbb" : 5,  "gb" : 6,  "g" : 7,  "g#" : 8,  "gx" : 9,
		"abb" : 7,  "ab" : 8,  "a" : 9,  "a#" : 10, "ax" : 11,
		"bbb" : 9,  "bb" : 10, "b" : 11, "b#" : 12, "bx" : 13,
	};

	/**
	 *  scale index to note (sharps)
	 *  @type  {Array}
	 */
	var scaleIndexToNote = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];

	/**
	 *  The [concert pitch](https://en.wikipedia.org/wiki/Concert_pitch)
	 *  A4's values in Hertz.
	 *  @type {Frequency}
	 *  @static
	 */
	Tone.Frequency.A4 = 440;

	/**
	 *  Convert a MIDI note to frequency value.
	 *  @param  {MIDI} midi The midi number to convert.
	 *  @return {Frequency} the corresponding frequency value
	 *  @example
	 * tone.midiToFrequency(69); // returns 440
	 */
	Tone.Frequency.prototype.midiToFrequency = function(midi){
		return Tone.Frequency.A4 * Math.pow(2, (midi - 69) / 12);
	};

	/**
	 *  Convert a frequency value to a MIDI note.
	 *  @param {Frequency} frequency The value to frequency value to convert.
	 *  @returns  {MIDI}
	 *  @example
	 * tone.midiToFrequency(440); // returns 69
	 */
	Tone.Frequency.prototype.frequencyToMidi = function(frequency){
		return 69 + 12 * Math.log(frequency / Tone.Frequency.A4) / Math.LN2;
	};

	return Tone.Frequency;
});<commit_msg>fixed rounding error when converting frequency to midi<commit_after>define(["Tone/core/Tone", "Tone/type/TimeBase"], function (Tone) {

	/**
	 *  @class Tone.Frequency is a primitive type for encoding Frequency values.
	 *         Eventually all time values are evaluated to hertz
	 *         using the `eval` method.
	 *  @constructor
	 *  @extends {Tone.TimeBase}
	 *  @param  {String|Number}  val    The time value.
	 *  @param  {String=}  units  The units of the value.
	 *  @example
	 * Tone.Frequency("C3") // 261
	 * Tone.Frequency(38, "midi") //
	 * Tone.Frequency("C3").transpose(4);
	 */
	Tone.Frequency = function(val, units){
		if (this instanceof Tone.Frequency){

			Tone.TimeBase.call(this, val, units);

		} else {
			return new Tone.Frequency(val, units);
		}
	};

	Tone.extend(Tone.Frequency, Tone.TimeBase);

	///////////////////////////////////////////////////////////////////////////
	//	AUGMENT BASE EXPRESSIONS
	///////////////////////////////////////////////////////////////////////////

	//clone the expressions so that
	//we can add more without modifying the original
	Tone.Frequency.prototype._primaryExpressions = Object.create(Tone.TimeBase.prototype._primaryExpressions);

	/*
	 *  midi type primary expression
	 *  @type {Object}
	 *  @private
	 */
	Tone.Frequency.prototype._primaryExpressions.midi = {
		regexp : /^(\d+(?:\.\d+)?midi)/,
		method : function(value){
			return this.midiToFrequency(value);
		}
	};

	/*
	 *  note type primary expression
	 *  @type {Object}
	 *  @private
	 */
	Tone.Frequency.prototype._primaryExpressions.note = {
		regexp : /^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i,
		method : function(pitch, octave){
			var index = noteToScaleIndex[pitch.toLowerCase()];
			var noteNumber = index + (parseInt(octave) + 1) * 12;
			return this.midiToFrequency(noteNumber);
		}
	};

	/*
	 *  BeatsBarsSixteenths type primary expression
	 *  @type {Object}
	 *  @private
	 */
	Tone.Frequency.prototype._primaryExpressions.tr = {
			regexp : /^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):?(\d+(?:\.\d+)?)?/,
			method : function(m, q, s){
			var total = 1;
			if (m && m !== "0"){
				total *= this._beatsToUnits(this._timeSignature() * parseFloat(m));
			}
			if (q && q !== "0"){
				total *= this._beatsToUnits(parseFloat(q));
			}
			if (s && s !== "0"){
				total *= this._beatsToUnits(parseFloat(s) / 4);
			}
			return total;
		}
	};

	///////////////////////////////////////////////////////////////////////////
	//	EXPRESSIONS
	///////////////////////////////////////////////////////////////////////////

	/**
	 *  Transposes the frequency by the given number of semitones.
	 *  @param  {Interval}  interval
	 *  @return  {Tone.Frequency} this
	 *  @example
	 * Tone.Frequency("A4").transpose(3); //"C5"
	 */
	Tone.Frequency.prototype.transpose = function(interval){
		this._expr = function(expr, interval){
			var val = expr();
			return val * Tone.intervalToFrequencyRatio(interval);
		}.bind(this, this._expr, interval);
		return this;
	};

	/**
	 *  Takes an array of semitone intervals and returns
	 *  an array of frequencies transposed by those intervals.
	 *  @param  {Array}  intervals
	 *  @return  {Tone.Frequency} this
	 *  @example
	 * Tone.Frequency("A4").harmonize([0, 3, 7]); //["A4", "C5", "E5"]
	 */
	Tone.Frequency.prototype.harmonize = function(intervals){
		this._expr = function(expr, intervals){
			var val = expr();
			var ret = [];
			for (var i = 0; i < intervals.length; i++){
				ret[i] = val * Tone.intervalToFrequencyRatio(intervals[i]);
			}
			return ret;
		}.bind(this, this._expr, intervals);
		return this;
	};

	///////////////////////////////////////////////////////////////////////////
	//	UNIT CONVERSIONS
	///////////////////////////////////////////////////////////////////////////

	/**
	 *  Return the value of the frequency as a MIDI note
	 *  @return  {MIDI}
	 *  @example
	 * Tone.Frequency("C4").toMidi(); //60
	 */
	Tone.Frequency.prototype.toMidi = function(){
		return this.frequencyToMidi(this.valueOf());
	};

	/**
	 *  Return the value of the frequency in Scientific Pitch Notation
	 *  @return  {Note}
	 *  @example
	 * Tone.Frequency(69, "midi").toNote(); //"A4"
	 */
	Tone.Frequency.prototype.toNote = function(){
		var freq = this.valueOf();
		var log = Math.log(freq / Tone.Frequency.A4) / Math.LN2;
		var noteNumber = Math.round(12 * log) + 57;
		var octave = Math.floor(noteNumber/12);
		if(octave < 0){
			noteNumber += -12 * octave;
		}
		var noteName = scaleIndexToNote[noteNumber % 12];
		return noteName + octave.toString();
	};

	/**
	 *  Return the duration of one cycle in seconds.
	 *  @return  {Seconds}
	 */
	Tone.Frequency.prototype.toSeconds = function(){
		return 1 / this.valueOf();
	};

	/**
	 *  Return the value in Hertz
	 *  @return  {Frequency}
	 */
	Tone.Frequency.prototype.toFrequency = function(){
		return this.valueOf();
	};

	/**
	 *  Return the duration of one cycle in ticks
	 *  @return  {Ticks}
	 */
	Tone.Frequency.prototype.toTicks = function(){
		var quarterTime = this._beatsToUnits(1);
		var quarters = this.valueOf() / quarterTime;
		return Math.floor(quarters * Tone.Transport.PPQ);
	};

	///////////////////////////////////////////////////////////////////////////
	//	UNIT CONVERSIONS HELPERS
	///////////////////////////////////////////////////////////////////////////

	/**
	 *  Returns the value of a frequency in the current units
	 *  @param {Frequency} freq
	 *  @return  {Number}
	 *  @private
	 */
	Tone.Frequency.prototype._frequencyToUnits = function(freq){
		return freq;
	};

	/**
	 *  Returns the value of a tick in the current time units
	 *  @param {Ticks} ticks
	 *  @return  {Number}
	 *  @private
	 */
	Tone.Frequency.prototype._ticksToUnits = function(ticks){
		return 1 / ((ticks * 60) / (Tone.Transport.bpm.value * Tone.Transport.PPQ));
	};

	/**
	 *  Return the value of the beats in the current units
	 *  @param {Number} beats
	 *  @return  {Number}
	 *  @private
	 */
	Tone.Frequency.prototype._beatsToUnits = function(beats){
		return 1 / Tone.TimeBase.prototype._beatsToUnits.call(this, beats);
	};

	/**
	 *  Returns the value of a second in the current units
	 *  @param {Seconds} seconds
	 *  @return  {Number}
	 *  @private
	 */
	Tone.Frequency.prototype._secondsToUnits = function(seconds){
		return 1 / seconds;
	};

	/**
	 *  The default units if none are given.
	 *  @private
	 */
	Tone.Frequency.prototype._defaultUnits = "hz";

	///////////////////////////////////////////////////////////////////////////
	//	FREQUENCY CONVERSIONS
	///////////////////////////////////////////////////////////////////////////

	/**
	 *  Note to scale index
	 *  @type  {Object}
	 */
	var noteToScaleIndex = {
		"cbb" : -2, "cb" : -1, "c" : 0,  "c#" : 1,  "cx" : 2,
		"dbb" : 0,  "db" : 1,  "d" : 2,  "d#" : 3,  "dx" : 4,
		"ebb" : 2,  "eb" : 3,  "e" : 4,  "e#" : 5,  "ex" : 6,
		"fbb" : 3,  "fb" : 4,  "f" : 5,  "f#" : 6,  "fx" : 7,
		"gbb" : 5,  "gb" : 6,  "g" : 7,  "g#" : 8,  "gx" : 9,
		"abb" : 7,  "ab" : 8,  "a" : 9,  "a#" : 10, "ax" : 11,
		"bbb" : 9,  "bb" : 10, "b" : 11, "b#" : 12, "bx" : 13,
	};

	/**
	 *  scale index to note (sharps)
	 *  @type  {Array}
	 */
	var scaleIndexToNote = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];

	/**
	 *  The [concert pitch](https://en.wikipedia.org/wiki/Concert_pitch)
	 *  A4's values in Hertz.
	 *  @type {Frequency}
	 *  @static
	 */
	Tone.Frequency.A4 = 440;

	/**
	 *  Convert a MIDI note to frequency value.
	 *  @param  {MIDI} midi The midi number to convert.
	 *  @return {Frequency} the corresponding frequency value
	 *  @example
	 * tone.midiToFrequency(69); // returns 440
	 */
	Tone.Frequency.prototype.midiToFrequency = function(midi){
		return Tone.Frequency.A4 * Math.pow(2, (midi - 69) / 12);
	};

	/**
	 *  Convert a frequency value to a MIDI note.
	 *  @param {Frequency} frequency The value to frequency value to convert.
	 *  @returns  {MIDI}
	 *  @example
	 * tone.midiToFrequency(440); // returns 69
	 */
	Tone.Frequency.prototype.frequencyToMidi = function(frequency){
		return 69 + Math.round(12 * Math.log(frequency / Tone.Frequency.A4) / Math.LN2);
	};

	return Tone.Frequency;
});
<|endoftext|>


<commit_before>var PdView = (function() {

    var d3 = d3 || d3_tiny;

    var ƒ = Rpd.unit,
        not = Rpd.not;

    var stopPropagation = Rpd.Render.stopPropagation;

    var editorNode;
    var startEditing = Kefir.emitter(),
        finishEditing = Kefir.emitter();

    var selection = null;
    var startSelection = Kefir.emitter(),
        finishSelection = Kefir.emitter();

    var editModeOn = Kefir.emitter(),
        editModeOff = Kefir.emitter();

    function PdView(defaultSize) {
        this.inEditMode = Kefir.merge([ editModeOn.map(ƒ(true)),
                                        editModeOff.map(ƒ(false)) ]).toProperty(ƒ(false));
        editorNode = d3.select(document.createElement('input'))
                           .attr('type', 'text')
                           .attr('class', 'rpd-pd-text-editor')
                           .style('width', '300px')
                           .style('height', (defaultSize.height + 1) + 'px')
                           .node();
        document.addEventListener('DOMContentLoaded', function() {
           d3.select(document.body)
             .append(d3.select(editorNode)
                       .style('display', 'none')
                       .style('position', 'absolute').node());
        });
    }

    PdView.prototype.addSelection = function(selectNode) {
        Kefir.fromEvents(selectNode, 'click')
             .filterBy(this.inEditMode.map(not))
             .map(stopPropagation)
             .onValue(function() {

                 startSelection.emit();
                 if (selection) d3.select(selection).classed('rpd-pd-selected', false);
                 selection = selectNode;
                 d3.select(selectNode).classed('rpd-pd-selected', true);

                 Kefir.fromEvents(document.body, 'click').take(1)
                      .onValue(function() {

                          d3.select(selectNode).classed('rpd-pd-selected', false);
                          selection = null;
                          finishSelection.emit();

                      });
             });
    }

    PdView.prototype.addEditor = function(selectNode, textNode, onSubmit) {
        var text = d3.select(textNode);
        var editor = d3.select(editorNode);
        Kefir.fromEvents(selectNode, 'click')
             .filterBy(this.inEditMode.map(not))
             .map(stopPropagation)
             .map(function() { return text.text(); })
             .onValue(function(textValue) {
                 startEditing.emit();

                 var brect = textNode.getBoundingClientRect();
                 editor.classed('rpd-pd-selected', true)
                       .style('top', (brect.top - 5) + 'px')
                       .style('left', (brect.left - 1) + 'px');
                 editor.node().value = textValue || '';
                 editorNode.setSelectionRange(0, editorNode.value.length);
                 text.text('').style('display', 'none');
                 editor.style('display', 'block')
                       .node().focus();

                 Kefir.merge([ Kefir.fromEvents(document.body, 'click'),
                               Kefir.fromEvents(editorNode, 'keydown')
                                    .map(function(evt) { return evt.keyCode; })
                                    .filter(function(key) { return key === 13; }),
                               startSelection
                             ]).take(1)
                      .onValue(function() {

                          var value = editor.node().value;

                          editorNode.blur();
                          text.text(value);
                          editor.node().value = '';
                          editor.style('display', 'none')
                                .classed('rpd-pd-selected', false);
                          text.style('display', 'block');

                          finishEditing.emit();

                          if (onSubmit) onSubmit(value);
                      });
             });
    }

    PdView.prototype.addEditModeSwitch = function(switchNode, targetNode) {
        Kefir.fromEvents(switchNode, 'click')
             .map(stopPropagation)
             .map(ƒ(true))
             .scan(Rpd.not) // will toggle between `true` and `false`
             .onValue(function(val) {
                 if (val) { editModeOn.emit(); } else { editModeOff.emit(); };
                 d3.select(targetNode).classed('rpd-pd-enabled', val);
             });
    }

    PdView.prototype.addNodeAppender = function(buttonNode, nodeType, targetPatch) {
        Kefir.fromEvents(buttonNode, 'click')
             .map(stopPropagation)
             .onValue(function() {
                 targetPatch.addNode(nodeType);
             });
    }

    PdView.prototype.addValueSend = function(sourceNode, node, inlet, getValue) {
        var styleTimeout;
        Kefir.fromEvents(sourceNode, 'click')
             .filterBy(this.inEditMode)
             .map(stopPropagation)
             .onValue(function() {
                 if (styleTimeout) clearTimeout(styleTimeout);
                 d3.select(sourceNode).classed('rpd-pd-send-value', true);
                 styleTimeout = setTimeout(function() {
                     d3.select(sourceNode).classed('rpd-pd-send-value', false);
                 }, 300);
                 //node.inlets[inlet].receive(getValue());
                 node.webPdObject.inlets[0].message(getValue());
             });
    }

    PdView.prototype.addSpinner = function(sourceNode) {
        return new Spinner(sourceNode, this.inEditMode);
    }

    PdView.prototype.measureText = function(textHolder) {
        var bbox = textHolder.node().getBBox();
        return { width: bbox.width, height: bbox.height };
    }

    // ================================ Spinner ====================================

    function extractPos(evt) { return { x: evt.clientX,
                                        y: evt.clientY }; };
    function Spinner(element, editMode) {
        this.element = element;
        this.value = 0;

        var spinner = this;

        var changes = Kefir.emitter();

        changes.onValue(function(value) {
            spinner.value = value;
        });

        Kefir.fromEvents(element, 'mousedown')
             .filterBy(editMode)
             .map(stopPropagation)
             .map(extractPos)
             .flatMap(function(startPos) {
                 var start = spinner.value;
                 return Kefir.fromEvents(document.body, 'mousemove')
                             .map(extractPos)
                             .takeUntilBy(Kefir.fromEvents(document.body, 'mouseup'))
                             .map(function(newPos) { return start + (startPos.y - newPos.y); })
                             .onValue(function(num) { changes.emit(num); })
             }).onEnd(function() {});
        //this.changes.onValue(function() {});

        this.changes = changes;
    }
    Spinner.prototype.getChangesStream = function() {
        return this.changes;
    }

    return PdView;

})();

var PdModel = (function() {

    var WebPd = window.Pd || null;
    if (!WebPd) throw new Error('Building PD Model requires WebPd present');

    var pdResolveObject = (function() {
        return function(patch, command, _arguments) {
            try {
                return patch.webPdPatch.createObject(command, _arguments);
            } catch (e) {
                if (!(e instanceof WebPd.core.errors.UnkownObjectError)) {
                    console.error(e, command, _arguments);
                }
                return null;
            }
        };

    })();

    var requestResolveEmitter = Kefir.emitter();
    var isResolvedEmitter = Kefir.emitter();

    var events = {
        // This event is emitted every time object node needs to be
        // resolved, i.e. to determine if we know command it contains,
        // emits PdObjectResolved event with a result, on each value.
        // event is: { node: node, command: [] }
        'object/request-resolve': requestResolveEmitter,
        // This event is emitted every time object node got (or lost)
        // the appropriate function, so the number of inlets/outlets
        // changed and style should be changed as well.
        // Renderer subscribes to this event.
        // event is: { node: node,
        //             command: command,
        //             arguments: [],
        //             definition: { inlets, outlets, process } }
        //       or: { node: node,
        //             command: command,
        //             arguments: [],
        //             definition: null }, if command wasn't succesfully parsed
        'object/is-resolved': isResolvedEmitter.toProperty()
    };

    requestResolveEmitter.map(function(value) {
        return {
            node: value.node, patch: value.node.patch,
            command: value.command, arguments: value.arguments,
            object: pdResolveObject(value.node.patch, value.command, value.arguments)
        };
    }).onValue(function(value) {
        isResolvedEmitter.emit(value);
    });

    function PdModel(patch, webPdPatch) {
        this.patch = patch;
        this.webPdPatch = webPdPatch;

        this.nodeToInlets = {};
        this.nodeToOutlets = {};
        //this.nodeToCommand = {};

        this.webPdDummy = { patch: webPdPatch };
    };

    var DspInlet = Pd.core.portlets.DspInlet,
        DspOutlet = Pd.core.portlets.DspOutlet;

    function getInletType(pdInlet) {
        return (pdInlet instanceof DspInlet) ? 'pd/dsp' : 'pd/value';
    }
    function getOutletType(pdOutlet) {
        return (pdOutlet instanceof DspOutlet) ? 'pd/dsp' : 'pd/value';
    }

    PdModel.prototype.connectToWebPd = function(inlets, outlets, webPdInlets, webPdOutlets) { // FIXME: remove label
        if ((inlets && !webPdInlets) ||
            (inlets && (inlets.length !== webPdInlets.length))) throw new Error('inlets number not matches to WebPd inlets number');
        if ((outlets && !webPdOutlets) ||
            (outlets && (outlets.length !== webPdOutlets.length))) throw new Error('outlets number not matches to WebPd outlets number');
        if (inlets && webPdInlets) {
            inlets.forEach(function(inlet, idx) {
                if (inlet.type === 'pd/dsp') return;
                // TODO: disconnect/unsubscribe previously connected links
                var webPdInlet = webPdInlets[idx];
                if (!webPdInlet) throw new Error('Failed to find WebPd inlet corresponding to inlet ' + idx);
                inlet.event['inlet/update'].onValue(function(val) {
                    webPdInlet.message(val.get());
                });
            });
        }
        if (outlets && webPdOutlets) {
            var dummy = this.webPdDummy;
            outlets.forEach(function(outlet, idx) {
                if (outlet.type === 'pd/dsp') return;
                var receiver = new WebPd.core.portlets.Inlet(dummy);
                receiver.message = function(args) {
                    outlet.send(PdValue.from(args));
                };
                // TODO: disconnect previously connected links
                if (webPdOutlets[idx]) {
                    webPdOutlets[idx].connect(receiver);
                } else throw new Error('Failed to find WebPd outlet corresponding to outlet ' + idx);
            });
        }
    }

    // add required inlets and outlets to the node using the properties from resove-event
    PdModel.prototype.applyDefinition = function(node, command, _arguments, object) {
        //this.nodeToCommand[node.id] = command;

        var nodeInlets = this.nodeToInlets[node.id],
            nodeOutlets = this.nodeToOutlets[node.id];

        //if (this.nodeToCommand[node.id] === command) return;

        if (nodeInlets) {
            nodeInlets.forEach(function(inlet) { node.removeInlet(inlet); });
            nodeInlets = null;
        }
        if (nodeOutlets) {
            nodeOutlets.forEach(function(outlet) { node.removeOutlet(outlet); });
            nodeOutlets = null;
        }
        if (!object) return;

        var pdInlets = object.inlets || {},
            pdOutlets = object.outlets || {};
        var savedInlets = [], savedOutlets = [];
        pdInlets.forEach(function(pdInlet, idx) {
            savedInlets.push(node.addInlet(getInletType(pdInlet), idx.toString()));
        });
        pdOutlets.forEach(function(pdOutlet, idx) {
            savedOutlets.push(node.addOutlet(getOutletType(pdOutlet), idx.toString()));
        });
        this.nodeToInlets[node.id] = savedInlets.length ? savedInlets : null;
        this.nodeToOutlets[node.id] = savedOutlets.length ? savedOutlets : null;

        this.connectToWebPd(savedInlets, savedOutlets,
                            object.inlets, object.outlets,
                            '<'+node.id+'> ' + (object.prefix || command || node.type));
    };

    PdModel.prototype.requestResolve = function(node, command, _arguments) {
        requestResolveEmitter.emit({ node: node,
                                     command: command,
                                     arguments: _arguments });
    };

    PdModel.prototype.whenResolved = function(node, callback) {
        isResolvedEmitter.filter(function(value) {
            return value.node.id === node.id;
        }).onValue(callback);
    };

    PdModel.prototype.initMessage = function(node, _arguments) {
        node.inlets['init'].receive(PdValue.from(_arguments));
    };

    PdModel.getReceivingInlet = function(node) {
        return node.inlets['receive'];
    };

    PdModel.getSendingOutlet = function(node) {
        return node.outlets['send'];
    };

    PdModel.TYPE_MAP = {
        'obj':        'pd/object',
        'msg':        'pd/message',
        'floatatom':  'pd/number',
        'symbolatom': 'pd/symbol',
        'text':       'pd/comment',
        'bng':        'pd/bang',
        'tgl':        'pd/toggle',
        'nbx':        null, // 'pd/number-2'
        'vsl':        null, // 'pd/vslider'
        'hsl':        null, // 'pd/hslider'
        'vradio':     null, // 'pd/vradio'
        'hradio':     null, // 'pd/hradio'
        'vu':         null, // 'pd/vumeter'
        'cnv':        null, // 'pd/canvas'
        'graph':      null, // 'pd/graph'
        'array':      null  // 'pd/array'
    };

    return PdModel;

})();

PdValue = (function() {

    function PdValue(vals) {
        this.value = vals;
    };

    PdValue.prototype.get = function() {
        return this.value;
    };

    PdValue.prototype.isBang = function() {
        return (this.value[0] === 'bang');
    };

    PdValue.isPdValue = function(test) {
        return test instanceof PdValue;
    };

    PdValue.from = function(vals) {
        return new PdValue(vals);
    };

    PdValue.bang = function() {
        return new PdValue(['bang']);
    };

    return PdValue;

})();
<commit_msg>fix inlet removing error when previous object state was resolved to no-inlet/no-outlet object (#251)<commit_after>var PdView = (function() {

    var d3 = d3 || d3_tiny;

    var ƒ = Rpd.unit,
        not = Rpd.not;

    var stopPropagation = Rpd.Render.stopPropagation;

    var editorNode;
    var startEditing = Kefir.emitter(),
        finishEditing = Kefir.emitter();

    var selection = null;
    var startSelection = Kefir.emitter(),
        finishSelection = Kefir.emitter();

    var editModeOn = Kefir.emitter(),
        editModeOff = Kefir.emitter();

    function PdView(defaultSize) {
        this.inEditMode = Kefir.merge([ editModeOn.map(ƒ(true)),
                                        editModeOff.map(ƒ(false)) ]).toProperty(ƒ(false));
        editorNode = d3.select(document.createElement('input'))
                           .attr('type', 'text')
                           .attr('class', 'rpd-pd-text-editor')
                           .style('width', '300px')
                           .style('height', (defaultSize.height + 1) + 'px')
                           .node();
        document.addEventListener('DOMContentLoaded', function() {
           d3.select(document.body)
             .append(d3.select(editorNode)
                       .style('display', 'none')
                       .style('position', 'absolute').node());
        });
    }

    PdView.prototype.addSelection = function(selectNode) {
        Kefir.fromEvents(selectNode, 'click')
             .filterBy(this.inEditMode.map(not))
             .map(stopPropagation)
             .onValue(function() {

                 startSelection.emit();
                 if (selection) d3.select(selection).classed('rpd-pd-selected', false);
                 selection = selectNode;
                 d3.select(selectNode).classed('rpd-pd-selected', true);

                 Kefir.fromEvents(document.body, 'click').take(1)
                      .onValue(function() {

                          d3.select(selectNode).classed('rpd-pd-selected', false);
                          selection = null;
                          finishSelection.emit();

                      });
             });
    }

    PdView.prototype.addEditor = function(selectNode, textNode, onSubmit) {
        var text = d3.select(textNode);
        var editor = d3.select(editorNode);
        Kefir.fromEvents(selectNode, 'click')
             .filterBy(this.inEditMode.map(not))
             .map(stopPropagation)
             .map(function() { return text.text(); })
             .onValue(function(textValue) {
                 startEditing.emit();

                 var brect = textNode.getBoundingClientRect();
                 editor.classed('rpd-pd-selected', true)
                       .style('top', (brect.top - 5) + 'px')
                       .style('left', (brect.left - 1) + 'px');
                 editor.node().value = textValue || '';
                 editorNode.setSelectionRange(0, editorNode.value.length);
                 text.text('').style('display', 'none');
                 editor.style('display', 'block')
                       .node().focus();

                 Kefir.merge([ Kefir.fromEvents(document.body, 'click'),
                               Kefir.fromEvents(editorNode, 'keydown')
                                    .map(function(evt) { return evt.keyCode; })
                                    .filter(function(key) { return key === 13; }),
                               startSelection
                             ]).take(1)
                      .onValue(function() {

                          var value = editor.node().value;

                          editorNode.blur();
                          text.text(value);
                          editor.node().value = '';
                          editor.style('display', 'none')
                                .classed('rpd-pd-selected', false);
                          text.style('display', 'block');

                          finishEditing.emit();

                          if (onSubmit) onSubmit(value);
                      });
             });
    }

    PdView.prototype.addEditModeSwitch = function(switchNode, targetNode) {
        Kefir.fromEvents(switchNode, 'click')
             .map(stopPropagation)
             .map(ƒ(true))
             .scan(Rpd.not) // will toggle between `true` and `false`
             .onValue(function(val) {
                 if (val) { editModeOn.emit(); } else { editModeOff.emit(); };
                 d3.select(targetNode).classed('rpd-pd-enabled', val);
             });
    }

    PdView.prototype.addNodeAppender = function(buttonNode, nodeType, targetPatch) {
        Kefir.fromEvents(buttonNode, 'click')
             .map(stopPropagation)
             .onValue(function() {
                 targetPatch.addNode(nodeType);
             });
    }

    PdView.prototype.addValueSend = function(sourceNode, node, inlet, getValue) {
        var styleTimeout;
        Kefir.fromEvents(sourceNode, 'click')
             .filterBy(this.inEditMode)
             .map(stopPropagation)
             .onValue(function() {
                 if (styleTimeout) clearTimeout(styleTimeout);
                 d3.select(sourceNode).classed('rpd-pd-send-value', true);
                 styleTimeout = setTimeout(function() {
                     d3.select(sourceNode).classed('rpd-pd-send-value', false);
                 }, 300);
                 //node.inlets[inlet].receive(getValue());
                 node.webPdObject.inlets[0].message(getValue());
             });
    }

    PdView.prototype.addSpinner = function(sourceNode) {
        return new Spinner(sourceNode, this.inEditMode);
    }

    PdView.prototype.measureText = function(textHolder) {
        var bbox = textHolder.node().getBBox();
        return { width: bbox.width, height: bbox.height };
    }

    // ================================ Spinner ====================================

    function extractPos(evt) { return { x: evt.clientX,
                                        y: evt.clientY }; };
    function Spinner(element, editMode) {
        this.element = element;
        this.value = 0;

        var spinner = this;

        var changes = Kefir.emitter();

        changes.onValue(function(value) {
            spinner.value = value;
        });

        Kefir.fromEvents(element, 'mousedown')
             .filterBy(editMode)
             .map(stopPropagation)
             .map(extractPos)
             .flatMap(function(startPos) {
                 var start = spinner.value;
                 return Kefir.fromEvents(document.body, 'mousemove')
                             .map(extractPos)
                             .takeUntilBy(Kefir.fromEvents(document.body, 'mouseup'))
                             .map(function(newPos) { return start + (startPos.y - newPos.y); })
                             .onValue(function(num) { changes.emit(num); })
             }).onEnd(function() {});
        //this.changes.onValue(function() {});

        this.changes = changes;
    }
    Spinner.prototype.getChangesStream = function() {
        return this.changes;
    }

    return PdView;

})();

var PdModel = (function() {

    var WebPd = window.Pd || null;
    if (!WebPd) throw new Error('Building PD Model requires WebPd present');

    var pdResolveObject = (function() {
        return function(patch, command, _arguments) {
            try {
                return patch.webPdPatch.createObject(command, _arguments);
            } catch (e) {
                if (!(e instanceof WebPd.core.errors.UnkownObjectError)) {
                    console.error(e, command, _arguments);
                }
                return null;
            }
        };

    })();

    var requestResolveEmitter = Kefir.emitter();
    var isResolvedEmitter = Kefir.emitter();

    var events = {
        // This event is emitted every time object node needs to be
        // resolved, i.e. to determine if we know command it contains,
        // emits PdObjectResolved event with a result, on each value.
        // event is: { node: node, command: [] }
        'object/request-resolve': requestResolveEmitter,
        // This event is emitted every time object node got (or lost)
        // the appropriate function, so the number of inlets/outlets
        // changed and style should be changed as well.
        // Renderer subscribes to this event.
        // event is: { node: node,
        //             command: command,
        //             arguments: [],
        //             definition: { inlets, outlets, process } }
        //       or: { node: node,
        //             command: command,
        //             arguments: [],
        //             definition: null }, if command wasn't succesfully parsed
        'object/is-resolved': isResolvedEmitter.toProperty()
    };

    requestResolveEmitter.map(function(value) {
        return {
            node: value.node, patch: value.node.patch,
            command: value.command, arguments: value.arguments,
            object: pdResolveObject(value.node.patch, value.command, value.arguments)
        };
    }).onValue(function(value) {
        isResolvedEmitter.emit(value);
    });

    function PdModel(patch, webPdPatch) {
        this.patch = patch;
        this.webPdPatch = webPdPatch;

        this.nodeToInlets = {};
        this.nodeToOutlets = {};
        //this.nodeToCommand = {};

        this.webPdDummy = { patch: webPdPatch };
    };

    var DspInlet = Pd.core.portlets.DspInlet,
        DspOutlet = Pd.core.portlets.DspOutlet;

    function getInletType(pdInlet) {
        return (pdInlet instanceof DspInlet) ? 'pd/dsp' : 'pd/value';
    }
    function getOutletType(pdOutlet) {
        return (pdOutlet instanceof DspOutlet) ? 'pd/dsp' : 'pd/value';
    }

    PdModel.prototype.connectToWebPd = function(inlets, outlets, webPdInlets, webPdOutlets) { // FIXME: remove label
        if ((inlets && !webPdInlets) ||
            (inlets && (inlets.length !== webPdInlets.length))) throw new Error('inlets number not matches to WebPd inlets number');
        if ((outlets && !webPdOutlets) ||
            (outlets && (outlets.length !== webPdOutlets.length))) throw new Error('outlets number not matches to WebPd outlets number');
        if (inlets && webPdInlets) {
            inlets.forEach(function(inlet, idx) {
                if (inlet.type === 'pd/dsp') return;
                // TODO: disconnect/unsubscribe previously connected links
                var webPdInlet = webPdInlets[idx];
                if (!webPdInlet) throw new Error('Failed to find WebPd inlet corresponding to inlet ' + idx);
                inlet.event['inlet/update'].onValue(function(val) {
                    webPdInlet.message(val.get());
                });
            });
        }
        if (outlets && webPdOutlets) {
            var dummy = this.webPdDummy;
            outlets.forEach(function(outlet, idx) {
                if (outlet.type === 'pd/dsp') return;
                var receiver = new WebPd.core.portlets.Inlet(dummy);
                receiver.message = function(args) {
                    outlet.send(PdValue.from(args));
                };
                // TODO: disconnect previously connected links
                if (webPdOutlets[idx]) {
                    webPdOutlets[idx].connect(receiver);
                } else throw new Error('Failed to find WebPd outlet corresponding to outlet ' + idx);
            });
        }
    }

    // add required inlets and outlets to the node using the properties from resove-event
    PdModel.prototype.applyDefinition = function(node, command, _arguments, object) {
        //this.nodeToCommand[node.id] = command;

        var nodeInlets = this.nodeToInlets[node.id],
            nodeOutlets = this.nodeToOutlets[node.id];

        //if (this.nodeToCommand[node.id] === command) return;

        if (nodeInlets) {
            nodeInlets.forEach(function(inlet) { node.removeInlet(inlet); });
            this.nodeToInlets[node.id] = null;
        }
        if (nodeOutlets) {
            nodeOutlets.forEach(function(outlet) { node.removeOutlet(outlet); });
            this.nodeToOutlets[node.id] = null;
        }
        if (!object) return;

        var pdInlets = object.inlets || {},
            pdOutlets = object.outlets || {};
        var savedInlets = [], savedOutlets = [];
        pdInlets.forEach(function(pdInlet, idx) {
            savedInlets.push(node.addInlet(getInletType(pdInlet), idx.toString()));
        });
        pdOutlets.forEach(function(pdOutlet, idx) {
            savedOutlets.push(node.addOutlet(getOutletType(pdOutlet), idx.toString()));
        });
        this.nodeToInlets[node.id] = savedInlets.length ? savedInlets : null;
        this.nodeToOutlets[node.id] = savedOutlets.length ? savedOutlets : null;

        this.connectToWebPd(savedInlets, savedOutlets,
                            object.inlets, object.outlets,
                            '<'+node.id+'> ' + (object.prefix || command || node.type));
    };

    PdModel.prototype.requestResolve = function(node, command, _arguments) {
        requestResolveEmitter.emit({ node: node,
                                     command: command,
                                     arguments: _arguments });
    };

    PdModel.prototype.whenResolved = function(node, callback) {
        isResolvedEmitter.filter(function(value) {
            return value.node.id === node.id;
        }).onValue(callback);
    };

    PdModel.prototype.initMessage = function(node, _arguments) {
        node.inlets['init'].receive(PdValue.from(_arguments));
    };

    PdModel.getReceivingInlet = function(node) {
        return node.inlets['receive'];
    };

    PdModel.getSendingOutlet = function(node) {
        return node.outlets['send'];
    };

    PdModel.TYPE_MAP = {
        'obj':        'pd/object',
        'msg':        'pd/message',
        'floatatom':  'pd/number',
        'symbolatom': 'pd/symbol',
        'text':       'pd/comment',
        'bng':        'pd/bang',
        'tgl':        'pd/toggle',
        'nbx':        null, // 'pd/number-2'
        'vsl':        null, // 'pd/vslider'
        'hsl':        null, // 'pd/hslider'
        'vradio':     null, // 'pd/vradio'
        'hradio':     null, // 'pd/hradio'
        'vu':         null, // 'pd/vumeter'
        'cnv':        null, // 'pd/canvas'
        'graph':      null, // 'pd/graph'
        'array':      null  // 'pd/array'
    };

    return PdModel;

})();

PdValue = (function() {

    function PdValue(vals) {
        this.value = vals;
    };

    PdValue.prototype.get = function() {
        return this.value;
    };

    PdValue.prototype.isBang = function() {
        return (this.value[0] === 'bang');
    };

    PdValue.isPdValue = function(test) {
        return test instanceof PdValue;
    };

    PdValue.from = function(vals) {
        return new PdValue(vals);
    };

    PdValue.bang = function() {
        return new PdValue(['bang']);
    };

    return PdValue;

})();
<|endoftext|>


<commit_before>/**
 * Edition field for a file - a file uploader.
 *
 * @example <ma-file-field field="field"></ma-file-field>
 */
export default function maFileField(Upload) {
    return {
        scope: {
            'field': '&',
            'value': '='
        },
        restrict: 'E',
        link: {
            pre: function(scope) {
                var uploadInformation = scope.field().uploadInformation();
                if (!uploadInformation.hasOwnProperty('url')) {
                    throw new Error('You must provide a URL property to allow the upload of files.');
                }

                scope.multiple = uploadInformation.hasOwnProperty('multiple') ? uploadInformation.multiple : false;
                scope.accept = "*";
                if (uploadInformation.hasOwnProperty('accept')) {
                    scope.accept = uploadInformation.accept;
                }
                scope.apifilename = uploadInformation.hasOwnProperty('apifilename') ? uploadInformation.apifilename : false;

                var files = scope.value ? scope.value.split(',') : [];
                scope.files = {};
                for (var file in files) {
                    scope.files[files[file]] = {
                        "name": files[file],
                        "progress": 0
                    };
                }
            },
            post: function(scope, element) {
                var field = scope.field();
                scope.name = field.name();
                scope.v = field.validation();
                if (scope.value) {
                    scope.v.required = false;
                }
                var input = element.find('input')[0];
                var attributes = field.attributes();
                for (var name in attributes) {
                    input.setAttribute(name, attributes[name]);
                }

                scope.fileSelected = function(selectedFiles) {
                    if (!selectedFiles || !selectedFiles.length) {
                        return;
                    }

                    var uploadParams;

                    scope.files = {};
                    for (var file in selectedFiles) {
                        uploadParams = angular.copy(scope.field().uploadInformation());
                        uploadParams.file = selectedFiles[file];
                        Upload
                            .upload(uploadParams)
                            .progress(function(evt) {
                                scope.files[evt.config.file.name] = {
                                    "name": evt.config.file.name,
                                    "progress": Math.min(100, parseInt(100.0 * evt.loaded / evt.total))
                                };
                            })
                            .success(function(data, status, headers, config) {
                                scope.files[config.file.name] = {
                                    "name": scope.apifilename ? data[scope.apifilename] : config.file.name,
                                    "progress": 0
                                };
                                if (scope.apifilename) {
                                    var apiNames = Object.keys(scope.files).map(function(fileindex) {
                                        return scope.files[fileindex].name;
                                    });
                                    scope.value = apiNames.join(',');
                                } else {
                                    scope.value = Object.keys(scope.files).join(',');
                                }
                            })
                            .error(function(data, status, headers, config) {
                                delete scope.files[config.file.name];

                                scope.value = Object.keys(scope.files).join(',');
                            });
                    }
                };

                scope.selectFile = function () {
                    input.click();
                };
            }
        },
        template:
`

{{ file.name }}

<input type="file" ngf-multiple="multiple" accept="{{ accept }}" ngf-select="fileSelected($files)"
       id="{{ name }}" name="{{ name }}" ng-required="v.required" style="display:none" />`
    };
}

maFileField.$inject = ['Upload'];
<commit_msg>maFileField: Close em and small tags in template<commit_after>/**
 * Edition field for a file - a file uploader.
 *
 * @example <ma-file-field field="field"></ma-file-field>
 */
export default function maFileField(Upload) {
    return {
        scope: {
            'field': '&',
            'value': '='
        },
        restrict: 'E',
        link: {
            pre: function(scope) {
                var uploadInformation = scope.field().uploadInformation();
                if (!uploadInformation.hasOwnProperty('url')) {
                    throw new Error('You must provide a URL property to allow the upload of files.');
                }

                scope.multiple = uploadInformation.hasOwnProperty('multiple') ? uploadInformation.multiple : false;
                scope.accept = "*";
                if (uploadInformation.hasOwnProperty('accept')) {
                    scope.accept = uploadInformation.accept;
                }
                scope.apifilename = uploadInformation.hasOwnProperty('apifilename') ? uploadInformation.apifilename : false;

                var files = scope.value ? scope.value.split(',') : [];
                scope.files = {};
                for (var file in files) {
                    scope.files[files[file]] = {
                        "name": files[file],
                        "progress": 0
                    };
                }
            },
            post: function(scope, element) {
                var field = scope.field();
                scope.name = field.name();
                scope.v = field.validation();
                if (scope.value) {
                    scope.v.required = false;
                }
                var input = element.find('input')[0];
                var attributes = field.attributes();
                for (var name in attributes) {
                    input.setAttribute(name, attributes[name]);
                }

                scope.fileSelected = function(selectedFiles) {
                    if (!selectedFiles || !selectedFiles.length) {
                        return;
                    }

                    var uploadParams;

                    scope.files = {};
                    for (var file in selectedFiles) {
                        uploadParams = angular.copy(scope.field().uploadInformation());
                        uploadParams.file = selectedFiles[file];
                        Upload
                            .upload(uploadParams)
                            .progress(function(evt) {
                                scope.files[evt.config.file.name] = {
                                    "name": evt.config.file.name,
                                    "progress": Math.min(100, parseInt(100.0 * evt.loaded / evt.total))
                                };
                            })
                            .success(function(data, status, headers, config) {
                                scope.files[config.file.name] = {
                                    "name": scope.apifilename ? data[scope.apifilename] : config.file.name,
                                    "progress": 0
                                };
                                if (scope.apifilename) {
                                    var apiNames = Object.keys(scope.files).map(function(fileindex) {
                                        return scope.files[fileindex].name;
                                    });
                                    scope.value = apiNames.join(',');
                                } else {
                                    scope.value = Object.keys(scope.files).join(',');
                                }
                            })
                            .error(function(data, status, headers, config) {
                                delete scope.files[config.file.name];

                                scope.value = Object.keys(scope.files).join(',');
                            });
                    }
                };

                scope.selectFile = function () {
                    input.click();
                };
            }
        },
        template:
`

{{ file.name }}

<input type="file" ngf-multiple="multiple" accept="{{ accept }}" ngf-select="fileSelected($files)"
       id="{{ name }}" name="{{ name }}" ng-required="v.required" style="display:none" />`
    };
}

maFileField.$inject = ['Upload'];
<|endoftext|>