<commit_before>/* global AudioContext */
const regl = require('../regl')()
const perspective = require('gl-mat4/perspective')
const lookAt = require('gl-mat4/lookAt')

const N = 512

require('resl')({
  manifest: {
    song: {
      type: 'audio',
      src: 'assets/8bitpeoples-bamboo-cactus.mp3',
      stream: true
    }
  },

  onDone: ({song}) => {
    const context = new AudioContext()
    const source = context.createMediaElementSource(song)
    const analyser = context.createAnalyser()
    source.connect(analyser)
    source.connect(context.destination)

    song.play()

    const terrainData = new Uint8Array(N * N)
    terrainData.fill(128)
    const terrainTexture = regl.texture()

    const drawTerrain = regl({
      vert: `
      precision highp float;

      #define N float(${N})
      #define WEIGHT1 vec4(-1.0, 8.0, -8.0, 1.0)
      #define WEIGHT2 vec4(-1.0, 16.0, 16.0, -1.0)

      attribute vec2 vertId;

      uniform mat4 projection, view;
      uniform float offsetRow;
      uniform sampler2D terrain;

      varying vec3 grad;
      varying float curvature;

      float f(vec2 x) {
        return 0.5 * texture2D(terrain, x + vec2(0.0, offsetRow / N)).r;
      }

      vec4 stencil(vec2 x, vec2 d) {
        return vec4(
          f(x - 2.0 * d),
          f(x - d),
          f(x + d),
          f(x + 2.0 * d));
      }

      void main () {
        vec2 uv = vertId / N;

        float h0 = f(uv);
        vec4 hx = stencil(uv, vec2(1.0 / N, 0.0));
        vec4 hy = stencil(uv, vec2(0.0, 1.0 / N));

        grad = normalize(vec3(
          dot(WEIGHT1, hx),
          dot(WEIGHT1, hy),
          1.0));

        curvature =
          max((dot(WEIGHT2, hx) - 30.0 * h0),
              (dot(WEIGHT2, hy) - 30.0 * h0));

        gl_Position = projection * view * vec4(uv, h0, 1);
      }`,

      frag: `
      precision highp float;

      uniform vec3 lightDir, color;

      varying vec3 grad;
      varying float curvature;

      void main () {
        float ao = max(1.0 - 0.8 * max(curvature, 0.0), 0.25);
        float light = ao;
        gl_FragColor = vec4(light * color, 1);
      }`,

      attributes: {
        vertId: Array(N * N).fill().map((_, i) => {
          const x = Math.floor(i / N)
          const y = i % N
          return [
            x, y,
            x + 1, y,
            x, y + 1,
            x, y + 1,
            x + 1, y + 1,
            x + 1, y
          ]
        })
      },

      uniforms: {
        offsetRow: ({count}) => count % N,
        terrain: terrainTexture,
        projection: ({viewportWidth, viewportHeight}) =>
          perspective([],
            Math.PI / 8,
            viewportWidth / viewportHeight,
            0.01,
            1000),
        view: ({count}) =>
          lookAt([],
            [0.5, 0, 0.6],
            [0.5, 1, 0],
            [0, 0, 1]),
        lightDir: [-1, -1, 1],
        color: [0.6, 0.4, 1.0]
      },

      count: N * N * 6
    })

    regl.frame(({count}) => {
      const offsetRow = count % N

      // Clear background
      regl.clear({
        color: [0, 0, 0, 1],
        depth: 1
      })

      // Update texture
      analyser.getByteTimeDomainData(
        terrainData.subarray(offsetRow * N, (offsetRow + 1) * N))
      terrainTexture({
        mag: 'linear',
        min: 'linear',
        wrap: 'repeat',
        shape: [N, N, 1],
        data: terrainData
      })

      // Render terrain
      drawTerrain()
    })
  }
})
<commit_msg>improve audio example<commit_after>/* global AudioContext */
const regl = require('../regl')()
const perspective = require('gl-mat4/perspective')
const lookAt = require('gl-mat4/lookAt')

const N = 512

require('resl')({
  manifest: {
    song: {
      type: 'audio',
      src: 'assets/8bitpeoples-bamboo-cactus.mp3',
      stream: true
    }
  },

  onDone: ({song}) => {
    const context = new AudioContext()
    const source = context.createMediaElementSource(song)
    const analyser = context.createAnalyser()
    source.connect(analyser)
    source.connect(context.destination)

    song.play()

    const terrainTexture = regl.texture({
      data: (new Uint8Array(N * N)).fill(128),
      radius: N,
      channels: 1,
      min: 'linear',
      mag: 'linear',
      wrap: 'repeat'
    })

    const colorTexture = regl.texture({
      width: N / 4,
      height: 1,
      channels: 4,
      min: 'linear',
      mag: 'linear',
      wrap: 'repeat'
    })

    const drawTerrain = regl({
      vert: `
      precision highp float;

      #define N float(${N})
      #define WEIGHT1 vec4(-1.0, 8.0, -8.0, 1.0)
      #define WEIGHT2 vec4(-1.0, 16.0, 16.0, -1.0)

      attribute vec2 vertId;

      uniform float t;
      uniform mat4 projection, view;
      uniform vec3 lightPosition;
      uniform float offsetRow;
      uniform sampler2D terrain, color;

      varying vec3 grad, fragColor, eyeDir, lightDir;
      varying float curvature;

      float f(vec2 x) {
        return 0.025 * texture2D(terrain, x).r;
      }

      vec4 stencil(vec2 x, vec2 d) {
        return vec4(
          f(x - 2.0 * d),
          f(x - d),
          f(x + d),
          f(x + 2.0 * d));
      }

      void main () {
        vec2 uv = (vertId + vec2(0.0, offsetRow)) / N;

        float h0 = f(uv);
        vec4 hx = stencil(uv, vec2(1.0 / N, 0.0));
        vec4 hy = stencil(uv, vec2(0.0, 1.0 / N));

        grad = normalize(vec3(
          dot(WEIGHT1, hx),
          dot(WEIGHT1, hy),
          0.025));

        curvature =
          max(max((dot(WEIGHT2, hx) - 30.0 * h0),
              (dot(WEIGHT2, hy) - 30.0 * h0)), 0.0);

        vec3 pos = vec3(vertId / N, h0 + 0.4);
        lightDir = lightPosition - pos;

        vec4 viewPos = view * vec4(pos, 1);
        gl_Position = projection * viewPos;
        eyeDir = viewPos.xyz / viewPos.w;
        fragColor = 1.25 * texture2D(color, vec2(uv.y, 0)).rgb;
      }`,

      frag: `
      precision highp float;

      varying vec3 grad, fragColor, eyeDir, lightDir;
      varying float curvature;

      void main () {
        vec3 N = normalize(grad);
        vec3 V = normalize(eyeDir);
        vec3 L = normalize(lightDir);

        vec3 H = normalize(V + L);

        float ao = 1.0 - curvature;
        float diffuse = max(dot(L, N), 0.0);
        float fresnel = 0.1 + 0.5 * pow(1.0 - max(dot(H, V), 0.0), 5.0);
        float light = 0.25 * ao + 0.8 * diffuse + fresnel;
        gl_FragColor = vec4(light * fragColor, 1);
      }`,

      attributes: {
        vertId: Array(4 * N * N).fill().map((_, i) => {
          const x = 0.5 * Math.floor(i / (2 * N))
          const y = 0.5 * (i % (2 * N))
          return [
            x, y,
            x + 0.5, y,
            x, y + 0.5,
            x, y + 0.5,
            x + 0.5, y + 0.5,
            x + 0.5, y
          ]
        })
      },

      uniforms: {
        offsetRow: ({count}) => count % N,
        terrain: terrainTexture,
        projection: ({viewportWidth, viewportHeight}) =>
          perspective([],
            Math.PI / 8,
            viewportWidth / viewportHeight,
            0.01,
            1000),
        view: ({count}) =>
          lookAt([],
            [ 0.5 + 0.2 * Math.cos(0.001 * count),
              1,
              0.6 + 0.1 * Math.cos(0.003 * count + 2.4) ],
            [0.5, 0, 0],
            [0, 0, 1]),
        lightPosition: ({count}) => [
          0.5 + Math.sin(0.01 * count),
          1.0 + Math.cos(0.01 * count),
          1.0 + 0.6 * Math.cos(0.04 * count) ],
        color: colorTexture,
        t: ({count}) => 0.01 * count
      },

      elements: null,
      instances: -1,

      count: 4 * N * N * 6
    })

    const timeSamples = {
      width: N,
      height: 1,
      data: new Uint8Array(N)
    }
    const freqSamples = new Uint8Array(N)
    regl.frame(({count}) => {
      const offsetRow = count % N

      // Clear background
      regl.clear({
        color: [0, 0, 0, 1],
        depth: 1
      })

      // Update texture
      analyser.getByteTimeDomainData(timeSamples.data)
      terrainTexture.subimage(timeSamples, 0, offsetRow)

      // Update colors
      analyser.getByteFrequencyData(freqSamples)
      colorTexture.subimage(freqSamples)

      // Render terrain
      drawTerrain()
    })
  }
})
<|endoftext|>


<commit_before>// @flow
import * as React from 'react'
import * as Kb from '../../common-adapters'
import * as Types from '../../constants/types/chat2'
import * as Constants from '../../constants/chat2'
import * as Styles from '../../styles'
import SelectableSmallTeam from '../selectable-small-team-container'
import SelectableBigTeamChannel from '../selectable-big-team-channel-container'
import {inboxWidth} from '../inbox/row/sizes'
import {Owl} from '../inbox/owl'

type NameResult = {|
  conversationIDKey: Types.ConversationIDKey,
  type: 'big' | 'small',
|}

type TextResult = {|
  conversationIDKey: Types.ConversationIDKey,
  type: 'big' | 'small',
  numHits: number,
  query: string,
|}

type Props = {|
  header?: React.Node,
  indexPercent: number,
  nameStatus: Types.InboxSearchStatus,
  nameResults: Array<NameResult>,
  nameResultsUnread: boolean,
  onCancel: () => void,
  onSelectConversation: (Types.ConversationIDKey, number, string) => void,
  selectedIndex: number,
  textStatus: Types.InboxSearchStatus,
  textResults: Array<TextResult>,
  query: string,
|}

type State = {
  nameCollapsed: boolean,
  textCollapsed: boolean,
}

class InboxSearch extends React.Component<Props, State> {
  state = {nameCollapsed: false, textCollapsed: false}

  _renderHit = ({item, section, index}) => {
    const realIndex = index + section.indexOffset
    return item.type === 'big' ? (
      <SelectableBigTeamChannel
        conversationIDKey={item.conversationIDKey}
        isSelected={!Styles.isMobile && this.props.selectedIndex === realIndex}
        numSearchHits={item?.numHits ?? undefined}
        maxSearchHits={Constants.inboxSearchMaxTextMessages}
        onSelectConversation={() => section.onSelect(item, realIndex)}
      />
    ) : (
      <SelectableSmallTeam
        conversationIDKey={item.conversationIDKey}
        isSelected={!Styles.isMobile && this.props.selectedIndex === realIndex}
        numSearchHits={item?.numHits ?? undefined}
        maxSearchHits={Constants.inboxSearchMaxTextMessages}
        onSelectConversation={() => section.onSelect(item, realIndex)}
      />
    )
  }
  _toggleCollapseName = () => {
    this.setState({nameCollapsed: !this.state.nameCollapsed})
  }
  _toggleCollapseText = () => {
    this.setState({textCollapsed: !this.state.textCollapsed})
  }
  _selectName = (item, index) => {
    this.props.onSelectConversation(item.conversationIDKey, index, '')
    this.props.onCancel()
  }
  _selectText = (item, index) => {
    this.props.onSelectConversation(item.conversationIDKey, index, item.query)
  }
  _renderNameHeader = section => {
    return (
      <Kb.SectionDivider
        collapsed={section.isCollapsed}
        label={section.title}
        onToggleCollapsed={section.onCollapse}
        showSpinner={section.status === 'inprogress'}
      />
    )
  }
  _renderTextHeader = section => {
    return (
      <Kb.Box2 direction="vertical" fullWidth={true} style={styles.textHeader}>
        <Kb.SectionDivider
          collapsed={section.isCollapsed}
          label={section.title}
          onToggleCollapsed={section.onCollapse}
          showSpinner={section.status === 'inprogress'}
        />
        {this.props.textStatus === 'error' ? (
          <Kb.Box2 direction="horizontal" style={styles.percentContainer} fullWidth={true}>
            <Kb.Text type="BodyTiny" style={styles.errorText} center={true}>
              Search failed, please try again, or contact Keybase describing the problem.
            </Kb.Text>
          </Kb.Box2>
        ) : this.props.indexPercent > 0 && this.props.indexPercent < 100 ? (
          <Kb.Box2 direction="horizontal" gap="xtiny" style={styles.percentContainer} fullWidth={true}>
            <Kb.Text type="BodyTiny">Indexing...</Kb.Text>
            <Kb.ProgressBar style={styles.progressBar} ratio={this.props.indexPercent / 100.0} />
          </Kb.Box2>
        ) : null}
      </Kb.Box2>
    )
  }
  _renderSectionHeader = ({section}) => {
    return section.renderHeader(section)
  }
  _keyExtractor = (item, index) => index
  _nameResults = () => {
    return this.state.nameCollapsed ? [] : this.props.nameResults
  }
  _textResults = () => {
    return this.state.textCollapsed ? [] : this.props.textResults
  }
  _isStatusDone = status => {
    return status === 'success' || status === 'error'
  }

  render() {
    const textResults = this._textResults()
    const nameResults = this._nameResults()
    const noResults =
      this._isStatusDone(this.props.nameStatus) &&
      this._isStatusDone(this.props.textStatus) &&
      this.props.nameResults.length === 0 &&
      this.props.textResults.length === 0 &&
      this.props.query.length > 0
    const sections = [
      {
        data: nameResults,
        indexOffset: 0,
        isCollapsed: this.state.nameCollapsed,
        onCollapse: this._toggleCollapseName,
        onSelect: this._selectName,
        renderHeader: this._renderNameHeader,
        renderItem: this._renderHit,
        status: this.props.nameStatus,
        title: this.props.nameResultsUnread ? 'Recent' : 'Chats',
      },
    ]
    if (!this.props.nameResultsUnread) {
      sections.push({
        data: textResults,
        indexOffset: nameResults.length,
        isCollapsed: this.state.textCollapsed,
        onCollapse: this._toggleCollapseText,
        onSelect: this._selectText,
        renderHeader: this._renderTextHeader,
        renderItem: this._renderHit,
        status: this.props.textStatus,
        title: 'Messages',
      })
    }
    return (
      <Kb.Box2 style={styles.container} direction="vertical" fullWidth={true}>
        <Kb.SectionList
          ListHeaderComponent={this.props.header}
          stickySectionHeadersEnabled={true}
          renderSectionHeader={this._renderSectionHeader}
          keyExtractor={this._keyExtractor}
          keyboardShouldPersistTaps="handled"
          sections={sections}
        />
        {noResults && <Owl />}
      </Kb.Box2>
    )
  }
}

const styles = Styles.styleSheetCreate({
  container: Styles.platformStyles({
    isElectron: {
      ...Styles.globalStyles.flexBoxColumn,
      backgroundColor: Styles.globalColors.blueGrey,
      contain: 'strict',
      height: '100%',
      maxWidth: inboxWidth,
      minWidth: inboxWidth,
      position: 'relative',
    },
  }),
  errorText: {
    color: Styles.globalColors.red,
  },
  percentContainer: {
    padding: Styles.globalMargins.tiny,
  },
  progressBar: {
    alignSelf: 'center',
    flex: 1,
    width: '100%',
  },
  textHeader: {
    backgroundColor: Styles.globalColors.blue5,
  },
})

export default InboxSearch
<commit_msg>index progress tooltip (#17284)<commit_after>// @flow
import * as React from 'react'
import * as Kb from '../../common-adapters'
import * as Types from '../../constants/types/chat2'
import * as Constants from '../../constants/chat2'
import * as Styles from '../../styles'
import SelectableSmallTeam from '../selectable-small-team-container'
import SelectableBigTeamChannel from '../selectable-big-team-channel-container'
import {inboxWidth} from '../inbox/row/sizes'
import {Owl} from '../inbox/owl'

type NameResult = {|
  conversationIDKey: Types.ConversationIDKey,
  type: 'big' | 'small',
|}

type TextResult = {|
  conversationIDKey: Types.ConversationIDKey,
  type: 'big' | 'small',
  numHits: number,
  query: string,
|}

type Props = {|
  header?: React.Node,
  indexPercent: number,
  nameStatus: Types.InboxSearchStatus,
  nameResults: Array<NameResult>,
  nameResultsUnread: boolean,
  onCancel: () => void,
  onSelectConversation: (Types.ConversationIDKey, number, string) => void,
  selectedIndex: number,
  textStatus: Types.InboxSearchStatus,
  textResults: Array<TextResult>,
  query: string,
|}

type State = {
  nameCollapsed: boolean,
  textCollapsed: boolean,
}

class InboxSearch extends React.Component<Props, State> {
  state = {nameCollapsed: false, textCollapsed: false}

  _renderHit = ({item, section, index}) => {
    const realIndex = index + section.indexOffset
    return item.type === 'big' ? (
      <SelectableBigTeamChannel
        conversationIDKey={item.conversationIDKey}
        isSelected={!Styles.isMobile && this.props.selectedIndex === realIndex}
        numSearchHits={item?.numHits ?? undefined}
        maxSearchHits={Constants.inboxSearchMaxTextMessages}
        onSelectConversation={() => section.onSelect(item, realIndex)}
      />
    ) : (
      <SelectableSmallTeam
        conversationIDKey={item.conversationIDKey}
        isSelected={!Styles.isMobile && this.props.selectedIndex === realIndex}
        numSearchHits={item?.numHits ?? undefined}
        maxSearchHits={Constants.inboxSearchMaxTextMessages}
        onSelectConversation={() => section.onSelect(item, realIndex)}
      />
    )
  }
  _toggleCollapseName = () => {
    this.setState({nameCollapsed: !this.state.nameCollapsed})
  }
  _toggleCollapseText = () => {
    this.setState({textCollapsed: !this.state.textCollapsed})
  }
  _selectName = (item, index) => {
    this.props.onSelectConversation(item.conversationIDKey, index, '')
    this.props.onCancel()
  }
  _selectText = (item, index) => {
    this.props.onSelectConversation(item.conversationIDKey, index, item.query)
  }
  _renderNameHeader = section => {
    return (
      <Kb.SectionDivider
        collapsed={section.isCollapsed}
        label={section.title}
        onToggleCollapsed={section.onCollapse}
        showSpinner={section.status === 'inprogress'}
      />
    )
  }
  _renderTextHeader = section => {
    const ratio = this.props.indexPercent / 100.0
    return (
      <Kb.Box2 direction="vertical" fullWidth={true} style={styles.textHeader}>
        <Kb.SectionDivider
          collapsed={section.isCollapsed}
          label={section.title}
          onToggleCollapsed={section.onCollapse}
          showSpinner={section.status === 'inprogress'}
        />
        {this.props.textStatus === 'error' ? (
          <Kb.Box2 direction="horizontal" style={styles.percentContainer} fullWidth={true}>
            <Kb.Text type="BodyTiny" style={styles.errorText} center={true}>
              Search failed, please try again, or contact Keybase describing the problem.
            </Kb.Text>
          </Kb.Box2>
        ) : this.props.indexPercent > 0 && this.props.indexPercent < 100 ? (
          <Kb.Box2 direction="horizontal" gap="xtiny" style={styles.percentContainer} fullWidth={true}>
            <Kb.Text type="BodyTiny">Indexing...</Kb.Text>
            {Styles.isMobile ? (
              <Kb.ProgressBar style={styles.progressBar} ratio={ratio} />
            ) : (
              <Kb.WithTooltip
                containerStyle={styles.progressBar}
                position="bottom center"
                text={`${this.props.indexPercent}% complete`}
              >
                <Kb.ProgressBar style={styles.progressBar} ratio={ratio} />
              </Kb.WithTooltip>
            )}
          </Kb.Box2>
        ) : null}
      </Kb.Box2>
    )
  }
  _renderSectionHeader = ({section}) => {
    return section.renderHeader(section)
  }
  _keyExtractor = (item, index) => index
  _nameResults = () => {
    return this.state.nameCollapsed ? [] : this.props.nameResults
  }
  _textResults = () => {
    return this.state.textCollapsed ? [] : this.props.textResults
  }
  _isStatusDone = status => {
    return status === 'success' || status === 'error'
  }

  render() {
    const textResults = this._textResults()
    const nameResults = this._nameResults()
    const noResults =
      this._isStatusDone(this.props.nameStatus) &&
      this._isStatusDone(this.props.textStatus) &&
      this.props.nameResults.length === 0 &&
      this.props.textResults.length === 0 &&
      this.props.query.length > 0
    const sections = [
      {
        data: nameResults,
        indexOffset: 0,
        isCollapsed: this.state.nameCollapsed,
        onCollapse: this._toggleCollapseName,
        onSelect: this._selectName,
        renderHeader: this._renderNameHeader,
        renderItem: this._renderHit,
        status: this.props.nameStatus,
        title: this.props.nameResultsUnread ? 'Recent' : 'Chats',
      },
    ]
    if (!this.props.nameResultsUnread) {
      sections.push({
        data: textResults,
        indexOffset: nameResults.length,
        isCollapsed: this.state.textCollapsed,
        onCollapse: this._toggleCollapseText,
        onSelect: this._selectText,
        renderHeader: this._renderTextHeader,
        renderItem: this._renderHit,
        status: this.props.textStatus,
        title: 'Messages',
      })
    }
    return (
      <Kb.Box2 style={styles.container} direction="vertical" fullWidth={true}>
        <Kb.SectionList
          ListHeaderComponent={this.props.header}
          stickySectionHeadersEnabled={true}
          renderSectionHeader={this._renderSectionHeader}
          keyExtractor={this._keyExtractor}
          keyboardShouldPersistTaps="handled"
          sections={sections}
        />
        {noResults && <Owl />}
      </Kb.Box2>
    )
  }
}

const styles = Styles.styleSheetCreate({
  container: Styles.platformStyles({
    isElectron: {
      ...Styles.globalStyles.flexBoxColumn,
      backgroundColor: Styles.globalColors.blueGrey,
      contain: 'strict',
      height: '100%',
      maxWidth: inboxWidth,
      minWidth: inboxWidth,
      position: 'relative',
    },
  }),
  errorText: {
    color: Styles.globalColors.red,
  },
  percentContainer: {
    padding: Styles.globalMargins.tiny,
  },
  progressBar: {
    alignSelf: 'center',
    flex: 1,
    width: '100%',
  },
  textHeader: {
    backgroundColor: Styles.globalColors.blue5,
  },
})

export default InboxSearch
<|endoftext|>


<commit_before>var Graph = require('../src')
  , prettyjson = require('prettyjson').render

/*!
 * The main file of the program
 */
var entry = __dirname + '/husband.js';

var dirRegex = new RegExp('^'+__dirname);

new Graph()
	.use('javascript')
	.trace(entry)
	.then(function (files) {
		files.forEach(function (file) {
			file.requires = file.requires()
			file.base = file.base.replace(dirRegex, '')
			file.path = file.path.replace(dirRegex, '')
		})
		console.log(prettyjson(files))
	})<commit_msg>update example<commit_after>var Graph = require('../src')
  , prettyjson = require('prettyjson').render

/*!
 * The main file of the program
 */
var entry = __dirname + '/husband.js';

var dirRegex = new RegExp('^'+__dirname);

new Graph()
	.use('javascript')
	.trace(entry)
	.then(function (files) {
		files.forEach(function (file) {
			file.base = file.base.replace(dirRegex, '')
			file.path = file.path.replace(dirRegex, '')
		})
		console.log(prettyjson(files))
	})<|endoftext|>


<commit_before>import { ThreeTilesRenderer } from '../src/ThreeTilesRenderer.js';
import { Scene, DirectionalLight, AmbientLight, WebGLRenderer, PerspectiveCamera, CameraHelper, Box3, Raycaster, Vector2, Ray, Mesh, CylinderBufferGeometry, MeshBasicMaterial, Group } from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import * as dat from 'three/examples/jsm/libs/dat.gui.module.js';
import Stats from 'three/examples/jsm/libs/stats.module.js';

let camera, controls, scene, renderer, tiles, cameraHelper;
let thirdPersonCamera, thirdPersonRenderer, thirdPersonControls;
let box;
let raycaster, mouse, rayIntersect;
let offsetParent;
let statsContainer, stats;

let params = {

	'errorTarget': 6,
	'errorThreshold': 60,
	'maxDepth': 15,
	'loadSiblings': true,

	'up': '+Y',
	'displayBounds': false,
	'showThirdPerson': true,
	'reload': reinstantiateTiles,

};

init();
animate();

function reinstantiateTiles() {

	const url = window.location.hash.replace( /^#/, '' ) || './SampleTileset/tileset.json';

	if ( tiles ) {

		offsetParent.remove( tiles.group );

	}

	tiles = new ThreeTilesRenderer( url, camera, renderer );
	offsetParent.add( tiles.group );

}

function init() {

	// Third person camera view
	thirdPersonCamera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 3000 );
	thirdPersonCamera.position.set( 50, 40, 40 );
	thirdPersonCamera.lookAt( 0, 0, 0 );

	thirdPersonRenderer = new WebGLRenderer( { antialias: true } );
	thirdPersonRenderer.setPixelRatio( window.devicePixelRatio );
	thirdPersonRenderer.setSize( window.innerWidth, window.innerHeight );
	thirdPersonRenderer.setClearColor( 0xdddddd );

	document.body.appendChild( thirdPersonRenderer.domElement );
	thirdPersonRenderer.domElement.style.position = 'fixed';
	thirdPersonRenderer.domElement.style.left = '5px';
	thirdPersonRenderer.domElement.style.bottom = '5px';

	thirdPersonControls = new OrbitControls( thirdPersonCamera, thirdPersonRenderer.domElement );
	thirdPersonControls.screenSpacePanning = false;
	thirdPersonControls.minDistance = 1;
	thirdPersonControls.maxDistance = 2000;

	// primary camera view
	scene = new Scene();

	renderer = new WebGLRenderer( { antialias: true } );
	renderer.setPixelRatio( window.devicePixelRatio );
	renderer.setSize( window.innerWidth, window.innerHeight );
	renderer.setClearColor( 0xcccccc );
	renderer.gammaInput = true;
	renderer.gameOutput = true;

	document.body.appendChild( renderer.domElement );

	camera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 2000 );
	camera.position.set( 100, 100, 100 );

	cameraHelper = new CameraHelper( camera );
	scene.add( cameraHelper );

	// controls
	controls = new OrbitControls( camera, renderer.domElement );
	controls.screenSpacePanning = false;
	controls.minDistance = 1;
	controls.maxDistance = 2000;

	// lights
	var dirLight = new DirectionalLight( 0xffffff );
	dirLight.position.set( 1, 1, 1 );
	scene.add( dirLight );

	var ambLight = new AmbientLight( 0x222222 );
	scene.add( ambLight );

	box = new Box3();

	raycaster = new Raycaster();
	mouse = new Vector2();
	rayIntersect = new Mesh( new CylinderBufferGeometry( 0.25, 0.25, 5 ), new MeshBasicMaterial( { color: 0xff0000 } ) );
	scene.add( rayIntersect );

	offsetParent = new Group();
	scene.add( offsetParent );

	reinstantiateTiles();

	onWindowResize();
	window.addEventListener( 'resize', onWindowResize, false );
	window.addEventListener( 'mousemove', onMouseMove, false );

	// GUI
	const gui = new dat.GUI();
	const tiles = gui.addFolder( 'Tiles Options' );
	tiles.add( params, 'loadSiblings' );
	tiles.add( params, 'errorTarget' ).min( 0 ).max( 50 );
	tiles.add( params, 'errorThreshold' ).min( 0 ).max( 1000 );
	tiles.add( params, 'maxDepth' ).min( 1 ).max( 100 );
	tiles.add( params, 'up', [ '+Y', '-Z' ] );
	tiles.open();

	gui.add( params, 'displayBounds' );
	gui.add( params, 'showThirdPerson' );
	gui.add( params, 'reload' );

	gui.open();

	// TilesRenderer stats display
	let textShadow = [];
	for ( let x = - 1; x <= 1; x ++ ) {

		for ( let y = - 1; y <= 1; y ++ ) {

			let valX = x;
			let valY = y;

			if ( valX !== 0 && valY !== 0 ) {

				valX *= Math.cos( Math.PI / 4 );
				valY *= Math.sin( Math.PI / 4 );

			}

			valX *= 1.5;
			valY *= 1.5;

			textShadow.push( `white ${ valX }px ${ valY }px 0` );

		}

	}

	statsContainer = document.createElement( 'div' );
	statsContainer.style.position = 'absolute';
	statsContainer.style.top = 0;
	statsContainer.style.left = 0;
	statsContainer.style.width = '100%';
	statsContainer.style.textAlign = 'center';
	statsContainer.style.textShadow = textShadow.join( ',' );
	statsContainer.style.padding = '10px';
	document.body.appendChild( statsContainer );

	// Stats
	stats = new Stats();
	stats.showPanel( 0 );
	document.body.appendChild( stats.dom );

}

function onWindowResize() {

	thirdPersonCamera.aspect = window.innerWidth / window.innerHeight;
	thirdPersonCamera.updateProjectionMatrix();
	thirdPersonRenderer.setSize( Math.floor( window.innerWidth / 3 ), Math.floor( window.innerHeight / 3 ) );

	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize( window.innerWidth, window.innerHeight );

}

function onMouseMove( e ) {

	mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
	mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
	raycaster.setFromCamera( mouse, camera );

	const results = raycaster.intersectObject( tiles.group, true );
	if ( results.length ) {

		const closestHit = results[ 0 ];
		rayIntersect.position.copy( closestHit.point );

		closestHit.face.normal.add( closestHit.point );
		rayIntersect.lookAt( closestHit.face.normal );

	}

}

function animate() {

	// update options
	tiles.errorTarget = params.errorTarget;
	tiles.errorThreshold = params.errorThreshold;
	tiles.loadSiblings = params.loadSiblings;
	tiles.maxDepth = params.maxDepth;
	tiles.displayBounds = params.displayBounds;

	// update tiles
	tiles.update();
	window.tiles = tiles;

	offsetParent.rotation.set( 0, 0, 0 );
	if ( params.up === '-Z' ) {

		offsetParent.rotation.x = Math.PI / 2;

	}

	// update tiles center
	if ( tiles.getBounds( box ) ) {

		box.getCenter( tiles.group.position );
		tiles.group.position.multiplyScalar( - 1 );

	}

	stats.begin();
	render();
	stats.end();

	requestAnimationFrame( animate );

}

function render() {

	// render primary view
	cameraHelper.visible = false;
	renderer.render( scene, camera );

	// render third person view
	thirdPersonRenderer.domElement.style.visibility = params.showThirdPerson ? 'visible' : 'hidden';
	if ( params.showThirdPerson ) {

		cameraHelper.visible = true;
		thirdPersonRenderer.render( scene, thirdPersonCamera );

	}

	statsContainer.innerText =
		`Downloading: ${tiles.stats.downloading} Parsing: ${tiles.stats.parsing} Visible: ${tiles.group.children.length}`;

}
<commit_msg>Update look of demo<commit_after>import { ThreeTilesRenderer } from '../src/ThreeTilesRenderer.js';
import { Scene, DirectionalLight, AmbientLight, WebGLRenderer, PerspectiveCamera, CameraHelper, Box3, Raycaster, Vector2, Mesh, CylinderBufferGeometry, MeshBasicMaterial, Group, AxesHelper, TorusBufferGeometry } from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import * as dat from 'three/examples/jsm/libs/dat.gui.module.js';
import Stats from 'three/examples/jsm/libs/stats.module.js';

let camera, controls, scene, renderer, tiles, cameraHelper;
let thirdPersonCamera, thirdPersonRenderer, thirdPersonControls;
let box;
let raycaster, mouse, rayIntersect;
let offsetParent;
let statsContainer, stats;

let params = {

	'errorTarget': 6,
	'errorThreshold': 60,
	'maxDepth': 15,
	'loadSiblings': true,

	'up': '+Y',
	'displayBounds': false,
	'showThirdPerson': true,
	'reload': reinstantiateTiles,

};

init();
animate();

function reinstantiateTiles() {

	const url = window.location.hash.replace( /^#/, '' ) || './SampleTileset/tileset.json';

	if ( tiles ) {

		offsetParent.remove( tiles.group );

	}

	tiles = new ThreeTilesRenderer( url, camera, renderer );
	offsetParent.add( tiles.group );

}

function init() {

	// Third person camera view
	thirdPersonCamera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 3000 );
	thirdPersonCamera.position.set( 50, 40, 40 );
	thirdPersonCamera.lookAt( 0, 0, 0 );

	thirdPersonRenderer = new WebGLRenderer( { antialias: true } );
	thirdPersonRenderer.setPixelRatio( window.devicePixelRatio );
	thirdPersonRenderer.setSize( window.innerWidth, window.innerHeight );
	thirdPersonRenderer.setClearColor( 0x0f1416 );

	document.body.appendChild( thirdPersonRenderer.domElement );
	thirdPersonRenderer.domElement.style.position = 'fixed';
	thirdPersonRenderer.domElement.style.left = '5px';
	thirdPersonRenderer.domElement.style.bottom = '5px';

	thirdPersonControls = new OrbitControls( thirdPersonCamera, thirdPersonRenderer.domElement );
	thirdPersonControls.screenSpacePanning = false;
	thirdPersonControls.minDistance = 1;
	thirdPersonControls.maxDistance = 2000;

	// primary camera view
	scene = new Scene();

	renderer = new WebGLRenderer( { antialias: true } );
	renderer.setPixelRatio( window.devicePixelRatio );
	renderer.setSize( window.innerWidth, window.innerHeight );
	renderer.setClearColor( 0x151c1f );
	renderer.gammaInput = true;
	renderer.gameOutput = true;

	document.body.appendChild( renderer.domElement );

	camera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 2000 );
	camera.position.set( 100, 100, 100 );

	cameraHelper = new CameraHelper( camera );
	scene.add( cameraHelper );

	// controls
	controls = new OrbitControls( camera, renderer.domElement );
	controls.screenSpacePanning = false;
	controls.minDistance = 1;
	controls.maxDistance = 2000;

	// lights
	var dirLight = new DirectionalLight( 0xffffff );
	dirLight.position.set( 1, 1, 1 );
	scene.add( dirLight );

	var ambLight = new AmbientLight( 0x222222 );
	scene.add( ambLight );

	box = new Box3();

	raycaster = new Raycaster();
	mouse = new Vector2();

	rayIntersect = new Group();

	const rayMesh = new Mesh( new CylinderBufferGeometry( 0.25, 0.25, 10 ), new MeshBasicMaterial( { color: 0xe91e63 } ) );
	rayMesh.rotation.x = Math.PI / 2;
	rayMesh.position.z += 5;
	rayIntersect.add( rayMesh );

	const rayRing = new Mesh( new TorusBufferGeometry( 1.5, 0.2, 16, 100 ), new MeshBasicMaterial( { color: 0xe91e63 } ) );
	rayIntersect.add( rayRing );
	scene.add( rayIntersect );

	offsetParent = new Group();
	scene.add( offsetParent );

	reinstantiateTiles();

	onWindowResize();
	window.addEventListener( 'resize', onWindowResize, false );
	window.addEventListener( 'mousemove', onMouseMove, false );

	// GUI
	const gui = new dat.GUI();
	const tiles = gui.addFolder( 'Tiles Options' );
	tiles.add( params, 'loadSiblings' );
	tiles.add( params, 'errorTarget' ).min( 0 ).max( 50 );
	tiles.add( params, 'errorThreshold' ).min( 0 ).max( 1000 );
	tiles.add( params, 'maxDepth' ).min( 1 ).max( 100 );
	tiles.add( params, 'up', [ '+Y', '-Z' ] );
	tiles.open();

	gui.add( params, 'displayBounds' );
	gui.add( params, 'showThirdPerson' );
	gui.add( params, 'reload' );

	gui.open();

	statsContainer = document.createElement( 'div' );
	statsContainer.style.position = 'absolute';
	statsContainer.style.top = 0;
	statsContainer.style.left = 0;
	statsContainer.style.color = 'white';
	statsContainer.style.width = '100%';
	statsContainer.style.textAlign = 'center';
	statsContainer.style.padding = '10px';
	document.body.appendChild( statsContainer );

	// Stats
	stats = new Stats();
	stats.showPanel( 0 );
	document.body.appendChild( stats.dom );

}

function onWindowResize() {

	thirdPersonCamera.aspect = window.innerWidth / window.innerHeight;
	thirdPersonCamera.updateProjectionMatrix();
	thirdPersonRenderer.setSize( Math.floor( window.innerWidth / 3 ), Math.floor( window.innerHeight / 3 ) );

	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize( window.innerWidth, window.innerHeight );

}

function onMouseMove( e ) {

	mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
	mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
	raycaster.setFromCamera( mouse, camera );

	const results = raycaster.intersectObject( tiles.group, true );
	if ( results.length ) {

		const closestHit = results[ 0 ];
		rayIntersect.position.copy( closestHit.point );

		closestHit.face.normal.add( closestHit.point );
		rayIntersect.lookAt( closestHit.face.normal );

	}

}

function animate() {

	// update options
	tiles.errorTarget = params.errorTarget;
	tiles.errorThreshold = params.errorThreshold;
	tiles.loadSiblings = params.loadSiblings;
	tiles.maxDepth = params.maxDepth;
	tiles.displayBounds = params.displayBounds;

	// update tiles
	tiles.update();
	window.tiles = tiles;

	offsetParent.rotation.set( 0, 0, 0 );
	if ( params.up === '-Z' ) {

		offsetParent.rotation.x = Math.PI / 2;

	}

	// update tiles center
	if ( tiles.getBounds( box ) ) {

		box.getCenter( tiles.group.position );
		tiles.group.position.multiplyScalar( - 1 );

	}

	stats.begin();
	render();
	stats.end();

	requestAnimationFrame( animate );

}

function render() {

	// render primary view
	cameraHelper.visible = false;
	renderer.render( scene, camera );

	// render third person view
	thirdPersonRenderer.domElement.style.visibility = params.showThirdPerson ? 'visible' : 'hidden';
	if ( params.showThirdPerson ) {

		cameraHelper.visible = true;
		thirdPersonRenderer.render( scene, thirdPersonCamera );

	}

	statsContainer.innerText =
		`Downloading: ${tiles.stats.downloading} Parsing: ${tiles.stats.parsing} Visible: ${tiles.group.children.length}`;

}
<|endoftext|>


<commit_before>// Dependencies
var Cobol = require("../lib");

// Execute some COBOL snippets
Cobol(function () { /*
       IDENTIFICATION DIVISION.
       PROGRAM-ID. HELLO.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       PROCEDURE DIVISION.

       PROGRAM-BEGIN.
           DISPLAY "Hello world".

       PROGRAM-DONE.
           STOP RUN.
*/ }, function (err, data) {
    console.log(err || data);
});
// => "Hello World"

Cobol(__dirname + "/args.cbl", {
    args: ["Alice"]
}, function (err, data) {
    console.log(err || data);
});
// => "Your name is: Alice"

// This will read data from stdin
Cobol(function () { /*
       IDENTIFICATION DIVISION.
       PROGRAM-ID. APP.
      *> http://stackoverflow.com/q/938760/1420197

       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
       SELECT SYSIN ASSIGN TO KEYBOARD ORGANIZATION LINE SEQUENTIAL.

       DATA DIVISION.
       FILE SECTION.
       FD SYSIN.
       01 ln PIC X(64).
          88 EOF VALUE HIGH-VALUES.
       WORKING-STORAGE SECTION.
       PROCEDURE DIVISION.
       DISPLAY "Write something and then press the <Enter> key"
       OPEN INPUT SYSIN
       READ SYSIN
       AT END SET EOF TO TRUE
       END-READ
       PERFORM UNTIL EOF
       DISPLAY "You wrote: ", ln
       DISPLAY "------------"
       READ SYSIN
       AT END SET EOF TO TRUE
       END-READ
       END-PERFORM
       CLOSE SYSIN
       STOP RUN.
*/ }, {
    stdin: process.stdin
  , stdout: process.stdout
}, function (err) {
    if (err) {
        console.log(err);
    }
});
// => Write something and then press the <Enter> key
// <= Hi there!
// => You wrote: Hi there!
// => ------------

//you can also use our promise based API

var Q = require('q');
var helloWorld1 = Cobol(function () { /*
       IDENTIFICATION DIVISION.
       PROGRAM-ID. HELLO.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       PROCEDURE DIVISION.

       PROGRAM-BEGIN.
       DISPLAY "Hello world".

       PROGRAM-DONE.
       STOP RUN.
 */ });

var helloWorld2 = Cobol(function () { /*
       IDENTIFICATION DIVISION.
       PROGRAM-ID. HELLO.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       PROCEDURE DIVISION.

       PROGRAM-BEGIN.
       DISPLAY "Hello world second time!".

       PROGRAM-DONE.
       STOP RUN.
 */ });

console.log("no elo");
Q.all([helloWorld1, helloWorld2]).then(function (res) {
 console.log(a);
 console.log(b);
}).catch(function(res) {
 console.log(res);
});<commit_msg>small cleanup<commit_after>// Dependencies
var Cobol = require("../lib");

// Execute some COBOL snippets
Cobol(function () { /*
       IDENTIFICATION DIVISION.
       PROGRAM-ID. HELLO.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       PROCEDURE DIVISION.

       PROGRAM-BEGIN.
           DISPLAY "Hello world".

       PROGRAM-DONE.
           STOP RUN.
*/ }, function (err, data) {
    console.log(err || data);
});
// => "Hello World"

Cobol(__dirname + "/args.cbl", {
    args: ["Alice"]
}, function (err, data) {
    console.log(err || data);
});
// => "Your name is: Alice"

// This will read data from stdin
Cobol(function () { /*
       IDENTIFICATION DIVISION.
       PROGRAM-ID. APP.
      *> http://stackoverflow.com/q/938760/1420197

       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
       SELECT SYSIN ASSIGN TO KEYBOARD ORGANIZATION LINE SEQUENTIAL.

       DATA DIVISION.
       FILE SECTION.
       FD SYSIN.
       01 ln PIC X(64).
          88 EOF VALUE HIGH-VALUES.
       WORKING-STORAGE SECTION.
       PROCEDURE DIVISION.
       DISPLAY "Write something and then press the <Enter> key"
       OPEN INPUT SYSIN
       READ SYSIN
       AT END SET EOF TO TRUE
       END-READ
       PERFORM UNTIL EOF
       DISPLAY "You wrote: ", ln
       DISPLAY "------------"
       READ SYSIN
       AT END SET EOF TO TRUE
       END-READ
       END-PERFORM
       CLOSE SYSIN
       STOP RUN.
*/ }, {
    stdin: process.stdin
  , stdout: process.stdout
}, function (err) {
    if (err) {
        console.log(err);
    }
});
// => Write something and then press the <Enter> key
// <= Hi there!
// => You wrote: Hi there!
// => ------------

//you can also use our promise based API

var Q = require('q');
var helloWorld1 = Cobol(function () { /*
       IDENTIFICATION DIVISION.
       PROGRAM-ID. HELLO.
       PROCEDURE DIVISION.

       PROGRAM-BEGIN.
       DISPLAY "Hello world".

       PROGRAM-DONE.
       STOP RUN.
 */ });

var helloWorld2 = Cobol(function () { /*
       IDENTIFICATION DIVISION.
       PROGRAM-ID. HELLO.
       PROCEDURE DIVISION.

       PROGRAM-BEGIN.
       DISPLAY "Hello world second time!".

       PROGRAM-DONE.
       STOP RUN.
 */ });

Q.all([helloWorld1, helloWorld2]).then(function (res) {
 console.log(res);
}).catch(function(err) {
 console.log(err);
});<|endoftext|>


<commit_before>'use strict';
const redis=require('redis');
const genio=require('../lib');
const client=redis.createClient();
/*genio(function*(){
    let val;
    let redis=new genio.Context(client);
    val='works with Redis';
    yield redis.set('gen-io',val);
    val=yield redis.get('gen-io');
    console.log(`gen-io ${val}`);
});*/
client.set('ggg','val',function(err){
    if(err){
        console.error(err);
    }
    client.get('ggg',function(err,val){
        if(err){
            console.error(err);
        }
        console.log(val);
        process.exit(0);
    })
});<commit_msg>debug<commit_after>'use strict';
const redis=require('redis');
const genio=require('../lib');
const client=redis.createClient();
genio(function*(){
    let val;
    let redis=new genio.Context(client);
    console.log(redis);
    val='works with Redis';
    yield redis.set('gen-io',val);
    val=yield redis.get('gen-io');
    console.log(`gen-io ${val}`);
});/*
client.set('ggg','val',function(err){
    if(err){
        console.error(err);
    }
    client.get('ggg',function(err,val){
        if(err){
            console.error(err);
        }
        console.log(val);
        process.exit(0);
    })
});*/<|endoftext|>


<commit_before>import React, { useState, useMemo, useRef, useEffect } from 'react'
import { Slate, Editable, ReactEditor, withReact, useSlate } from 'slate-react'
import { Editor, Transforms, Text, createEditor } from 'slate'
import { css } from 'emotion'
import { withHistory } from 'slate-history'

import { Button, Icon, Menu, Portal } from '../components'
import { Range } from 'slate'

const HoveringMenuExample = () => {
  const [value, setValue] = useState(initialValue)
  const editor = useMemo(() => withHistory(withReact(createEditor())), [])

  return (
    <Slate editor={editor} value={value} onChange={value => setValue(value)}>
      <HoveringToolbar />
      <Editable
        renderLeaf={props => <Leaf {...props} />}
        placeholder="Enter some text..."
        onDOMBeforeInput={event => {
          switch (event.inputType) {
            case 'formatBold':
              return toggleFormat(editor, 'bold')
            case 'formatItalic':
              return toggleFormat(editor, 'italic')
            case 'formatUnderline':
              return toggleFormat(editor, 'underline')
          }
        }}
      />
    </Slate>
  )
}

const toggleFormat = (editor, format) => {
  const isActive = isFormatActive(editor, format)
  Transforms.setNodes(
    editor,
    { [format]: isActive ? null : true },
    { match: Text.isText, split: true }
  )
}

const isFormatActive = (editor, format) => {
  const [match] = Editor.nodes(editor, {
    match: n => n[format] === true,
    mode: 'all',
  })
  return !!match
}

const Leaf = ({ attributes, children, leaf }) => {
  if (leaf.bold) {
    children = {children}
  }

  if (leaf.italic) {
    children = {children}
  }

  if (leaf.underlined) {
    children = {children}
  }

  return {children}
}

const HoveringToolbar = () => {
  const ref = useRef()
  const editor = useSlate()

  useEffect(() => {
    const el = ref.current
    const { selection } = editor

    if (!el) {
      return
    }

    if (
      !selection ||
      !ReactEditor.isFocused(editor) ||
      Range.isCollapsed(selection) ||
      Editor.string(editor, selection) === ''
    ) {
      el.removeAttribute('style')
      return
    }

    const domSelection = window.getSelection()
    const domRange = domSelection.getRangeAt(0)
    const rect = domRange.getBoundingClientRect()
    el.style.opacity = 1
    el.style.top = `${rect.top + window.pageYOffset - el.offsetHeight}px`
    el.style.left = `${rect.left +
      window.pageXOffset -
      el.offsetWidth / 2 +
      rect.width / 2}px`
  })

  return (
    <Portal>
      <Menu
        ref={ref}
        className={css`
          padding: 8px 7px 6px;
          position: absolute;
          z-index: 1;
          top: -10000px;
          left: -10000px;
          margin-top: -6px;
          opacity: 0;
          background-color: #222;
          border-radius: 4px;
          transition: opacity 0.75s;
        `}
      >
        <FormatButton format="bold" icon="format_bold" />
        <FormatButton format="italic" icon="format_italic" />
        <FormatButton format="underlined" icon="format_underlined" />
      </Menu>
    </Portal>
  )
}

const FormatButton = ({ format, icon }) => {
  const editor = useSlate()
  return (
    <Button
      reversed
      active={isFormatActive(editor, format)}
      onMouseDown={event => {
        event.preventDefault()
        toggleFormat(editor, format)
      }}
    >
      <Icon>{icon}</Icon>
    </Button>
  )
}

const initialValue = [
  {
    children: [
      {
        text:
          'This example shows how you can make a hovering menu appear above your content, which you can use to make text ',
      },
      { text: 'bold', bold: true },
      { text: ', ' },
      { text: 'italic', italic: true },
      { text: ', or anything else you might want to do!' },
    ],
  },
  {
    children: [
      { text: 'Try it out yourself! Just ' },
      { text: 'select any piece of text and the menu will appear', bold: true },
      { text: '.' },
    ],
  },
]

export default HoveringMenuExample
<commit_msg>fix hovering toolbar format hotkeys (#3667)<commit_after>import React, { useState, useMemo, useRef, useEffect } from 'react'
import { Slate, Editable, ReactEditor, withReact, useSlate } from 'slate-react'
import { Editor, Transforms, Text, createEditor } from 'slate'
import { css } from 'emotion'
import { withHistory } from 'slate-history'

import { Button, Icon, Menu, Portal } from '../components'
import { Range } from 'slate'

const HoveringMenuExample = () => {
  const [value, setValue] = useState(initialValue)
  const editor = useMemo(() => withHistory(withReact(createEditor())), [])

  return (
    <Slate editor={editor} value={value} onChange={value => setValue(value)}>
      <HoveringToolbar />
      <Editable
        renderLeaf={props => <Leaf {...props} />}
        placeholder="Enter some text..."
        onDOMBeforeInput={event => {
          event.preventDefault()
          switch (event.inputType) {
            case 'formatBold':
              return toggleFormat(editor, 'bold')
            case 'formatItalic':
              return toggleFormat(editor, 'italic')
            case 'formatUnderline':
              return toggleFormat(editor, 'underline')
          }
        }}
      />
    </Slate>
  )
}

const toggleFormat = (editor, format) => {
  const isActive = isFormatActive(editor, format)
  Transforms.setNodes(
    editor,
    { [format]: isActive ? null : true },
    { match: Text.isText, split: true }
  )
}

const isFormatActive = (editor, format) => {
  const [match] = Editor.nodes(editor, {
    match: n => n[format] === true,
    mode: 'all',
  })
  return !!match
}

const Leaf = ({ attributes, children, leaf }) => {
  if (leaf.bold) {
    children = {children}
  }

  if (leaf.italic) {
    children = {children}
  }

  if (leaf.underlined) {
    children = {children}
  }

  return {children}
}

const HoveringToolbar = () => {
  const ref = useRef()
  const editor = useSlate()

  useEffect(() => {
    const el = ref.current
    const { selection } = editor

    if (!el) {
      return
    }

    if (
      !selection ||
      !ReactEditor.isFocused(editor) ||
      Range.isCollapsed(selection) ||
      Editor.string(editor, selection) === ''
    ) {
      el.removeAttribute('style')
      return
    }

    const domSelection = window.getSelection()
    const domRange = domSelection.getRangeAt(0)
    const rect = domRange.getBoundingClientRect()
    el.style.opacity = 1
    el.style.top = `${rect.top + window.pageYOffset - el.offsetHeight}px`
    el.style.left = `${rect.left +
      window.pageXOffset -
      el.offsetWidth / 2 +
      rect.width / 2}px`
  })

  return (
    <Portal>
      <Menu
        ref={ref}
        className={css`
          padding: 8px 7px 6px;
          position: absolute;
          z-index: 1;
          top: -10000px;
          left: -10000px;
          margin-top: -6px;
          opacity: 0;
          background-color: #222;
          border-radius: 4px;
          transition: opacity 0.75s;
        `}
      >
        <FormatButton format="bold" icon="format_bold" />
        <FormatButton format="italic" icon="format_italic" />
        <FormatButton format="underlined" icon="format_underlined" />
      </Menu>
    </Portal>
  )
}

const FormatButton = ({ format, icon }) => {
  const editor = useSlate()
  return (
    <Button
      reversed
      active={isFormatActive(editor, format)}
      onMouseDown={event => {
        event.preventDefault()
        toggleFormat(editor, format)
      }}
    >
      <Icon>{icon}</Icon>
    </Button>
  )
}

const initialValue = [
  {
    children: [
      {
        text:
          'This example shows how you can make a hovering menu appear above your content, which you can use to make text ',
      },
      { text: 'bold', bold: true },
      { text: ', ' },
      { text: 'italic', italic: true },
      { text: ', or anything else you might want to do!' },
    ],
  },
  {
    children: [
      { text: 'Try it out yourself! Just ' },
      { text: 'select any piece of text and the menu will appear', bold: true },
      { text: '.' },
    ],
  },
]

export default HoveringMenuExample
<|endoftext|>


<commit_before>describe('rendering', function(){

  describe('.render() fundamentals', function(){

    it('adds a .render() method to jQuery objects', function(){
      expect($empty.render).to.be.a('function');
    });

    it('returns the original jquery object from jquery\'s .render()', function(){
      expect($empty.render({})).to.equal($empty);
    });

    xit('proxies an object that has been rendered against', function(){
      $empty.render(empty);
      expect(bound.isProxied(empty)).to.equal(true);
    });

    xit('adds a bound-widget attribute to the target node', function(){
      expect($empty.render({}).attr('bound-widget') === undefined).to.be(false);
    });

    xit('doesn\'t recurse onto descendant bound widgets', function(){
      $name.render({}).appendTo($empty);
      expect(bound.getBoundDirectiveRenderCount()).to.equal(1);
      $empty.render(alice);
      expect(bound.getBoundDirectiveRenderCount()).to.equal(1);
      expect($name.html()).to.equal('');
    });

    it('falls through to namespaces that is in middle of scope chain', function(){
      var $node = $('
\

\

\

\

');
      $node.render({
        text: 'masked',
        child: {
          text: 'matched',
          grandchild: {}
        }
      });
      expect($node.find('[bound-with=grandchild]').html()).to.equal('matched');
    });

  });

  describe('directive render operation counting', function(){

    it('counts the number of directives processed', function(){
      expect(bound.getDirectiveRenderCount()).to.equal(0);
      $name.render(alice);
      expect(bound.getDirectiveRenderCount()).to.equal(1);
      bound.resetDirectiveRenderCount();
      expect(bound.getDirectiveRenderCount()).to.equal(0);
    });

  });

  describe('affected nodes', function(){

    it('does not operate on nodes that have no directives', function(){
      $empty.render({});
      expect(bound.getDirectiveRenderCount()).to.equal(0);
    });

    it('operates on all nodes in a single jQuery collection', function(){
      $name.add($age).render(alice);
      expect(bound.getDirectiveRenderCount()).to.equal(2);
      expect($name.html()).to.equal('alice');
      expect($age.html()).to.equal('20');
    });

  });

  describe('following directives', function(){

    it('does not remove a directive attribute after following it', function(){
      expect($name.render(alice).attr('bound-contents')).to.equal('name');
    });

    xit('errors when passed an invalid directive name');

    it('updates nodes nested within the top level node', function(){
      $empty.append($name).render(alice);
      expect($name.html()).to.equal('alice');
    });

    it('it should insert contents that are text as text and not as dom nodes', function(){
      expect($message.render({text: ''}).text()).to.equal('');
    });

    it('it should insert contents that are dom nodes as dom nodes and not as text', function(){
      expect($message.render({text: $name}).children()[0]).to.be($name[0]);
      expect(typeof $message.render({text: $name}).children()[0]).to.equal('object');
    });

  });

  describe('debug directive', function(){
    it('detects a debug directive', function(){
      sinon.spy(_, 'debug');
      $('
').render({});
      expect(_.debug.called).to.be(true);
    });
  });

  describe('scopes and multiple namespace inputs', function(){

    afterEach(function(){
      delete global.age;
    });

    it('falls back onto the global namespace for keys that are not found on the input namespace', function(){
      global.age = 10;
      expect($age.render({}).html()).to.equal('10');
    });

  });

  describe('reactive updates', function(){

    it('refollows the directives of all rendered nodes when .bound() is called on a rendered-against namespace that has changed', function(){
      $name.render(alice);
      $age.render(alice);
      _.extend(alice, {name: 'al', age: 24});
      alice.bound();
      clock.tick(0);
      expect($name.html()).to.equal('al');
      expect($age.html()).to.equal('24');
    });

    xit('does not refollow directives for properties that have not change, after calling .bound()', function(){
      $name.render(alice);
      expect(bound.getDirectiveRenderCount()).to.be(1);
      // called after no changes, so no directives should be re-run
      alice.bound();
      clock.tick(0);
      expect(bound.getDirectiveRenderCount()).to.be(1);
    });

    it('should only update the directives of nodes that were rendered against the object that has .bound() called on it', function(){
      $name.render(alice);
      $name2.render(bob);
      bob.name = 'robert';
      bound.proxy(alice).bound('set', 'name', 'al');
      clock.tick(0);
      expect($name.html()).to.equal('al');
      expect($name2.html()).to.equal('bob');
    });

    xit('should rerender the object that bound("set") on it', function(){
      var $node = $('
\

\

\

');
      $node.render({
        alice: alice,
        bob: bob
      });
      expect(bound.getDirectiveRenderCount()).to.equal(4);

      bob.name = 'billy-bob';
      bound.proxy(alice).bound('set', 'name', 'al');
      expect($node.find('[bound-with=bob]').html()).to.equal('bob');
      expect($node.find('[bound-with=alice]').html()).to.equal('al');
      expect(bound.getDirectiveRenderCount()).to.equal(5);
    });

  });

});
<commit_msg>bound.proxy -> B for renderSpec<commit_after>describe('rendering', function(){

  describe('.render() fundamentals', function(){

    it('adds a .render() method to jQuery objects', function(){
      expect($empty.render).to.be.a('function');
    });

    it('returns the original jquery object from jquery\'s .render()', function(){
      expect($empty.render({})).to.equal($empty);
    });

    xit('proxies an object that has been rendered against', function(){
      $empty.render(empty);
      expect(bound.isProxied(empty)).to.equal(true);
    });

    xit('adds a bound-widget attribute to the target node', function(){
      expect($empty.render({}).attr('bound-widget') === undefined).to.be(false);
    });

    xit('doesn\'t recurse onto descendant bound widgets', function(){
      $name.render({}).appendTo($empty);
      expect(bound.getBoundDirectiveRenderCount()).to.equal(1);
      $empty.render(alice);
      expect(bound.getBoundDirectiveRenderCount()).to.equal(1);
      expect($name.html()).to.equal('');
    });

    it('falls through to namespaces that is in middle of scope chain', function(){
      var $node = $('
\

\

\

\

');
      $node.render({
        text: 'masked',
        child: {
          text: 'matched',
          grandchild: {}
        }
      });
      expect($node.find('[bound-with=grandchild]').html()).to.equal('matched');
    });

  });

  describe('directive render operation counting', function(){

    it('counts the number of directives processed', function(){
      expect(bound.getDirectiveRenderCount()).to.equal(0);
      $name.render(alice);
      expect(bound.getDirectiveRenderCount()).to.equal(1);
      bound.resetDirectiveRenderCount();
      expect(bound.getDirectiveRenderCount()).to.equal(0);
    });

  });

  describe('affected nodes', function(){

    it('does not operate on nodes that have no directives', function(){
      $empty.render({});
      expect(bound.getDirectiveRenderCount()).to.equal(0);
    });

    it('operates on all nodes in a single jQuery collection', function(){
      $name.add($age).render(alice);
      expect(bound.getDirectiveRenderCount()).to.equal(2);
      expect($name.html()).to.equal('alice');
      expect($age.html()).to.equal('20');
    });

  });

  describe('following directives', function(){

    it('does not remove a directive attribute after following it', function(){
      expect($name.render(alice).attr('bound-contents')).to.equal('name');
    });

    xit('errors when passed an invalid directive name');

    it('updates nodes nested within the top level node', function(){
      $empty.append($name).render(alice);
      expect($name.html()).to.equal('alice');
    });

    it('it should insert contents that are text as text and not as dom nodes', function(){
      expect($message.render({text: ''}).text()).to.equal('');
    });

    it('it should insert contents that are dom nodes as dom nodes and not as text', function(){
      expect($message.render({text: $name}).children()[0]).to.be($name[0]);
      expect(typeof $message.render({text: $name}).children()[0]).to.equal('object');
    });

  });

  describe('debug directive', function(){
    it('detects a debug directive', function(){
      sinon.stub(_, 'debug');
      $('
').render({});
      expect(_.debug.called).to.be(true);
    });
  });

  describe('scopes and multiple namespace inputs', function(){

    afterEach(function(){
      delete global.age;
    });

    it('falls back onto the global namespace for keys that are not found on the input namespace', function(){
      global.age = 10;
      expect($age.render({}).html()).to.equal('10');
    });

  });

  describe('reactive updates', function(){

    it('refollows the directives of all rendered nodes when .bound() is called on a rendered-against namespace that has changed', function(){
      $name.render(alice);
      $age.render(alice);
      _.extend(alice, {name: 'al', age: 24});
      alice.bound();
      clock.tick(0);
      expect($name.html()).to.equal('al');
      expect($age.html()).to.equal('24');
    });

    xit('does not refollow directives for properties that have not change, after calling .bound()', function(){
      $name.render(alice);
      expect(bound.getDirectiveRenderCount()).to.be(1);
      // called after no changes, so no directives should be re-run
      alice.bound();
      clock.tick(0);
      expect(bound.getDirectiveRenderCount()).to.be(1);
    });

    it('should only update the directives of nodes that were rendered against the object that has .bound() called on it', function(){
      $name.render(alice);
      $name2.render(bob);
      bob.name = 'robert';
      B(alice).set('name', 'al');
      clock.tick(0);
      expect($name.html()).to.equal('al');
      expect($name2.html()).to.equal('bob');
    });

    xit('should rerender the object that bound("set") on it', function(){
      var $node = $('
\

\

\

');
      $node.render({
        alice: alice,
        bob: bob
      });
      expect(bound.getDirectiveRenderCount()).to.equal(4);

      bob.name = 'billy-bob';
      B(alice).set('name', 'al');
      expect($node.find('[bound-with=bob]').html()).to.equal('bob');
      expect($node.find('[bound-with=alice]').html()).to.equal('al');
      expect(bound.getDirectiveRenderCount()).to.equal(5);
    });

  });

});
<|endoftext|>


<commit_before>import { createSelector } from 'reselect';
import isEmpty from 'lodash/isEmpty';
import uniqBy from 'lodash/uniqBy';
import uniq from 'lodash/uniq';
import groupBy from 'lodash/groupBy';
import remove from 'lodash/remove';
import pick from 'lodash/pick';
import {
  getYColumnValue,
  getThemeConfig,
  getTooltipConfig
} from 'utils/graphs';

import { ESP_BLACKLIST } from 'data/constants';

// constants needed for data parsing
const COLORS = [
  '#2D9290',
  '#B25BD0',
  '#7EA759',
  '#FF0D3A',
  '#687AB7',
  '#BC6332',
  '#F97DA1',
  '#00971D',
  '#F1933B',
  '#938126',
  '#2D9290',
  '#B25BD0',
  '#7EA759'
];

const AXES_CONFIG = {
  xBottom: {
    name: 'Year',
    unit: 'date',
    format: 'YYYY'
  },
  yLeft: {
    name: 'Emissions',
    unit: 'CO2e',
    format: 'number'
  }
};

const DEFAULT_SELECTIONS = {
  model: 'GCAM',
  subcategory: {
    best: 'GHG Emissions by gas with LULUCF',
    secondBest: 'GHG emissions by gas without LULUCF',
    thirdBest: 'Total GHG Emissions'
  },
  indicator: 'CO2'
};

// meta data for selectors
const getLocations = state => state.locations || null;
const getModels = state => state.models || null;
const getScenarios = state => state.scenarios || null;
const getIndicators = state => state.indicators || null;

const getLocation = state => parseInt(state.location, 10) || null;
const getModel = state => parseInt(state.model, 10) || null;
const getScenario = state => state.scenario || null;
const getIndicator = state => parseInt(state.indicator, 10) || null;
const getCategory = state => parseInt(state.category, 10) || null;
const getSubcategory = state => parseInt(state.subcategory, 10) || null;

// data for the graph
const getData = state => state.data || null;

// Selector options
export const getLocationsOptions = createSelector([getLocations], locations => {
  if (!locations || !locations.length) return [];
  return locations.map(l => ({
    label: l.name,
    value: l.id
  }));
});

const getLocationSelected = createSelector(
  [getLocationsOptions, getLocation],
  (locations, locationSelected) => {
    if (!locations) return null;
    if (!locationSelected) {
      const defaultLocation = locations.find(l => l.label === 'World');
      return defaultLocation || locations[0];
    }
    return locations.find(l => locationSelected === l.value);
  }
);

const getAvailableModels = createSelector(
  [state => state.availableModels, getLocationSelected],
  (availableModels, location) => {
    if (isEmpty(availableModels) || !location) return null;
    return availableModels[location.value];
  }
);

export const getModelsOptions = createSelector(
  [getModels, getAvailableModels],
  (models, availableModels) => {
    if (
      !models ||
      !models.length ||
      !availableModels ||
      isEmpty(availableModels)
    ) {
      return [];
    }
    const modelOptions = [];
    models.forEach(m => {
      if (availableModels.indexOf(m.id) > -1) {
        modelOptions.push({
          label: m.abbreviation,
          value: m.id,
          scenarios: m.scenario_ids
        });
      }
    });
    return modelOptions;
  }
);

export const getModelSelected = createSelector(
  [getModelsOptions, getModel],
  (models, modelSelected) => {
    if (!models) return null;
    if (!modelSelected) {
      const defaultModel = models.find(
        m => m.label === DEFAULT_SELECTIONS.model
      );
      return defaultModel || models[0];
    }
    return models.find(m => modelSelected === m.value);
  }
);

export const getScenariosOptions = createSelector(
  [getScenarios, getModelSelected],
  (scenarios, modelSelected) => {
    if (!modelSelected || !scenarios || !scenarios.length) return null;
    const filteredScenarios = scenarios.filter(
      s => modelSelected.scenarios.indexOf(s.id) > -1
    );
    return filteredScenarios.map(s => ({
      label: s.name,
      value: s.id
    }));
  }
);

export const getScenariosSelected = createSelector(
  [getScenariosOptions, getScenario, getModelSelected],
  (scenarios, scenarioSelected, model) => {
    if (!scenarios || !model) return null;
    if ((!scenarioSelected && !model.scenarios) || scenarioSelected === '') {
      return null;
    }
    if (!scenarioSelected) {
      return scenarios;
    }
    const scenarioSelectedParsed = scenarioSelected
      .split(',')
      .map(s => parseInt(s, 10));
    return scenarios.filter(s => scenarioSelectedParsed.indexOf(s.value) > -1);
  }
);

// Map the data from the API
export const filterDataByScenario = createSelector(
  [getData, getScenariosSelected],
  (data, scenarios) => {
    if (!data || isEmpty(data) || scenarios === '') return null;
    if (!scenarios) return data;
    return data.filter(
      d => scenarios.map(s => s.value).indexOf(d.scenario_id) > -1
    );
  }
);

const getIndicatorsWithData = createSelector(
  [filterDataByScenario, getIndicators, getModelSelected],
  (data, indicators, modelSelected) => {
    if (!data || !indicators || !indicators.length || !modelSelected) {
      return null;
    }
    const indicatorsWithData = uniq(data.map(d => d.indicator_id));
    return indicators.filter(
      i => i.name && indicatorsWithData.indexOf(i.id) > -1
    );
  }
);

export const getCategoryOptions = createSelector(
  [getIndicatorsWithData],
  indicators => {
    if (!indicators) return null;
    const categories = indicators.filter(i => i.category).map(i => ({
      label: i.category.name,
      value: i.category.id
    }));
    return uniqBy(categories, 'value');
  }
);

export const getCategorySelected = createSelector(
  [getCategoryOptions, getCategory],
  (categories, categorySelected) => {
    if (!categories) return null;
    if (!categorySelected) {
      return categories[0];
    }
    return categories.find(i => i.value === categorySelected);
  }
);

export const getSubCategoryOptions = createSelector(
  [getIndicatorsWithData, getCategorySelected],
  (indicators, category) => {
    if (!indicators || !category) return null;
    const indicatorsSelected = indicators.filter(
      i => i.category.id === category.value
    );
    const subcategories = (indicatorsSelected || []).map(i => ({
      label: i.subcategory.name,
      value: i.subcategory.id
    }));
    return uniqBy(subcategories, 'value');
  }
);

export const getSubcategorySelected = createSelector(
  [getSubCategoryOptions, getSubcategory],
  (subcategories, subcategorySelected) => {
    if (!subcategories) return null;
    if (!subcategorySelected) {
      const defaultSubcategory = subcategories.find(
        s =>
          s.label === DEFAULT_SELECTIONS.subcategory.best ||
          s.label === DEFAULT_SELECTIONS.subcategory.secondBest ||
          s.label === DEFAULT_SELECTIONS.subcategory.thirdBest
      );
      return defaultSubcategory || subcategories[0];
    }
    return subcategories.find(s => subcategorySelected === s.value);
  }
);

export const getIndicatorsOptions = createSelector(
  [getIndicatorsWithData, getSubcategorySelected],
  (indicators, subcategory) => {
    if (!indicators || !indicators.length || !subcategory) return [];
    let filteredIndicators = indicators;
    if (subcategory) {
      filteredIndicators = indicators.filter(
        i => i.subcategory.id === subcategory.value
      );
    }

    return filteredIndicators.map(i => ({
      label: i.name || i.composite_name || '',
      value: i.id,
      unit: i.unit,
      subcategory: i.subcategory.name
    }));
  }
);

export const getIndicatorSelected = createSelector(
  [getIndicatorsOptions, getIndicator],
  (indicators, indicatorSelected) => {
    if (!indicators || !indicators.length) return null;
    if (!indicatorSelected) {
      const defaultIndicator = indicators.find(
        i => i.label === DEFAULT_SELECTIONS.indicator
      );
      return defaultIndicator || indicators[0];
    }
    return indicators.find(i => indicatorSelected === i.value);
  }
);

export const filterDataByIndicator = createSelector(
  [filterDataByScenario, getIndicatorSelected],
  (data, indicator) => {
    if (!data || isEmpty(data) || !indicator) return null;
    return data.filter(d => d.indicator_id === indicator.value);
  }
);

export const getFiltersOptions = createSelector(
  [
    getLocationsOptions,
    getModelsOptions,
    getScenariosOptions,
    getIndicatorsOptions,
    getCategoryOptions,
    getSubCategoryOptions
  ],
  (locations, models, scenarios, indicators, category, subcategory) => ({
    locations,
    models,
    scenarios,
    indicators,
    category,
    subcategory
  })
);

export const getFiltersSelected = createSelector(
  [
    getLocationSelected,
    getModelSelected,
    getScenariosSelected,
    getCategorySelected,
    getSubcategorySelected,
    getIndicatorSelected
  ],
  (location, model, scenarios, category, subcategory, indicator) => ({
    location,
    model,
    scenarios,
    category,
    subcategory,
    indicator
  })
);

export const getChartData = createSelector([filterDataByIndicator], data => {
  if (!data) return null;
  const groupByYear = groupBy(data, 'year');
  const xValues = Object.keys(groupByYear);
  const dataMapped = [];
  xValues.forEach(x => {
    const yValues = {};
    const groupedByScenario = groupBy(groupByYear[x], 'scenario_id');
    Object.keys(groupedByScenario).forEach(i => {
      yValues[`y${i}`] = parseFloat(groupedByScenario[i][0].value);
    });
    dataMapped.push({
      x,
      ...yValues
    });
  });
  return dataMapped;
});

export const getChartXDomain = createSelector([getChartData], data => {
  if (!data) return null;
  const xValues = data.map(d => d.x);
  return { x: [Math.min(...xValues), Math.max(...xValues)] };
});

export const getChartConfig = createSelector(
  [filterDataByIndicator, getScenariosOptions, getIndicatorSelected],
  (data, scenarios, indicator) => {
    if (!data || !scenarios) return null;
    const yColumns = data.map(d => {
      const scenario = scenarios.find(
        s => parseInt(s.value, 10) === d.scenario_id
      );
      return {
        label: scenario ? scenario.label : null,
        value: getYColumnValue(d.scenario_id)
      };
    });
    const yColumnsChecked = uniqBy(yColumns, 'value');
    const theme = getThemeConfig(yColumnsChecked, COLORS);
    const tooltip = getTooltipConfig(yColumnsChecked);
    const axes = indicator
      ? {
        ...AXES_CONFIG,
        yLeft: { ...AXES_CONFIG.yLeft, unit: indicator.unit }
      }
      : AXES_CONFIG;

    return {
      axes,
      theme,
      tooltip,
      columns: {
        x: [{ label: 'year', value: 'x' }],
        y: yColumnsChecked
      }
    };
  }
);

// Parse Metadata for Modal
const getModelSelectedMetadata = createSelector(
  [getModels, getModelSelected],
  (models, modelSelected) => {
    if (!models || !modelSelected) return null;
    return models.find(m => modelSelected.value === m.id);
  }
);

const addLinktoModelSelectedMetadata = createSelector(
  [getModelSelectedMetadata],
  model => {
    if (!model) return null;
    return {
      ...model,
      Link: `/emission-pathways/models/${model.id}`
    };
  }
);

export const getScenariosSelectedMetadata = createSelector(
  [getScenarios, getScenariosSelected],
  (scenarios, scenariosSelected) => {
    if (isEmpty(scenarios) || !scenariosSelected) return null;
    const selectedScenarioIds = scenariosSelected.map(s => s.value);
    const scenariosMetadata = scenarios.filter(
      s => selectedScenarioIds.indexOf(s.id) > -1
    );
    return (
      scenariosMetadata.length > 0 &&
      scenariosMetadata.map(s => ({
        name: s.name,
        description: s.description,
        Link: `/emission-pathways/scenarios/${s.id}`
      }))
    );
  }
);

export const getIndicatorSelectedMetadata = createSelector(
  [getIndicators, getIndicatorSelected],
  (indicators, indicatorSelected) => {
    if (!indicators || !indicatorSelected) return null;
    return indicators.find(i => indicatorSelected.value === i.id);
  }
);

export const filterModelsByBlackList = createSelector(
  [addLinktoModelSelectedMetadata],
  data => {
    if (!data || isEmpty(data)) return null;
    const whiteList = remove(
      Object.keys(data),
      n => ESP_BLACKLIST.models.indexOf(n) === -1
    );
    return pick(data, whiteList);
  }
);

const filterIndicatorsByBlackList = createSelector(
  [getIndicatorSelectedMetadata],
  data => {
    if (!data || isEmpty(data)) return null;
    const whiteList = remove(
      Object.keys(data),
      n => ESP_BLACKLIST.indicators.indexOf(n) === -1
    );
    return pick(data, whiteList);
  }
);

export const parseObjectsInIndicators = createSelector(
  [filterIndicatorsByBlackList],
  data => {
    if (isEmpty(data)) return null;
    const parsedData = {};
    Object.keys(data).forEach(key => {
      let fieldData = data[key];
      if (
        fieldData &&
        typeof fieldData !== 'string' &&
        typeof fieldData !== 'number'
      ) {
        fieldData = fieldData.name;
      }
      parsedData[key] = fieldData;
    });
    return parsedData;
  }
);

export const getModalData = createSelector(
  [
    filterModelsByBlackList,
    getScenariosSelectedMetadata,
    parseObjectsInIndicators
  ],
  (model, scenarios, indicator) => [model, scenarios, indicator]
);

export default {
  getChartData,
  getChartXDomain,
  getChartConfig,
  getFiltersOptions,
  getFiltersSelected
};
<commit_msg>Show full name instead of abbr in esp graph dropdown<commit_after>import { createSelector } from 'reselect';
import isEmpty from 'lodash/isEmpty';
import uniqBy from 'lodash/uniqBy';
import uniq from 'lodash/uniq';
import groupBy from 'lodash/groupBy';
import remove from 'lodash/remove';
import pick from 'lodash/pick';
import {
  getYColumnValue,
  getThemeConfig,
  getTooltipConfig
} from 'utils/graphs';

import { ESP_BLACKLIST } from 'data/constants';

// constants needed for data parsing
const COLORS = [
  '#2D9290',
  '#B25BD0',
  '#7EA759',
  '#FF0D3A',
  '#687AB7',
  '#BC6332',
  '#F97DA1',
  '#00971D',
  '#F1933B',
  '#938126',
  '#2D9290',
  '#B25BD0',
  '#7EA759'
];

const AXES_CONFIG = {
  xBottom: {
    name: 'Year',
    unit: 'date',
    format: 'YYYY'
  },
  yLeft: {
    name: 'Emissions',
    unit: 'CO2e',
    format: 'number'
  }
};

const DEFAULT_SELECTIONS = {
  model: 'GCAM',
  subcategory: {
    best: 'GHG Emissions by gas with LULUCF',
    secondBest: 'GHG emissions by gas without LULUCF',
    thirdBest: 'Total GHG Emissions'
  },
  indicator: 'CO2'
};

// meta data for selectors
const getLocations = state => state.locations || null;
const getModels = state => state.models || null;
const getScenarios = state => state.scenarios || null;
const getIndicators = state => state.indicators || null;

const getLocation = state => parseInt(state.location, 10) || null;
const getModel = state => parseInt(state.model, 10) || null;
const getScenario = state => state.scenario || null;
const getIndicator = state => parseInt(state.indicator, 10) || null;
const getCategory = state => parseInt(state.category, 10) || null;
const getSubcategory = state => parseInt(state.subcategory, 10) || null;

// data for the graph
const getData = state => state.data || null;

// Selector options
export const getLocationsOptions = createSelector([getLocations], locations => {
  if (!locations || !locations.length) return [];
  return locations.map(l => ({
    label: l.name,
    value: l.id
  }));
});

const getLocationSelected = createSelector(
  [getLocationsOptions, getLocation],
  (locations, locationSelected) => {
    if (!locations) return null;
    if (!locationSelected) {
      const defaultLocation = locations.find(l => l.label === 'World');
      return defaultLocation || locations[0];
    }
    return locations.find(l => locationSelected === l.value);
  }
);

const getAvailableModels = createSelector(
  [state => state.availableModels, getLocationSelected],
  (availableModels, location) => {
    if (isEmpty(availableModels) || !location) return null;
    return availableModels[location.value];
  }
);

export const getModelsOptions = createSelector(
  [getModels, getAvailableModels],
  (models, availableModels) => {
    if (
      !models ||
      !models.length ||
      !availableModels ||
      isEmpty(availableModels)
    ) {
      return [];
    }
    const modelOptions = [];
    models.forEach(m => {
      if (availableModels.indexOf(m.id) > -1) {
        modelOptions.push({
          label: m.full_name,
          value: m.id,
          scenarios: m.scenario_ids
        });
      }
    });
    return modelOptions;
  }
);

export const getModelSelected = createSelector(
  [getModelsOptions, getModel],
  (models, modelSelected) => {
    if (!models) return null;
    if (!modelSelected) {
      const defaultModel = models.find(
        m => m.label === DEFAULT_SELECTIONS.model
      );
      return defaultModel || models[0];
    }
    return models.find(m => modelSelected === m.value);
  }
);

export const getScenariosOptions = createSelector(
  [getScenarios, getModelSelected],
  (scenarios, modelSelected) => {
    if (!modelSelected || !scenarios || !scenarios.length) return null;
    const filteredScenarios = scenarios.filter(
      s => modelSelected.scenarios.indexOf(s.id) > -1
    );
    return filteredScenarios.map(s => ({
      label: s.name,
      value: s.id
    }));
  }
);

export const getScenariosSelected = createSelector(
  [getScenariosOptions, getScenario, getModelSelected],
  (scenarios, scenarioSelected, model) => {
    if (!scenarios || !model) return null;
    if ((!scenarioSelected && !model.scenarios) || scenarioSelected === '') {
      return null;
    }
    if (!scenarioSelected) {
      return scenarios;
    }
    const scenarioSelectedParsed = scenarioSelected
      .split(',')
      .map(s => parseInt(s, 10));
    return scenarios.filter(s => scenarioSelectedParsed.indexOf(s.value) > -1);
  }
);

// Map the data from the API
export const filterDataByScenario = createSelector(
  [getData, getScenariosSelected],
  (data, scenarios) => {
    if (!data || isEmpty(data) || scenarios === '') return null;
    if (!scenarios) return data;
    return data.filter(
      d => scenarios.map(s => s.value).indexOf(d.scenario_id) > -1
    );
  }
);

const getIndicatorsWithData = createSelector(
  [filterDataByScenario, getIndicators, getModelSelected],
  (data, indicators, modelSelected) => {
    if (!data || !indicators || !indicators.length || !modelSelected) {
      return null;
    }
    const indicatorsWithData = uniq(data.map(d => d.indicator_id));
    return indicators.filter(
      i => i.name && indicatorsWithData.indexOf(i.id) > -1
    );
  }
);

export const getCategoryOptions = createSelector(
  [getIndicatorsWithData],
  indicators => {
    if (!indicators) return null;
    const categories = indicators.filter(i => i.category).map(i => ({
      label: i.category.name,
      value: i.category.id
    }));
    return uniqBy(categories, 'value');
  }
);

export const getCategorySelected = createSelector(
  [getCategoryOptions, getCategory],
  (categories, categorySelected) => {
    if (!categories) return null;
    if (!categorySelected) {
      return categories[0];
    }
    return categories.find(i => i.value === categorySelected);
  }
);

export const getSubCategoryOptions = createSelector(
  [getIndicatorsWithData, getCategorySelected],
  (indicators, category) => {
    if (!indicators || !category) return null;
    const indicatorsSelected = indicators.filter(
      i => i.category.id === category.value
    );
    const subcategories = (indicatorsSelected || []).map(i => ({
      label: i.subcategory.name,
      value: i.subcategory.id
    }));
    return uniqBy(subcategories, 'value');
  }
);

export const getSubcategorySelected = createSelector(
  [getSubCategoryOptions, getSubcategory],
  (subcategories, subcategorySelected) => {
    if (!subcategories) return null;
    if (!subcategorySelected) {
      const defaultSubcategory = subcategories.find(
        s =>
          s.label === DEFAULT_SELECTIONS.subcategory.best ||
          s.label === DEFAULT_SELECTIONS.subcategory.secondBest ||
          s.label === DEFAULT_SELECTIONS.subcategory.thirdBest
      );
      return defaultSubcategory || subcategories[0];
    }
    return subcategories.find(s => subcategorySelected === s.value);
  }
);

export const getIndicatorsOptions = createSelector(
  [getIndicatorsWithData, getSubcategorySelected],
  (indicators, subcategory) => {
    if (!indicators || !indicators.length || !subcategory) return [];
    let filteredIndicators = indicators;
    if (subcategory) {
      filteredIndicators = indicators.filter(
        i => i.subcategory.id === subcategory.value
      );
    }

    return filteredIndicators.map(i => ({
      label: i.name || i.composite_name || '',
      value: i.id,
      unit: i.unit,
      subcategory: i.subcategory.name
    }));
  }
);

export const getIndicatorSelected = createSelector(
  [getIndicatorsOptions, getIndicator],
  (indicators, indicatorSelected) => {
    if (!indicators || !indicators.length) return null;
    if (!indicatorSelected) {
      const defaultIndicator = indicators.find(
        i => i.label === DEFAULT_SELECTIONS.indicator
      );
      return defaultIndicator || indicators[0];
    }
    return indicators.find(i => indicatorSelected === i.value);
  }
);

export const filterDataByIndicator = createSelector(
  [filterDataByScenario, getIndicatorSelected],
  (data, indicator) => {
    if (!data || isEmpty(data) || !indicator) return null;
    return data.filter(d => d.indicator_id === indicator.value);
  }
);

export const getFiltersOptions = createSelector(
  [
    getLocationsOptions,
    getModelsOptions,
    getScenariosOptions,
    getIndicatorsOptions,
    getCategoryOptions,
    getSubCategoryOptions
  ],
  (locations, models, scenarios, indicators, category, subcategory) => ({
    locations,
    models,
    scenarios,
    indicators,
    category,
    subcategory
  })
);

export const getFiltersSelected = createSelector(
  [
    getLocationSelected,
    getModelSelected,
    getScenariosSelected,
    getCategorySelected,
    getSubcategorySelected,
    getIndicatorSelected
  ],
  (location, model, scenarios, category, subcategory, indicator) => ({
    location,
    model,
    scenarios,
    category,
    subcategory,
    indicator
  })
);

export const getChartData = createSelector([filterDataByIndicator], data => {
  if (!data) return null;
  const groupByYear = groupBy(data, 'year');
  const xValues = Object.keys(groupByYear);
  const dataMapped = [];
  xValues.forEach(x => {
    const yValues = {};
    const groupedByScenario = groupBy(groupByYear[x], 'scenario_id');
    Object.keys(groupedByScenario).forEach(i => {
      yValues[`y${i}`] = parseFloat(groupedByScenario[i][0].value);
    });
    dataMapped.push({
      x,
      ...yValues
    });
  });
  return dataMapped;
});

export const getChartXDomain = createSelector([getChartData], data => {
  if (!data) return null;
  const xValues = data.map(d => d.x);
  return { x: [Math.min(...xValues), Math.max(...xValues)] };
});

export const getChartConfig = createSelector(
  [filterDataByIndicator, getScenariosOptions, getIndicatorSelected],
  (data, scenarios, indicator) => {
    if (!data || !scenarios) return null;
    const yColumns = data.map(d => {
      const scenario = scenarios.find(
        s => parseInt(s.value, 10) === d.scenario_id
      );
      return {
        label: scenario ? scenario.label : null,
        value: getYColumnValue(d.scenario_id)
      };
    });
    const yColumnsChecked = uniqBy(yColumns, 'value');
    const theme = getThemeConfig(yColumnsChecked, COLORS);
    const tooltip = getTooltipConfig(yColumnsChecked);
    const axes = indicator
      ? {
        ...AXES_CONFIG,
        yLeft: { ...AXES_CONFIG.yLeft, unit: indicator.unit }
      }
      : AXES_CONFIG;

    return {
      axes,
      theme,
      tooltip,
      columns: {
        x: [{ label: 'year', value: 'x' }],
        y: yColumnsChecked
      }
    };
  }
);

// Parse Metadata for Modal
const getModelSelectedMetadata = createSelector(
  [getModels, getModelSelected],
  (models, modelSelected) => {
    if (!models || !modelSelected) return null;
    return models.find(m => modelSelected.value === m.id);
  }
);

const addLinktoModelSelectedMetadata = createSelector(
  [getModelSelectedMetadata],
  model => {
    if (!model) return null;
    return {
      ...model,
      Link: `/emission-pathways/models/${model.id}`
    };
  }
);

export const getScenariosSelectedMetadata = createSelector(
  [getScenarios, getScenariosSelected],
  (scenarios, scenariosSelected) => {
    if (isEmpty(scenarios) || !scenariosSelected) return null;
    const selectedScenarioIds = scenariosSelected.map(s => s.value);
    const scenariosMetadata = scenarios.filter(
      s => selectedScenarioIds.indexOf(s.id) > -1
    );
    return (
      scenariosMetadata.length > 0 &&
      scenariosMetadata.map(s => ({
        name: s.name,
        description: s.description,
        Link: `/emission-pathways/scenarios/${s.id}`
      }))
    );
  }
);

export const getIndicatorSelectedMetadata = createSelector(
  [getIndicators, getIndicatorSelected],
  (indicators, indicatorSelected) => {
    if (!indicators || !indicatorSelected) return null;
    return indicators.find(i => indicatorSelected.value === i.id);
  }
);

export const filterModelsByBlackList = createSelector(
  [addLinktoModelSelectedMetadata],
  data => {
    if (!data || isEmpty(data)) return null;
    const whiteList = remove(
      Object.keys(data),
      n => ESP_BLACKLIST.models.indexOf(n) === -1
    );
    return pick(data, whiteList);
  }
);

const filterIndicatorsByBlackList = createSelector(
  [getIndicatorSelectedMetadata],
  data => {
    if (!data || isEmpty(data)) return null;
    const whiteList = remove(
      Object.keys(data),
      n => ESP_BLACKLIST.indicators.indexOf(n) === -1
    );
    return pick(data, whiteList);
  }
);

export const parseObjectsInIndicators = createSelector(
  [filterIndicatorsByBlackList],
  data => {
    if (isEmpty(data)) return null;
    const parsedData = {};
    Object.keys(data).forEach(key => {
      let fieldData = data[key];
      if (
        fieldData &&
        typeof fieldData !== 'string' &&
        typeof fieldData !== 'number'
      ) {
        fieldData = fieldData.name;
      }
      parsedData[key] = fieldData;
    });
    return parsedData;
  }
);

export const getModalData = createSelector(
  [
    filterModelsByBlackList,
    getScenariosSelectedMetadata,
    parseObjectsInIndicators
  ],
  (model, scenarios, indicator) => [model, scenarios, indicator]
);

export default {
  getChartData,
  getChartXDomain,
  getChartConfig,
  getFiltersOptions,
  getFiltersSelected
};
<|endoftext|>