<commit_before>/*
 * MinIO Javascript Library for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import stream from 'stream'
import mime from 'mime-types'

// Returns a wrapper function that will promisify a given callback function.
// It will preserve 'this'.
export function promisify(fn) {
  return function() {
    // If the last argument is a function, assume its the callback.
    let callback = arguments[arguments.length - 1]

    // If the callback is given, don't promisify, just pass straight in.
    if (typeof callback === 'function') return fn.apply(this, arguments)

    // Otherwise, create a new set of arguments, and wrap
    // it in a promise.
    let args = [...arguments]

    return new Promise((resolve, reject) => {
      // Add the callback function.
      args.push((err, value) => {
        if (err) return reject(err)

        resolve(value)
      })

      // Call the function with our special adaptor callback added.
      fn.apply(this, args)
    })
  }
}

// All characters in string which are NOT unreserved should be percent encoded.
// Unreserved characers are : ALPHA / DIGIT / "-" / "." / "_" / "~"
// Reference https://tools.ietf.org/html/rfc3986#section-2.2
export function uriEscape(string) {
  return string.split('').reduce((acc, elem) => {
    let buf = Buffer.from(elem)
    if (buf.length === 1) {
      // length 1 indicates that elem is not a unicode character.
      // Check if it is an unreserved characer.
      if ('A' <= elem && elem <= 'Z' ||
          'a' <= elem && elem <= 'z' ||
          '0' <= elem && elem <= '9' ||
          elem === '_' ||
          elem === '.' ||
          elem === '~' ||
          elem === '-')
      {
        // Unreserved characer should not be encoded.
        acc = acc + elem
        return acc
      }
    }
    // elem needs encoding - i.e elem should be encoded if it's not unreserved
    // character or if it's a unicode character.
    for (var i = 0; i < buf.length; i++) {
      acc = acc + "%" + buf[i].toString(16).toUpperCase()
    }
    return acc
  }, '')
}

export function uriResourceEscape(string) {
  return uriEscape(string).replace(/%2F/g, '/')
}

export function getScope(region, date) {
  return `${makeDateShort(date)}/${region}/s3/aws4_request`
}

// isAmazonEndpoint - true if endpoint is 's3.amazonaws.com' or 's3.cn-north-1.amazonaws.com.cn'
export function isAmazonEndpoint(endpoint) {
  return endpoint === 's3.amazonaws.com' || endpoint === 's3.cn-north-1.amazonaws.com.cn'
}

// isVirtualHostStyle - verify if bucket name is support with virtual
// hosts. bucketNames with periods should be always treated as path
// style if the protocol is 'https:', this is due to SSL wildcard
// limitation. For all other buckets and Amazon S3 endpoint we will
// default to virtual host style.
export function isVirtualHostStyle(endpoint, protocol, bucket, pathStyle) {
  if (protocol === 'https:' && bucket.indexOf('.') > -1) {
    return false
  }
  return isAmazonEndpoint(endpoint) || !pathStyle
}

var ipv4Regex = /^(\d{1,3}\.){3,3}\d{1,3}$/

export function isValidIP(ip) {
  return ipv4Regex.test(ip)
}

// isValidEndpoint - true if endpoint is valid domain.
export function isValidEndpoint(endpoint) {
  if (!isValidDomain(endpoint) && !isValidIP(endpoint)) {
    return false
  }
  // Return true.
  return true
}

// isValidDomain - true if input host is a valid domain.
export function isValidDomain(host) {
  if (!isString(host)) return false
  // See RFC 1035, RFC 3696.
  if (host.length === 0 || host.length > 255) {
    return false
  }
  // Host cannot start or end with a '-'
  if (host[0] === '-' || host.substr(-1) === '-') {
    return false
  }
  // Host cannot start or end with a '_'
  if (host[0] === '_' || host.substr(-1) === '_') {
    return false
  }
  // Host cannot start or end with a '.'
  if (host[0] === '.' || host.substr(-1) === '.') {
    return false
  }
  var alphaNumerics = '`~!@#$%^&*()+={}[]|\\"\';:><?/'.split('')
  // All non alphanumeric characters are invalid.
  for (var i in alphaNumerics) {
    if (host.indexOf(alphaNumerics[i]) > -1) {
      return false
    }
  }
  // No need to regexp match, since the list is non-exhaustive.
  // We let it be valid and fail later.
  return true
}

// Probes contentType using file extensions.
// For example: probeContentType('file.png') returns 'image/png'.
export function probeContentType(path) {
  let contentType = mime.lookup(path)
  if (!contentType) {
    contentType = 'application/octet-stream'
  }
  return contentType
}

// isValidPort - is input port valid.
export function isValidPort(port) {
  // verify if port is a number.
  if (!isNumber(port)) return false
  // port cannot be negative.
  if (port < 0) return false
  // port '0' is valid and special case return true.
  if (port === 0) return true
  var min_port = 1
  var max_port = 65535
  // Verify if port is in range.
  return port >= min_port && port <= max_port
}

export function isValidBucketName(bucket) {
  if (!isString(bucket)) return false

  // bucket length should be less than and no more than 63
  // characters long.
  if (bucket.length < 3 || bucket.length > 63) {
    return false
  }
  // bucket with successive periods is invalid.
  if (bucket.indexOf('..') > -1) {
    return false
  }
  // bucket cannot have ip address style.
  if (bucket.match(/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)) {
    return false
  }
  // bucket should begin with alphabet/number and end with alphabet/number,
  // with alphabet/number/.- in the middle.
  if (bucket.match(/^[a-z0-9][a-z0-9.-]+[a-z0-9]$/)) {
    return true
  }
  return false
}

// check if objectName is a valid object name
export function isValidObjectName(objectName) {
  if (!isValidPrefix(objectName)) return false
  if (objectName.length === 0) return false
  return true
}

// check if prefix is valid
export function isValidPrefix(prefix) {
  if (!isString(prefix)) return false
  if (prefix.length > 1024) return false
  return true
}

// check if typeof arg number
export function isNumber(arg) {
  return typeof(arg) === 'number'
}

// check if typeof arg function
export function isFunction(arg) {
  return typeof(arg) === 'function'
}

// check if typeof arg string
export function isString(arg) {
  return typeof(arg) === 'string'
}

// check if typeof arg object
export function isObject(arg) {
  return typeof(arg) === 'object' && arg !== null
}

// check if object is readable stream
export function isReadableStream(arg) {
  return isObject(arg) && isFunction(arg._read)
}

// check if arg is boolean
export function isBoolean(arg) {
  return typeof(arg) === 'boolean'
}

// check if arg is array
export function isArray(arg) {
  return Array.isArray(arg)
}

// check if arg is a valid date
export function isValidDate(arg) {
  return arg instanceof Date && !isNaN(arg)
}

// Create a Date string with format:
// 'YYYYMMDDTHHmmss' + Z
export function makeDateLong(date) {
  date = date || new Date()

  // Gives format like: '2017-08-07T16:28:59.889Z'
  date = date.toISOString()

  return date.substr(0, 4) +
    date.substr(5, 2) +
    date.substr(8, 5) +
    date.substr(14, 2) +
    date.substr(17, 2) + 'Z'
}

// Create a Date string with format:
// 'YYYYMMDD'
export function makeDateShort(date) {
  date = date || new Date()

  // Gives format like: '2017-08-07T16:28:59.889Z'
  date = date.toISOString()

  return date.substr(0, 4) +
    date.substr(5, 2) +
    date.substr(8, 2)
}

// pipesetup sets up pipe() from left to right os streams array
// pipesetup will also make sure that error emitted at any of the upstream Stream
// will be emitted at the last stream. This makes error handling simple
export function pipesetup(...streams) {
  return streams.reduce((src, dst) => {
    src.on('error', err => dst.emit('error', err))
    return src.pipe(dst)
  })
}

// return a Readable stream that emits data
export function readableStream(data) {
  var s = new stream.Readable()
  s._read = () => {}
  s.push(data)
  s.push(null)
  return s
}

// Process metadata to insert appropriate value to `content-type` attribute
export function insertContentType(metaData, filePath) {
  // check if content-type attribute present in metaData
  for (var key in metaData) {
    if (key.toLowerCase() === 'content-type') {
      return metaData
    }
  }
  // if `content-type` attribute is not present in metadata,
  // then infer it from the extension in filePath
  var newMetadata = Object.assign({}, metaData)
  newMetadata['content-type'] = probeContentType(filePath)
  return newMetadata
}

// Function prepends metadata with the appropriate prefix if it is not already on
export function prependXAMZMeta(metaData) {
  var newMetadata = Object.assign({}, metaData)
  for (var key in metaData) {
    if(!isAmzHeader(key) && !isSupportedHeader(key) && !isStorageclassHeader(key)) {
      newMetadata["X-Amz-Meta-" + key ] = newMetadata[key]
      delete newMetadata[key]
    }
  }
  return newMetadata
}

// Checks if it is a valid header according to the AmazonS3 API
export function isAmzHeader(key) {
  var temp = key.toLowerCase()
  return temp.startsWith("x-amz-meta-") || temp === "x-amz-acl" || temp.startsWith("x-amz-server-side-encryption-") || temp === "x-amz-server-side-encryption"
}
//Checks if it is a supported Header
export function isSupportedHeader(key) {
  var supported_headers = [
    'content-type',
    'cache-control',
    'content-encoding',
    'content-disposition',
    'content-language',
    'x-amz-website-redirect-location']
  return (supported_headers.indexOf(key.toLowerCase()) > -1)
}
//Checks if it is a storage header
export function isStorageclassHeader(key) {
  return key.toLowerCase() === "x-amz-storage-class"
}

export function extractMetadata(metaData) {
  var newMetadata = {}
  for (var key in metaData) {
    if(isSupportedHeader(key) || isStorageclassHeader(key) || isAmzHeader(key)) {
      if(key.toLowerCase().startsWith("x-amz-meta-")) {
        newMetadata[key.slice(11,key.length)] = metaData[key]
      } else {
        newMetadata[key] = metaData[key]
      }
    }
  }
  return newMetadata
}
<commit_msg>Allows dot char, '.', at the end of domain name (#885)<commit_after>/*
 * MinIO Javascript Library for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import stream from 'stream'
import mime from 'mime-types'

// Returns a wrapper function that will promisify a given callback function.
// It will preserve 'this'.
export function promisify(fn) {
  return function() {
    // If the last argument is a function, assume its the callback.
    let callback = arguments[arguments.length - 1]

    // If the callback is given, don't promisify, just pass straight in.
    if (typeof callback === 'function') return fn.apply(this, arguments)

    // Otherwise, create a new set of arguments, and wrap
    // it in a promise.
    let args = [...arguments]

    return new Promise((resolve, reject) => {
      // Add the callback function.
      args.push((err, value) => {
        if (err) return reject(err)

        resolve(value)
      })

      // Call the function with our special adaptor callback added.
      fn.apply(this, args)
    })
  }
}

// All characters in string which are NOT unreserved should be percent encoded.
// Unreserved characers are : ALPHA / DIGIT / "-" / "." / "_" / "~"
// Reference https://tools.ietf.org/html/rfc3986#section-2.2
export function uriEscape(string) {
  return string.split('').reduce((acc, elem) => {
    let buf = Buffer.from(elem)
    if (buf.length === 1) {
      // length 1 indicates that elem is not a unicode character.
      // Check if it is an unreserved characer.
      if ('A' <= elem && elem <= 'Z' ||
          'a' <= elem && elem <= 'z' ||
          '0' <= elem && elem <= '9' ||
          elem === '_' ||
          elem === '.' ||
          elem === '~' ||
          elem === '-')
      {
        // Unreserved characer should not be encoded.
        acc = acc + elem
        return acc
      }
    }
    // elem needs encoding - i.e elem should be encoded if it's not unreserved
    // character or if it's a unicode character.
    for (var i = 0; i < buf.length; i++) {
      acc = acc + "%" + buf[i].toString(16).toUpperCase()
    }
    return acc
  }, '')
}

export function uriResourceEscape(string) {
  return uriEscape(string).replace(/%2F/g, '/')
}

export function getScope(region, date) {
  return `${makeDateShort(date)}/${region}/s3/aws4_request`
}

// isAmazonEndpoint - true if endpoint is 's3.amazonaws.com' or 's3.cn-north-1.amazonaws.com.cn'
export function isAmazonEndpoint(endpoint) {
  return endpoint === 's3.amazonaws.com' || endpoint === 's3.cn-north-1.amazonaws.com.cn'
}

// isVirtualHostStyle - verify if bucket name is support with virtual
// hosts. bucketNames with periods should be always treated as path
// style if the protocol is 'https:', this is due to SSL wildcard
// limitation. For all other buckets and Amazon S3 endpoint we will
// default to virtual host style.
export function isVirtualHostStyle(endpoint, protocol, bucket, pathStyle) {
  if (protocol === 'https:' && bucket.indexOf('.') > -1) {
    return false
  }
  return isAmazonEndpoint(endpoint) || !pathStyle
}

var ipv4Regex = /^(\d{1,3}\.){3,3}\d{1,3}$/

export function isValidIP(ip) {
  return ipv4Regex.test(ip)
}

// isValidEndpoint - true if endpoint is valid domain.
export function isValidEndpoint(endpoint) {
  if (!isValidDomain(endpoint) && !isValidIP(endpoint)) {
    return false
  }
  // Return true.
  return true
}

// isValidDomain - true if input host is a valid domain.
export function isValidDomain(host) {
  if (!isString(host)) return false
  // See RFC 1035, RFC 3696.
  if (host.length === 0 || host.length > 255) {
    return false
  }
  // Host cannot start or end with a '-'
  if (host[0] === '-' || host.substr(-1) === '-') {
    return false
  }
  // Host cannot start or end with a '_'
  if (host[0] === '_' || host.substr(-1) === '_') {
    return false
  }
  // Host cannot start with a '.'
  if (host[0] === '.') {
    return false
  }
  var alphaNumerics = '`~!@#$%^&*()+={}[]|\\"\';:><?/'.split('')
  // All non alphanumeric characters are invalid.
  for (var i in alphaNumerics) {
    if (host.indexOf(alphaNumerics[i]) > -1) {
      return false
    }
  }
  // No need to regexp match, since the list is non-exhaustive.
  // We let it be valid and fail later.
  return true
}

// Probes contentType using file extensions.
// For example: probeContentType('file.png') returns 'image/png'.
export function probeContentType(path) {
  let contentType = mime.lookup(path)
  if (!contentType) {
    contentType = 'application/octet-stream'
  }
  return contentType
}

// isValidPort - is input port valid.
export function isValidPort(port) {
  // verify if port is a number.
  if (!isNumber(port)) return false
  // port cannot be negative.
  if (port < 0) return false
  // port '0' is valid and special case return true.
  if (port === 0) return true
  var min_port = 1
  var max_port = 65535
  // Verify if port is in range.
  return port >= min_port && port <= max_port
}

export function isValidBucketName(bucket) {
  if (!isString(bucket)) return false

  // bucket length should be less than and no more than 63
  // characters long.
  if (bucket.length < 3 || bucket.length > 63) {
    return false
  }
  // bucket with successive periods is invalid.
  if (bucket.indexOf('..') > -1) {
    return false
  }
  // bucket cannot have ip address style.
  if (bucket.match(/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)) {
    return false
  }
  // bucket should begin with alphabet/number and end with alphabet/number,
  // with alphabet/number/.- in the middle.
  if (bucket.match(/^[a-z0-9][a-z0-9.-]+[a-z0-9]$/)) {
    return true
  }
  return false
}

// check if objectName is a valid object name
export function isValidObjectName(objectName) {
  if (!isValidPrefix(objectName)) return false
  if (objectName.length === 0) return false
  return true
}

// check if prefix is valid
export function isValidPrefix(prefix) {
  if (!isString(prefix)) return false
  if (prefix.length > 1024) return false
  return true
}

// check if typeof arg number
export function isNumber(arg) {
  return typeof(arg) === 'number'
}

// check if typeof arg function
export function isFunction(arg) {
  return typeof(arg) === 'function'
}

// check if typeof arg string
export function isString(arg) {
  return typeof(arg) === 'string'
}

// check if typeof arg object
export function isObject(arg) {
  return typeof(arg) === 'object' && arg !== null
}

// check if object is readable stream
export function isReadableStream(arg) {
  return isObject(arg) && isFunction(arg._read)
}

// check if arg is boolean
export function isBoolean(arg) {
  return typeof(arg) === 'boolean'
}

// check if arg is array
export function isArray(arg) {
  return Array.isArray(arg)
}

// check if arg is a valid date
export function isValidDate(arg) {
  return arg instanceof Date && !isNaN(arg)
}

// Create a Date string with format:
// 'YYYYMMDDTHHmmss' + Z
export function makeDateLong(date) {
  date = date || new Date()

  // Gives format like: '2017-08-07T16:28:59.889Z'
  date = date.toISOString()

  return date.substr(0, 4) +
    date.substr(5, 2) +
    date.substr(8, 5) +
    date.substr(14, 2) +
    date.substr(17, 2) + 'Z'
}

// Create a Date string with format:
// 'YYYYMMDD'
export function makeDateShort(date) {
  date = date || new Date()

  // Gives format like: '2017-08-07T16:28:59.889Z'
  date = date.toISOString()

  return date.substr(0, 4) +
    date.substr(5, 2) +
    date.substr(8, 2)
}

// pipesetup sets up pipe() from left to right os streams array
// pipesetup will also make sure that error emitted at any of the upstream Stream
// will be emitted at the last stream. This makes error handling simple
export function pipesetup(...streams) {
  return streams.reduce((src, dst) => {
    src.on('error', err => dst.emit('error', err))
    return src.pipe(dst)
  })
}

// return a Readable stream that emits data
export function readableStream(data) {
  var s = new stream.Readable()
  s._read = () => {}
  s.push(data)
  s.push(null)
  return s
}

// Process metadata to insert appropriate value to `content-type` attribute
export function insertContentType(metaData, filePath) {
  // check if content-type attribute present in metaData
  for (var key in metaData) {
    if (key.toLowerCase() === 'content-type') {
      return metaData
    }
  }
  // if `content-type` attribute is not present in metadata,
  // then infer it from the extension in filePath
  var newMetadata = Object.assign({}, metaData)
  newMetadata['content-type'] = probeContentType(filePath)
  return newMetadata
}

// Function prepends metadata with the appropriate prefix if it is not already on
export function prependXAMZMeta(metaData) {
  var newMetadata = Object.assign({}, metaData)
  for (var key in metaData) {
    if(!isAmzHeader(key) && !isSupportedHeader(key) && !isStorageclassHeader(key)) {
      newMetadata["X-Amz-Meta-" + key ] = newMetadata[key]
      delete newMetadata[key]
    }
  }
  return newMetadata
}

// Checks if it is a valid header according to the AmazonS3 API
export function isAmzHeader(key) {
  var temp = key.toLowerCase()
  return temp.startsWith("x-amz-meta-") || temp === "x-amz-acl" || temp.startsWith("x-amz-server-side-encryption-") || temp === "x-amz-server-side-encryption"
}
//Checks if it is a supported Header
export function isSupportedHeader(key) {
  var supported_headers = [
    'content-type',
    'cache-control',
    'content-encoding',
    'content-disposition',
    'content-language',
    'x-amz-website-redirect-location']
  return (supported_headers.indexOf(key.toLowerCase()) > -1)
}
//Checks if it is a storage header
export function isStorageclassHeader(key) {
  return key.toLowerCase() === "x-amz-storage-class"
}

export function extractMetadata(metaData) {
  var newMetadata = {}
  for (var key in metaData) {
    if(isSupportedHeader(key) || isStorageclassHeader(key) || isAmzHeader(key)) {
      if(key.toLowerCase().startsWith("x-amz-meta-")) {
        newMetadata[key.slice(11,key.length)] = metaData[key]
      } else {
        newMetadata[key] = metaData[key]
      }
    }
  }
  return newMetadata
}
<|endoftext|>


<commit_before>/**
 * @fileOverview Wrapper component to make charts adapt to the size of parent * DOM
 */
import React, { Component, PropTypes } from 'react';
import ContainerDimensions from 'react-container-dimensions';
import pureRender from '../util/PureRender';
import { getPercentValue, isPercent } from '../util/DataUtils';
import { warn } from '../util/LogUtils';

const render = ({ aspect, width, height, minWidth, minHeight, container, children }) => {

  warn(isPercent(width) || isPercent(height),
    `The width(%s) and height(%s) are both fixed numbers,
     maybe you don't need to use a ResponsiveContainer.`,
    width, height
  );

  warn(!aspect || aspect > 0,
       'The aspect(%s) must be greater than zero.',
       aspect);

  let calculatedWidth = getPercentValue(width, container.width);
  let calculatedHeight = getPercentValue(height, container.height);

  if (aspect && aspect > 0) {
    // Preserve the desired aspect ratio
    if (calculatedWidth / calculatedHeight > aspect) {
      calculatedWidth = calculatedHeight * aspect;
    } else if (calculatedWidth / calculatedHeight < aspect) {
      calculatedHeight = calculatedWidth / aspect;
    }
  }

  warn(calculatedWidth > 0 && calculatedHeight > 0,
    `The width(%s) and height(%s) of chart should be greater than 0,
     please check the style of container, or the props width(%s) and height(%s),
     or add a minWidth(%s) or minHeight(%s) or use aspect(%s) to control the
     height and width.`,
    calculatedWidth, calculatedHeight, width, height, minWidth, minHeight, aspect
  );

  return React.cloneElement(children, {
    width: calculatedWidth,
    height: calculatedHeight,
  });
};

const ResponsiveContainer = props => {
  const { minWidth, minHeight, width, height } = props;
  const style = { width, height, minWidth, minHeight };
  return (

      <ContainerDimensions>
        {
          container =>
            render({
              container,
              ...props,
            })
      }
      </ContainerDimensions>

  );
};

ResponsiveContainer.displayName = 'ResponsiveContainer';
ResponsiveContainer.propTypes = {
  aspect: PropTypes.number,
  width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  minHeight: PropTypes.number,
  minWidth: PropTypes.number,
  children: PropTypes.node.isRequired,
};

ResponsiveContainer.defaultProps = {
  width: '100%',
  height: '100%',
};

export default ResponsiveContainer;
<commit_msg>Don't double percentage.<commit_after>/**
 * @fileOverview Wrapper component to make charts adapt to the size of parent * DOM
 */
import React, { Component, PropTypes } from 'react';
import ContainerDimensions from 'react-container-dimensions';
import pureRender from '../util/PureRender';
import { isPercent } from '../util/DataUtils';
import { warn } from '../util/LogUtils';

const render = ({ aspect, width, height, minWidth, minHeight, container, children }) => {
  warn(isPercent(width) || isPercent(height),
    `The width(%s) and height(%s) are both fixed numbers,
     maybe you don't need to use a ResponsiveContainer.`,
    width, height
  );

  warn(!aspect || aspect > 0,
       'The aspect(%s) must be greater than zero.',
       aspect);

  let calculatedWidth = container.width;
  let calculatedHeight = container.height;

  if (aspect && aspect > 0) {
    // Preserve the desired aspect ratio
    if (calculatedWidth / calculatedHeight > aspect) {
      calculatedWidth = calculatedHeight * aspect;
    } else if (calculatedWidth / calculatedHeight < aspect) {
      calculatedHeight = calculatedWidth / aspect;
    }
  }

  warn(calculatedWidth > 0 && calculatedHeight > 0,
    `The width(%s) and height(%s) of chart should be greater than 0,
     please check the style of container, or the props width(%s) and height(%s),
     or add a minWidth(%s) or minHeight(%s) or use aspect(%s) to control the
     height and width.`,
    calculatedWidth, calculatedHeight, width, height, minWidth, minHeight, aspect
  );

  return React.cloneElement(children, {
    width: calculatedWidth,
    height: calculatedHeight,
  });
};

const ResponsiveContainer = props => {
  const { minWidth, minHeight, width, height } = props;
  const style = { width, height, minWidth, minHeight };
  return (

      <ContainerDimensions>
        {
          container =>
            render({
              container,
              ...props,
            })
      }
      </ContainerDimensions>

  );
};

ResponsiveContainer.displayName = 'ResponsiveContainer';
ResponsiveContainer.propTypes = {
  aspect: PropTypes.number,
  width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  minHeight: PropTypes.number,
  minWidth: PropTypes.number,
  children: PropTypes.node.isRequired,
};

ResponsiveContainer.defaultProps = {
  width: '100%',
  height: '100%',
};

export default ResponsiveContainer;
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import SkyLight from 'react-skylight';
import VisibilitySensor from 'react-visibility-sensor';
import cx from 'classnames';
import autoBind from 'auto-bind-es5';
import {connect} from'react-redux';

import Price from '../../Price';
import AddToCart from '../../AddToCart';
import ItemOptions from './ItemOptions';
import { open as openItemDetails, close as closeItemDetails } from '../../../store/actions/itemDetails';
import {media} from '../../../utils/api'

const noop = () => {};

class ItemDetails extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isVisible: false,
      loading: true,
      mainImage: props.item.get('files')[0] || ''
    };
    autoBind(this);
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      mainImage: nextProps.item.get('files')[0]
    });
  }

  open() {
    openItemDetails(this.props.item);
    this.customDialog.show();
    const { src } = this.props;
    const img = new Image();
    img.src = src;
    this.setState({
      loading: !img.complete
    });
    img.addEventListener('load', this.loaded);
  }

  loaded() {
    this.setState({ loading: false });
  }

  onVisibleChange( isVisible ) {
    this.setState({ isVisible });
  }

  render() {
    const {
      imgClassName,
      item,
      thumbsSrc,
      canSeePrices
    } = this.props;

    const {mainImage} = this.state;

    const {
      title,
      options,
      name,
      code,
      shortDescription,
      description
    } = item.data;
    const isVisible = item.get('visible');
    const { loading } = this.state;
    const bg = {
      backgroundImage: `url("${loading
        ? thumbsSrc
        : media(mainImage)}")`
    };
    const imgClasses = cx('lightboxImg_container', {
      loading: !!loading
    });

    const listingSrcImg = isVisible ? thumbsSrc : null;

    const priceJsx = canSeePrices ? (

        Price:
        <Price value={ this.props.calculatedPrice } /><AddToCart item={item} />

    ) : null;

    return (
      <VisibilitySensor
        partialVisibility
        onChange={isVisible ? noop : this.onVisibleChange}
      >

          <SkyLight
            hideOnOverlayClicked
            ref={el => this.customDialog = el}
            afterClose={closeItemDetails}
            title={title}>

                {item.get('files').filter(f => mainImage !== f).map(img => (
                   this.setState({mainImage: img})}
                    src={img}
                    alt="thumb"
                  />
                ))}

Details

                        Name:
                        {name}

                      {name !== code && (

                        Code:
                        {code}

)}
                      {shortDescription && (

                          Size:
                          {shortDescription}

                      )}
                      { priceJsx }

                  <ItemOptions options={options} initialValues={item.selectedOptions} />

          </SkyLight>

      </VisibilitySensor>
    );
  }
}

ItemDetails.propTypes = {
  src: PropTypes.string.isRequired,
  imgClassName: PropTypes.string.isRequired,
  thumbsSrc: PropTypes.string.isRequired,
  item: PropTypes.object.isRequired,
  canSeePrices: PropTypes.bool.isRequired,
  calculatedPrice: PropTypes.number.isRequired
};

export default connect(state => {
  return {
    calculatedPrice: state.itemDetails.calculatedPrice,
    canSeePrices: state.session.meta.prices
  };
})(ItemDetails);
<commit_msg>removed HD pictures<commit_after>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import SkyLight from 'react-skylight';
import VisibilitySensor from 'react-visibility-sensor';
import cx from 'classnames';
import autoBind from 'auto-bind-es5';
import {connect} from'react-redux';

import Price from '../../Price';
import AddToCart from '../../AddToCart';
import ItemOptions from './ItemOptions';
import { open as openItemDetails, close as closeItemDetails } from '../../../store/actions/itemDetails';
import {media} from '../../../utils/api'

const noop = () => {};

class ItemDetails extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isVisible: false,
      loading: true,
      mainImage: props.item.get('files')[0] || ''
    };
    autoBind(this);
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      mainImage: nextProps.item.get('files')[0]
    });
  }

  open() {
    openItemDetails(this.props.item);
    this.customDialog.show();
    const { src } = this.props;
    const img = new Image();
    img.src = src;
    this.setState({
      loading: !img.complete
    });
    img.addEventListener('load', this.loaded);
  }

  loaded() {
    this.setState({ loading: false });
  }

  onVisibleChange( isVisible ) {
    this.setState({ isVisible });
  }

  render() {
    const {
      imgClassName,
      item,
      thumbsSrc,
      canSeePrices
    } = this.props;

    const {mainImage} = this.state;

    const {
      title,
      options,
      name,
      code,
      shortDescription,
      canSeeImages,
      description
    } = item.data;
    const isVisible = item.get('visible');
    const { loading } = this.state;
    const bgStyle = {};

    if(canSeeImages) {
      bgStyle.backgroundImage = `url("${loading
        ? thumbsSrc
        : media(mainImage)}")`
    }
    const imgClasses = cx('lightboxImg_container', {
      loading: !!loading
    });

    const listingSrcImg = isVisible ? thumbsSrc : null;

    const priceJsx = canSeePrices ? (

        Price:
        <Price value={ this.props.calculatedPrice } /><AddToCart item={item} />

    ) : null;

    return (
      <VisibilitySensor
        partialVisibility
        onChange={isVisible ? noop : this.onVisibleChange}
      >

          <SkyLight
            hideOnOverlayClicked
            ref={el => this.customDialog = el}
            afterClose={closeItemDetails}
            title={title}>

                {item.get('files').filter(f => mainImage !== f).map(img => (
                   this.setState({mainImage: img})}
                    src={img}
                    alt="thumb"
                  />
                ))}

Details

                        Name:
                        {name}

                      {name !== code && (

                        Code:
                        {code}

)}
                      {shortDescription && (

                          Size:
                          {shortDescription}

                      )}
                      { priceJsx }

                  <ItemOptions options={options} initialValues={item.selectedOptions} />

          </SkyLight>

      </VisibilitySensor>
    );
  }
}

ItemDetails.propTypes = {
  src: PropTypes.string.isRequired,
  imgClassName: PropTypes.string.isRequired,
  thumbsSrc: PropTypes.string.isRequired,
  item: PropTypes.object.isRequired,
  canSeePrices: PropTypes.bool.isRequired,
  canSeeImages: PropTypes.bool.isRequired,
  calculatedPrice: PropTypes.number.isRequired
};

export default connect(state => {
  return {
    calculatedPrice: state.itemDetails.calculatedPrice,
    canSeePrices: state.session.meta.prices,
    canSeeImages: state.session.meta.images
  };
})(ItemDetails);
<|endoftext|>


<commit_before>export const characters = Object.assign({},
    require('./characters/geiger.jsx'),
    require('./characters/grave.jsx'),
    require('./characters/gwen.jsx'),
    require('./characters/jaina.jsx'),
    require('./characters/midori.jsx'),
    require('./characters/rook.jsx'),
    require('./characters/setsuki.jsx'),
    require('./characters/troq.jsx'),
    require('./characters/valerie.jsx'),
    require('./characters/argagarg.jsx'),
    require('./characters/degrey.jsx'),
    require('./characters/lum.jsx'),
    require('./characters/menelker.jsx'),
    require('./characters/quince.jsx'),
    require('./characters/persephone.jsx'),
    require('./characters/onimaru.jsx'),
    require('./characters/gloria.jsx'),
);

export default characters
<commit_msg>Remove Gloria<commit_after>export const characters = Object.assign({},
    require('./characters/geiger.jsx'),
    require('./characters/grave.jsx'),
    require('./characters/gwen.jsx'),
    require('./characters/jaina.jsx'),
    require('./characters/midori.jsx'),
    require('./characters/rook.jsx'),
    require('./characters/setsuki.jsx'),
    require('./characters/troq.jsx'),
    require('./characters/valerie.jsx'),
    require('./characters/argagarg.jsx'),
    require('./characters/degrey.jsx'),
    require('./characters/lum.jsx'),
    require('./characters/menelker.jsx'),
    require('./characters/quince.jsx'),
    require('./characters/persephone.jsx'),
    require('./characters/onimaru.jsx'),
);

export default characters
<|endoftext|>


<commit_before>/* global describe it beforeEach */

import expect from 'expect';
import expectJSX from 'expect-jsx';
import React from 'react';
import { IntlProvider } from 'react-intl';
import TestUtils from 'react-addons-test-utils';
import ComponentOwner from '../src/js/component-owner';

expect.extend(expectJSX);
let called = false;
const onSelect = () => {
  called = true;
  return;
}

describe('Component Owner Suite', () => {
  let renderer;
  const maxButtons = 5;
  const items = 5;
  const activePage = 2;

  beforeEach(() => {
    renderer = TestUtils.createRenderer();
  });

  it('1. shallowly renders the component owner using React TestUtils', () => {
    renderer.render(
      <ComponentOwner
        activePage={activePage}
        items={items}
        onSelect={onSelect}
        maxButtons={maxButtons}
      />
    );

    const pagination = renderer.getRenderOutput();

    expect(pagination.props.children.length).toEqual(3);
    expect(pagination.props.children[1].length).toEqual(maxButtons);
    expect(pagination.props.children[0].props.children[1].props.children).toEqual('Prev');
    expect(pagination.props.children[2].props.children[1].props.children).toEqual('Next');
  });

  it('2. handles large # of buttons (ellipses at end)', () => {
    renderer.render(
      <ComponentOwner
        activePage={1}
        items={100}
        onSelect={onSelect}
        maxButtons={5}
      />
    );

    const pagination = renderer.getRenderOutput();
    expect(pagination.props.children[1][0].key).toEqual('firstItem');
    expect(pagination.props.children[1][maxButtons].key).toEqual('backEllipses');
    expect(pagination.props.children[1][maxButtons].props.disabled).toEqual(true);
    expect(pagination.props.children[1][maxButtons].props.children[1].props.children).toEqual('...');
    expect(pagination.props.children[1][maxButtons + 1].props.children.props.children[1]).toEqual(100);
  });

  it('3. handles large # of buttons (ellipses at beginning)', () => {
    renderer.render(
      <ComponentOwner
        activePage={99}
        items={100}
        onSelect={onSelect}
        maxButtons={5}
      />
    );

    const pagination = renderer.getRenderOutput();

    expect(pagination.props.children[1][0].key).toEqual('firstItem');
    expect(pagination.props.children[1][1].key).toEqual('frontEllipses');
    expect(pagination.props.children[1][1].props.disabled).toEqual(true);
    expect(pagination.props.children[1][1].props.children[1].props.children).toEqual('...');
  });

  it('4. handles large # of buttons (ellipses at both ends)', () => {
    renderer.render(
      <ComponentOwner
        activePage={40}
        items={100}
        onSelect={onSelect}
        maxButtons={5}
      />
    );

    const pagination = renderer.getRenderOutput();

    expect(pagination.props.children[1][0].key).toEqual('firstItem');
    expect(pagination.props.children[1][1].key).toEqual('frontEllipses');
    expect(pagination.props.children[1][maxButtons].key).toEqual('backEllipses');
    expect(pagination.props.children[1][maxButtons + 1].props.children.props.children[1]).toEqual(100);
  })

  it('5. handles fewer pages than maxButtons', () => {
    renderer.render(
      <ComponentOwner
        activePage={1}
        items={3}
        onSelect={onSelect}
        maxButtons={5}
      />
    );

    const pagination = renderer.getRenderOutput();

    expect(pagination.props.children[1].length).toEqual(3);
    expect(pagination.props.children.length).toEqual(3);
  });

  it('6. handles onSelect', () => {
    const container = TestUtils.renderIntoDocument(
      <IntlProvider locale="en">
        <ComponentOwner
          activePage={1}
          items={3}
          onSelect={onSelect}
          maxButtons={5}
        />
      </IntlProvider>
    );

    const paginationButton = TestUtils.scryRenderedDOMComponentsWithTag(container, 'button')[4];
    TestUtils.Simulate.click(paginationButton);
    expect(called).toEqual(true);
  });

  it('7. handles defaults (maxButtons not set)', () => {
    renderer.render(
      <ComponentOwner
        activePage={1}
        items={5}
        onSelect={onSelect}
      />
    );

    const pagination = renderer.getRenderOutput();
    expect(pagination.props.children.length).toEqual(3);
    expect(pagination.props.children[1].length).toEqual(5);
  });
});
<commit_msg>Updated test file<commit_after>/* global describe it beforeEach */

import expect from 'expect';
import expectJSX from 'expect-jsx';
import React from 'react';
import { IntlProvider } from 'react-intl';
import TestUtils from 'react-addons-test-utils';
import ComponentOwner from '../src/js/component-owner';

expect.extend(expectJSX);
let called = false;
const onSelect = () => {
  called = true;
  return;
}

describe('Component Owner Suite', () => {
  let renderer;
  const maxButtons = 5;
  const items = 5;
  const activePage = 2;

  beforeEach(() => {
    renderer = TestUtils.createRenderer();
  });

  it('1. shallowly renders the component owner using React TestUtils', () => {
    renderer.render(
      <ComponentOwner
        activePage={activePage}
        items={items}
        onSelect={onSelect}
        maxButtons={maxButtons}
      />
    );

    const pagination = renderer.getRenderOutput();

    expect(pagination.props.children.length).toEqual(3);
    expect(pagination.props.children[1].length).toEqual(maxButtons);
    expect(pagination.props.children[0].props.children[1].props.children.props.defaultMessage).toEqual('Prev');
    expect(pagination.props.children[2].props.children[1].props.children.props.defaultMessage).toEqual('Next');
  });

  it('2. handles large # of buttons (ellipses at end)', () => {
    renderer.render(
      <ComponentOwner
        activePage={1}
        items={100}
        onSelect={onSelect}
        maxButtons={5}
      />
    );

    const pagination = renderer.getRenderOutput();

    expect(pagination.props.children[1][0].key).toEqual('firstItem');
    expect(pagination.props.children[1][maxButtons].key).toEqual('backEllipses');
    expect(pagination.props.children[1][maxButtons].props.disabled).toEqual(true);
    expect(pagination.props.children[1][maxButtons].props.children[1].props.children).toEqual('...');
    expect(pagination.props.children[1][maxButtons + 1].props.children[1]).toEqual(100);
  });

  it('3. handles large # of buttons (ellipses at beginning)', () => {
    renderer.render(
      <ComponentOwner
        activePage={99}
        items={100}
        onSelect={onSelect}
        maxButtons={5}
      />
    );

    const pagination = renderer.getRenderOutput();

    expect(pagination.props.children[1][0].key).toEqual('firstItem');
    expect(pagination.props.children[1][1].key).toEqual('frontEllipses');
    expect(pagination.props.children[1][1].props.disabled).toEqual(true);
    expect(pagination.props.children[1][1].props.children[1].props.children).toEqual('...');
  });

  it('4. handles large # of buttons (ellipses at both ends)', () => {
    renderer.render(
      <ComponentOwner
        activePage={40}
        items={100}
        onSelect={onSelect}
        maxButtons={5}
      />
    );

    const pagination = renderer.getRenderOutput();

    expect(pagination.props.children[1][0].key).toEqual('firstItem');
    expect(pagination.props.children[1][1].key).toEqual('frontEllipses');
    expect(pagination.props.children[1][maxButtons].key).toEqual('backEllipses');
    expect(pagination.props.children[1][maxButtons + 1].props.children[1]).toEqual(100);
  })

  it('5. handles fewer pages than maxButtons', () => {
    renderer.render(
      <ComponentOwner
        activePage={1}
        items={3}
        onSelect={onSelect}
        maxButtons={5}
      />
    );

    const pagination = renderer.getRenderOutput();

    expect(pagination.props.children[1].length).toEqual(3);
    expect(pagination.props.children.length).toEqual(3);
  });

  it('6. handles onSelect', () => {
    const container = TestUtils.renderIntoDocument(
      <IntlProvider locale="en">
        <ComponentOwner
          activePage={1}
          items={3}
          onSelect={onSelect}
          maxButtons={5}
        />
      </IntlProvider>
    );

    const paginationButton = TestUtils.scryRenderedDOMComponentsWithTag(container, 'button')[4];
    TestUtils.Simulate.click(paginationButton);

    expect(called).toEqual(true);
  });

  it('7. handles defaults (maxButtons not set)', () => {
    renderer.render(
      <ComponentOwner
        activePage={1}
        items={5}
        onSelect={onSelect}
      />
    );

    const pagination = renderer.getRenderOutput();

    expect(pagination.props.children.length).toEqual(3);
    expect(pagination.props.children[1].length).toEqual(5);
  });
});
<|endoftext|>


<commit_before>

Chart.Line = Class.create(Chart.Base, {
  initialize: function($super, canvas, options) {
    $super(canvas);
    this.setOptions(options);
    this.R = Raphael(canvas, this.options.width, this.options.height);
  },

  draw: function() {
    if (this._datasets.length === 0) {
      throw new Krang.Error("No dataset!");
    }

    var opt = this.options, R = this.R, g = opt.gutter, max;
    if (opt.grid.maxY === 'auto') {
      max = Math.max.apply(Math, this._datasets.invoke('maxValue'));
    } else {
      max = opt.grid.maxY;
    }

    // Horizontal space between each node.
    var xScale = (opt.width - (g.left + g.right)) /
     (this._datasets.first().dataLength() - 1);

    // Vertical scale
    var yRange = opt.height - (g.top + g.bottom);
    var yScale = yRange / max;

    var columns = opt.grid.vertical.enabled   ? opt.grid.vertical.lines   : 0;
    var rows    = opt.grid.horizontal.enabled ? opt.grid.horizontal.lines : 0;

    // Create the background grid.
    R.drawGrid(
      g.left,                           /* X                 */
      g.top,                            /* Y                 */
      opt.width  - (g.left + g.right),  /* width             */
      opt.height - (g.top + g.bottom),  /* height            */
      columns,                          /* number of columns */
      rows,                             /* number of rows    */
      opt.grid.color                    /* color             */
    );

    R.rect(
      g.left,
      g.top,
      opt.width  - (g.left + g.right),
      opt.height - (g.top + g.bottom)
    ).attr({ stroke: opt.border.color });

    var $color = opt.line.color;
    if (opt.line.color instanceof Krang.Colorset) {
      opt.line.color.setLength(this._datasets.length);
    }

    var blanket = R.set();

    function plotDataset(dataset, index) {
      var data = dataset.toArray();

      // Create the path objects for the line and the fill.
      var lineColor = $color.toString();
      var line = R.path({
        'stroke':          lineColor,
        'stroke-width':    opt.line.width,
        'stroke-linejoin': 'round'
      });

      var fill = R.path({
        fill:    lineColor,
        opacity: opt.fill.opacity,
        stroke:  'none'
      });

      fill.moveTo(g.left, opt.height - g.bottom);

      var label, value, x = 0, y, dot, rect;

      // Plot the values.
      for (var i = 0, l = data.length; i < l; i++) {
        label = data[i].label; value = data[i].value;

        y = Math.round(opt.height - g.bottom - (yScale * value));
        x = Math.round(g.left + (xScale * i));

        // Draw the line segment.
        if (i == 0) {
          line.moveTo(x, y, 10);
          fill.lineTo(x, y, 10);
        } else {
          line.cplineTo(x, y, opt.line.curve);
          fill.cplineTo(x, y, opt.line.curve);
        }

        // Draw the dot.
        dot = R.circle(x, y, opt.dot.radius).attr({
          fill:   opt.dot.color || lineColor,
          stroke: opt.dot.stroke
        });

        // Create an invisible rectangle that will receive hover events.
        rect = R.rect(
          g.left + (xScale * i),
          0,
          xScale,
          opt.height - g.bottom
        ).attr({
          stroke:  'none',
          fill:    '#fff',
          opacity: 0
        });

        Krang.Data.store(rect, {
          dot:  dot,
          data: data[i]
        });

        this._createObservers(rect);

        blanket.push(rect);

        // Draw X labels.
        if (!index) {
          var textStartY = g.top + yRange + Math.round(g.bottom / 2);

          var text = R.text(x, textStartY, label).attr({
            font: '#{0} #{1}'.interpolate([opt.text.fontSize, opt.text.fontFamily]),
            stroke: 'none',
            fill: opt.text.color
          });
        }
      }

      // Since the fill path is drawing a shape, not just a line, we need to
      // close the path.
      fill.lineTo(x, opt.height - g.bottom).andClose();

    }

    this._datasets.each(plotDataset, this);

    // Draw Y labels.
    var yStart = g.bottom, yEnd = opt.height - g.top;

    var value, yLabel, yPlot, text;
    for (var j = 0, yLabel; j <= rows; j++) {
      value  = (j / rows) * max;
      yLabel = opt.grid.labelY(value);
      yPlot  = yStart + ((j * yRange) / rows);

      text = R.text(Math.round(g.left / 2), (opt.height - yPlot), yLabel).attr({
        font: '#{0} #{1}'.interpolate([opt.text.fontSize, opt.text.fontFamily]),
        stroke: 'none',
        fill: opt.text.color
      });

      // Fake right-alignment.
      var textWidth = text.getBBox().width;
      var textX = g.left - 15 - textWidth;

      text.attr({ x: textX, 'text-anchor': 'start' });
    }

    blanket.toFront();
  },

  _createObservers: function(rect) {
    var over = function() {
      var dot = Krang.Data.retrieve(rect, 'dot'),
         data = Krang.Data.retrieve(rect, 'data');

      Event.fire(rect.node, 'krang:mouseover', { dot: dot, data: data });
    };

    var out = function() {
      var dot = Krang.Data.retrieve(rect, 'dot'),
         data = Krang.Data.retrieve(rect, 'data');

      Event.fire(rect.node, 'krang:mouseout', { dot: dot, data: data });
    };

    Event.observe(rect.node, 'mouseover', over);
    Event.observe(rect.node, 'click',     out );
    Event.observe(rect.node, 'mouseout',  out );
  }
});

Object.extend(Chart.Line, {
  DEFAULT_OPTIONS: {
    width:  800,
    height: 250,
    line: {
      color: new Krang.Colorset({
        vary: 'h',
        saturation: 0.6,
        lightness: 0.4
      }),
      width: 4,
      curve: 10
    },

    fill: {
      color: '#039',
      opacity: 0.3
    },

    gutter: {
      top:    20,
      bottom: 20,
      left:   30,
      right:  30
    },

    grid: {
      color: '#ddd',

      horizontal: {
        enabled: true,
        lines: 10
      },

      vertical: {
        enabled: false,
        lines: 0
      },

      labelX: Prototype.K,
      labelY: function(value) {
        return value.toFixed(1);
      },

      maxY: 'auto'
    },

    dot: {
      stroke: '#fff',
      radius: 4
    },

    border: {
      color: '#999'
    },

    text: {
      fontFamily: '"Lucida Grande"',
      fontSize:   '12px',
      color:      "#000"
    }
  }
});<commit_msg>Small changes to line chart.<commit_after>

Chart.Line = Class.create(Chart.Base, {
  initialize: function($super, canvas, options) {
    $super(canvas);
    this.setOptions(options);
    this.R = Raphael(canvas, this.options.width, this.options.height);
  },

  draw: function() {
    if (this._datasets.length === 0) {
      throw new Krang.Error("No dataset!");
    }

    var opt = this.options, R = this.R, g = opt.gutter, max;
    if (opt.grid.maxY === 'auto') {
      max = Math.max.apply(Math, this._datasets.invoke('maxValue'));
    } else {
      max = opt.grid.maxY;
    }

    // Horizontal space between each node.
    var xScale = (opt.width - (g.left + g.right)) /
     (this._datasets.first().dataLength() - 1);

    // Vertical scale
    var yRange = opt.height - (g.top + g.bottom);
    var yScale = yRange / max;

    var columns = opt.grid.vertical.enabled   ? opt.grid.vertical.lines   : 0;
    var rows    = opt.grid.horizontal.enabled ? opt.grid.horizontal.lines : 0;

    // Create the background grid.
    R.drawGrid(
      g.left,                           /* X                 */
      g.top,                            /* Y                 */
      opt.width  - (g.left + g.right),  /* width             */
      opt.height - (g.top + g.bottom),  /* height            */
      columns,                          /* number of columns */
      rows,                             /* number of rows    */
      opt.grid.color                    /* color             */
    );

    R.rect(
      g.left,
      g.top,
      opt.width  - (g.left + g.right),
      opt.height - (g.top + g.bottom)
    ).attr({ stroke: opt.border.color });

    var $color = opt.line.color;
    if (opt.line.color instanceof Krang.Colorset) {
      opt.line.color.setLength(this._datasets.length);
    }

    var blanket = R.set();

    function plotDataset(dataset, index) {
      var data = dataset.toArray();

      // Create the path objects for the line and the fill.
      var lineColor = $color.toString();
      var line = R.path({
        'stroke':          lineColor,
        'stroke-width':    opt.line.width,
        'stroke-linejoin': 'round'
      });

      var fill = R.path({
        fill:    lineColor,
        opacity: opt.fill.opacity,
        stroke:  'none'
      });

      fill.moveTo(g.left, opt.height - g.bottom);

      var label, value, x = 0, y, dot, rect;

      // Plot the values.
      for (var i = 0, l = data.length; i < l; i++) {
        label = data[i].label; value = data[i].value;

        y = Math.round(opt.height - g.bottom - (yScale * value));
        x = Math.round(g.left + (xScale * i));

        // Draw the line segment.
        if (i == 0) {
          line.moveTo(x, y, 10);
          fill.lineTo(x, y, 10);
        } else {
          line.cplineTo(x, y, opt.line.curve);
          fill.cplineTo(x, y, opt.line.curve);
        }

        // Draw the dot.
        dot = R.circle(x, y, opt.dot.radius).attr({
          fill:   opt.dot.color || lineColor,
          stroke: opt.dot.stroke
        });

        // Create an invisible rectangle that will receive hover events.
        rect = R.rect(
          g.left + (xScale * i),
          0,
          xScale,
          opt.height - g.bottom
        ).attr({
          stroke:  'none',
          fill:    '#fff',
          opacity: 0
        });

        Krang.Data.store(rect, {
          dot:  dot,
          data: data[i]
        });

        this._createObservers(rect);

        blanket.push(rect);

        // Draw X labels.
        if (!index) {
          var textStartY = g.top + yRange + Math.round(g.bottom / 2);

          var text = R.text(x, textStartY, label).attr({
            font: '#{0} "#{1}"'.interpolate([opt.text.fontSize, opt.text.fontFamily]),
            stroke: 'none',
            fill: opt.text.color
          });
        }
      }

      // Since the fill path is drawing a shape, not just a line, we need to
      // close the path.
      fill.lineTo(x, opt.height - g.bottom).andClose();

    }

    this._datasets.each(plotDataset, this);

    // Draw Y labels.
    var yStart = g.bottom, yEnd = opt.height - g.top;

    var value, yLabel, yPlot, text;
    for (var j = 0, yLabel; j <= rows; j++) {
      value  = (j / rows) * max;
      yLabel = opt.grid.labelY(value);
      yPlot  = yStart + ((j * yRange) / rows);

      text = R.text(Math.round(g.left / 2), (opt.height - yPlot), yLabel).attr({
        font: '#{0} "#{1}"'.interpolate([opt.text.fontSize, opt.text.fontFamily]),
        stroke: 'none',
        fill: opt.text.color
      });

      // Fake right-alignment.
      var textWidth = text.getBBox().width;
      var textX = g.left - 15 - textWidth;

      text.attr({ x: textX, 'text-anchor': 'start' });
    }

    blanket.toFront();
  },

  _createObservers: function(rect) {
    var over = function() {
      var dot = Krang.Data.retrieve(rect, 'dot'),
         data = Krang.Data.retrieve(rect, 'data');

      Event.fire(rect.node, 'krang:mouseover', { dot: dot, data: data });
    };

    var out = function() {
      var dot = Krang.Data.retrieve(rect, 'dot'),
         data = Krang.Data.retrieve(rect, 'data');

      Event.fire(rect.node, 'krang:mouseout', { dot: dot, data: data });
    };

    Event.observe(rect.node, 'mouseover', over);
    Event.observe(rect.node, 'click',     out );
    Event.observe(rect.node, 'mouseout',  out );
  }
});

Object.extend(Chart.Line, {
  DEFAULT_OPTIONS: {
    width:  800,
    height: 250,
    line: {
      color: new Krang.Colorset({
        vary: 'h',
        saturation: 0.6,
        lightness: 0.4
      }),
      width: 4,
      curve: 10
    },

    fill: {
      color: '#039',
      opacity: 0.3
    },

    gutter: {
      top:    20,
      bottom: 20,
      left:   30,
      right:  30
    },

    grid: {
      color: '#ddd',

      horizontal: {
        enabled: true,
        lines: 10
      },

      vertical: {
        enabled: false,
        lines: 0
      },

      labelX: Prototype.K,
      labelY: function(value) {
        return value.toFixed(1);
      },

      maxY: 'auto'
    },

    dot: {
      stroke: '#fff',
      radius: 4
    },

    border: {
      color: '#999'
    },

    text: {
      fontFamily: 'Lucida Grande',
      fontSize:   '12px',
      color:      "#000"
    }
  }
});<|endoftext|>


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

var World=require('../../app/world');
var data=require('./data');

var Product=require('../../app/product');
var Ship=rrequire('../../app/ship');
var City=require('../../app/city');

module.exports=function(done){
    this.clear();
    insertProducts();
    insertShipModels();
    insertCities();
    insertUsers(function(){
        insertShips();
        done();
    });
    };

module.exports.clear=function(){
    World.products.list={};
    World.ships.list={};
    World.users.users={};
    World.map.clear();
};

function insertProducts(){
    var products=[];
    for(var p in data.products) products.push(new Product(data.products[p].name,data.products[p].price));
    for(var i=0;i<products;i++) World.products.addProduct(products[i]);
}
function insertShipModels(){
    var ships=[];
    for(var s in data.ships) ships.push(new Ship(data.ships[s].name,data.ships[s]));
    for(var i=0;i<ships;i++) World.ships.addShip(ships[i]);
}
function insertCities(){
    var cities=[];
    var productList=World.products.getProductList();
    for(var c in data.cities){
        var cdata=data.cities[c];
         var l=cities.push(new City(cdata.name,[cdata.positionX,cdata.positionY]));
         var newcity=cities[l-1];
         for(var p in productList) newcity.addProduct(p,10,1);
         for(var i=0;i<cities.length;i++) World.cities.addCity(cities[i]);
    }
}
function insertUsers(done){
    async.forEachOf(data.users,function(user,key,cb){
        World.users.addUser(user.id,function(err,res){
            res.money=user.money;
            cb();
        });
    },function(err){
        done();
    });
}
function insertShips(){

}
<commit_msg>populate script<commit_after>
var async=require('async');

var World=require('../../app/world');
var data=require('./data');

var Product=require('../../app/product');
var Ship=rrequire('../../app/ship');
var City=require('../../app/city');

module.exports=function(done){
    this.clear();
    insertProducts();
    insertShipModels();
    insertCities();
    insertUsers(done);
    };

module.exports.clear=function(){
    World.products.list={};
    World.ships.list={};
    World.users.users={};
    World.map.clear();
};

function insertProducts(){
    var products=[];
    for(var p in data.products) products.push(new Product(data.products[p].name,data.products[p].price));
    for(var i=0;i<products;i++) World.products.addProduct(products[i]);
}
function insertShipModels(){
    var ships=[];
    for(var s in data.ships) ships.push(new Ship(data.ships[s].name,data.ships[s]));
    for(var i=0;i<ships;i++) World.ships.addShip(ships[i]);
}
function insertCities(){
    var cities=[];
    var productList=World.products.getProductList();
    for(var c in data.cities){
        var cdata=data.cities[c];
         var l=cities.push(new City(cdata.name,[cdata.positionX,cdata.positionY]));
         var newcity=cities[l-1];
         for(var p in productList) newcity.addProduct(p,10,1);
         for(var i=0;i<cities.length;i++) World.cities.addCity(cities[i]);
    }
}
function insertUsers(done){
    async.forEachOf(data.users,function(user,key,cb){
        World.users.addUser(user.id,function(err,res){
            res.money=user.money;
            insertShip(res,cb);
        });
    },function(err){
        done();
    });
}
function insertShip(user,cb){
    var shipsModel=data.ships.caravel;
    user.buildShip("Black Pearl", shipModel, data.cities.isengard, cb);
}
<|endoftext|>


<commit_before>import React, {Component} from "react";
import gql from "graphql-tag.macro";
import {withApollo} from "react-apollo";
import "./issueTracker.scss";

class IssueTracker extends Component {
  constructor(props) {
    super(props);
    this.state = {
      uploads: [],
    };
  }
  _handleEvent(which, e) {
    this.setState({[which]: e.target.value});
  }

  _submit = e => {
    e.preventDefault();
    if (!this.state.type) return;
    if (!this.state.priority) return;
    if (this.state.uploading) return;
    const mutation = gql`
      mutation IssueTracker(
        $title: String!
        $body: String!
        $person: String!
        $type: String!
        $priority: String!
      ) {
        addIssue(
          title: $title
          body: $body
          person: $person
          type: $type
          priority: $priority
        )
      }
    `;
    const variables = {
      title: this.state.title,
      body:
        this.state.body +
        `

${
  this.state.reproduce
    ? `### Steps to Reproduce
${this.state.reproduce}`
    : ""
}`,
      person: this.state.person,
      type: this.state.type,
      priority: this.state.priority,
    };
    this.props.client.mutate({
      mutation,
      variables,
    });
    this.setState({});
    this.props.close && this.props.close();
  };
  upload = e => {
    const parts = e.target.files[0].name.split(".");
    const ext = parts.pop();
    const filename = parts.join("-");
    const reader = new FileReader();
    reader.onload = () => {
      const result = reader.result;
      const base64 = result.split(",")[1];
      this.setState({uploading: true});
      this.props.client
        .mutate({
          mutation: gql`
            mutation AddUpload(
              $data: String!
              $filename: String!
              $ext: String!
            ) {
              addIssueUpload(data: $data, filename: $filename, ext: $ext)
            }
          `,
          variables: {data: base64, filename, ext},
        })
        .then(({data: {addIssueUpload}}) => {
          if (addIssueUpload) {
            this.setState(({body}) => {
              return {
                body: `${body || ""}

![${filename}](${addIssueUpload})`,
              };
            });
          }
        })
        .catch(err => console.error(err))
        .finally(() => {
          this.setState({uploading: false});
        });
    };
    e.target.files[0] && reader.readAsDataURL(e.target.files[0]);
  };
  fileRef = React.createRef();
  render() {
    return (

          <form onSubmit={this._submit}>

              Title
              <input
                onChange={this._handleEvent.bind(this, "title")}
                required
                placeholder="Required"
                className="form-control form-control-sm"
              />

              Submitted By
              <input
                onChange={this._handleEvent.bind(this, "person")}
                required
                placeholder="Your Name (email address optional) Eg. Alex (alex@fyreworks.us)"
                className="form-control form-control-sm"
              />

              Body
              <textarea
                onChange={this._handleEvent.bind(this, "body")}
                value={this.state.body}
                rows="5"
                placeholder="Please be specific. Include as much detail as possible. If you are filing a bug report, explain detailed steps to reproduce the bug. Include how you would want the bug to be fixed or the feature to be implemented. The more specific you are, the more likely the bug will be fixed or feature will be implemented. This field supports Markdown"
                required
                className="form-control form-control-sm"
              />

            {this.state.type === "type/bug" && (

                Steps to Reproduce
                <textarea
                  onChange={this._handleEvent.bind(this, "reproduce")}
                  rows="5"
                  placeholder="Explain step-by-step what someone can do to reproduce this issue. If you can't provide step-by-step instructions, try recreating the bug yourself. Once you can reproduce the bug, submit an issue."
                  required
                  className="form-control form-control-sm"
                />

            )}

              Type
              <select
                onChange={this._handleEvent.bind(this, "type")}
                required
                defaultValue={"select"}
                className="form-control form-control-sm"
              >
                <option disabled value="select">
                  Select a Type
                </option>
                <option value="type/bug">Bug</option>
                <option value="type/feature">Feature Request</option>
                <option value="type/card">Card Request</option>
                <option value="type/question">Question</option>
                <option value="type/enhancement">Enhancement</option>
              </select>

              Priority
              <select
                onChange={this._handleEvent.bind(this, "priority")}
                required
                defaultValue={"select"}
                className="form-control form-control-sm"
              >
                <option disabled value="select">
                  Select a Priority
                </option>
                <option value="high">High</option>
                <option value="medium">Medium</option>
                <option value="low">Low</option>
              </select>

            {this.state.uploading ? (
              "Uploading..."
            ) : (

                <input
                  id="image-upload"
                  value=""
                  type="file"
                  ref={this.fileRef}
                  onChange={this.upload}
                  hidden
                />

Upload Attachment

            )}

              <button
                disabled={this.state.uploading}
                className="btn btn-sm btn-primary"
                type="submit"
              >
                Submit
              </button>

          </form>

          What can you do to get your issue report addressed sooner? If you have
          an urgent need or want to prioritize something, submit a{" "}

            Service Request Form

          . If you know of developers who are capable of working on Thorium, you
          can point them at the{" "}

            Github Repository

          . And if you have further questions, feel free to reach out on the{" "}

            Discord Server

          .

    );
  }
}

export default withApollo(IssueTracker);
<commit_msg>Add a little prompt to the issue tracker.<commit_after>import React, {Component} from "react";
import gql from "graphql-tag.macro";
import {withApollo} from "react-apollo";
import "./issueTracker.scss";

class IssueTracker extends Component {
  constructor(props) {
    super(props);
    this.state = {
      uploads: [],
    };
  }
  _handleEvent(which, e) {
    this.setState({[which]: e.target.value});
  }

  _submit = e => {
    e.preventDefault();
    if (!this.state.type) return;
    if (!this.state.priority) return;
    if (this.state.uploading) return;
    const mutation = gql`
      mutation IssueTracker(
        $title: String!
        $body: String!
        $person: String!
        $type: String!
        $priority: String!
      ) {
        addIssue(
          title: $title
          body: $body
          person: $person
          type: $type
          priority: $priority
        )
      }
    `;
    const variables = {
      title: this.state.title,
      body:
        this.state.body +
        `

${
  this.state.reproduce
    ? `### Steps to Reproduce
${this.state.reproduce}`
    : ""
}`,
      person: this.state.person,
      type: this.state.type,
      priority: this.state.priority,
    };
    this.props.client.mutate({
      mutation,
      variables,
    });
    this.setState({});
    this.props.close && this.props.close();
  };
  upload = e => {
    const parts = e.target.files[0].name.split(".");
    const ext = parts.pop();
    const filename = parts.join("-");
    const reader = new FileReader();
    reader.onload = () => {
      const result = reader.result;
      const base64 = result.split(",")[1];
      this.setState({uploading: true});
      this.props.client
        .mutate({
          mutation: gql`
            mutation AddUpload(
              $data: String!
              $filename: String!
              $ext: String!
            ) {
              addIssueUpload(data: $data, filename: $filename, ext: $ext)
            }
          `,
          variables: {data: base64, filename, ext},
        })
        .then(({data: {addIssueUpload}}) => {
          if (addIssueUpload) {
            this.setState(({body}) => {
              return {
                body: `${body || ""}

![${filename}](${addIssueUpload})`,
              };
            });
          }
        })
        .catch(err => console.error(err))
        .finally(() => {
          this.setState({uploading: false});
        });
    };
    e.target.files[0] && reader.readAsDataURL(e.target.files[0]);
  };
  fileRef = React.createRef();
  render() {
    return (

          <form onSubmit={this._submit}>

              Title
              <input
                onChange={this._handleEvent.bind(this, "title")}
                required
                placeholder="Required"
                className="form-control form-control-sm"
              />

              Submitted By
              <input
                onChange={this._handleEvent.bind(this, "person")}
                required
                placeholder="Your Name (email address optional) Eg. Alex (alex@fyreworks.us)"
                className="form-control form-control-sm"
              />

              Body
              <textarea
                onChange={this._handleEvent.bind(this, "body")}
                value={this.state.body}
                rows="5"
                placeholder={`Please be specific. Include as much detail as possible. ${
                  this.state.type === "type/feature" ||
                  this.state.type === "type/card" ||
                  this.state.type === "type/enhancement"
                    ? "Can you tell me a story about a time that you wanted to do what your feature request outlines, and what you had to do instead?"
                    : ""
                } If you are filing a bug report, explain detailed steps to reproduce the bug. Include how you would want the bug to be fixed or the feature to be implemented. The more specific you are, the more likely the bug will be fixed or feature will be implemented. This field supports Markdown`}
                required
                className="form-control form-control-sm"
              />

            {this.state.type === "type/bug" && (

                Steps to Reproduce
                <textarea
                  onChange={this._handleEvent.bind(this, "reproduce")}
                  rows="5"
                  placeholder="Explain step-by-step what someone can do to reproduce this issue. If you can't provide step-by-step instructions, try recreating the bug yourself. Once you can reproduce the bug, submit an issue."
                  required
                  className="form-control form-control-sm"
                />

            )}

              Type
              <select
                onChange={this._handleEvent.bind(this, "type")}
                required
                defaultValue={"select"}
                className="form-control form-control-sm"
              >
                <option disabled value="select">
                  Select a Type
                </option>
                <option value="type/bug">Bug</option>
                <option value="type/feature">Feature Request</option>
                <option value="type/card">Card Request</option>
                <option value="type/question">Question</option>
                <option value="type/enhancement">Enhancement</option>
              </select>

              Priority
              <select
                onChange={this._handleEvent.bind(this, "priority")}
                required
                defaultValue={"select"}
                className="form-control form-control-sm"
              >
                <option disabled value="select">
                  Select a Priority
                </option>
                <option value="high">High</option>
                <option value="medium">Medium</option>
                <option value="low">Low</option>
              </select>

            {this.state.uploading ? (
              "Uploading..."
            ) : (

                <input
                  id="image-upload"
                  value=""
                  type="file"
                  ref={this.fileRef}
                  onChange={this.upload}
                  hidden
                />

Upload Attachment

            )}

              <button
                disabled={this.state.uploading}
                className="btn btn-sm btn-primary"
                type="submit"
              >
                Submit
              </button>

          </form>

          What can you do to get your issue report addressed sooner? If you have
          an urgent need or want to prioritize something, submit a{" "}

            Service Request Form

          . If you know of developers who are capable of working on Thorium, you
          can point them at the{" "}

            Github Repository

          . And if you have further questions, feel free to reach out on the{" "}

            Discord Server

          .

    );
  }
}

export default withApollo(IssueTracker);
<|endoftext|>


<commit_before>// dependencies
//
import React from 'react';
import update from 'react-addons-update';
import uniqueId from 'lodash/uniqueId';
import isArray from 'lodash/isArray';
import classnames from 'classnames';

/*

        Cycles

                <input type="checkbox" value="1">
                1

                <input type="checkbox" value="2">
                2

*/

class CheckboxGroup extends React.Component {
    constructor(props) {
        super(props);

        let value = [];

        if (this.props.value) {
            value = isArray(this.props.value) ? this.props.value : [this.props.value];
        }

        this.id = this.props.id || uniqueId('form-checkboxgroup-');

        this.state = {
            value,
            hasBeenClicked: false,
        };

        this.onClick = this.onClick.bind(this);
    }

    componentWillMount() {
        // determine if it's valid
        //
        const isValid = !this.props.required || this.state.value.length;

        // call the `onChildValidationEvent` handler once with
        // `hasValidated`=false, just to ensure that the parent knows about this
        // child
        //
        if (this.context.onChildValidationEvent) {
            this.context.onChildValidationEvent(
                this.id,
                false,
                isValid ? null : 'At least one item must be checked'
            );
        }
    }

    onClick(value) {
        const idx = this.state.value.findIndex((val) => val === value);

        let delta = null;
        if (idx === -1) {
            delta = { hasBeenClicked: { $set: true }, value: { $push: [value] } };
        } else {
            delta = { hasBeenClicked: { $set: true }, value: { $splice: [[idx, 1]] } };
        }

        this.setState((state) => update(state, delta), () => {
            if (this.props.onChange) {
                this.props.onChange(this.state.value);
            }
        });
    }

    render() {

        const classes = classnames('form-group', {
            'has-error': this.props.required && this.state.hasBeenClicked && !this.state.value.length,
        });

        const helpBlock = this.props.required && this.state.hasBeenClicked && !this.state.value.length
            ? At least one item must be checked
            : '';

        return (

                {this.props.label
                    ? {this.props.label}
                    : null
                }
                {this.props.options.map((opt) =>

                            <input
                                type="checkbox"
                                value={opt.value}
                                checked={this.state.value.findIndex((val) => val === opt.value) !== -1}
                                onChange={() => this.onClick(opt.value)}
                                onClick={() => this.onClick(opt.value)}
                            />
                            {opt.name}

                )}
                {helpBlock}

        );
    }
}

export default CheckboxGroup;
<commit_msg>updated onClick handler to call onChildValidationEvent handler<commit_after>// dependencies
//
import React from 'react';
import update from 'react-addons-update';
import uniqueId from 'lodash/uniqueId';
import isArray from 'lodash/isArray';
import classnames from 'classnames';

/*

        Cycles

                <input type="checkbox" value="1">
                1

                <input type="checkbox" value="2">
                2

*/

class CheckboxGroup extends React.Component {
    constructor(props) {
        super(props);

        let value = [];

        if (this.props.value) {
            value = isArray(this.props.value) ? this.props.value : [this.props.value];
        }

        this.id = this.props.id || uniqueId('form-checkboxgroup-');

        this.state = {
            value,
            hasBeenClicked: false,
        };

        this.onClick = this.onClick.bind(this);
    }

    componentWillMount() {
        // determine if it's valid
        //
        const isValid = !this.props.required || this.state.value.length;

        // call the `onChildValidationEvent` handler once with
        // `hasValidated`=false, just to ensure that the parent knows about this
        // child
        //
        if (this.context.onChildValidationEvent) {
            this.context.onChildValidationEvent(
                this.id,
                false,
                isValid ? null : 'At least one item must be checked'
            );
        }
    }

    onClick(value) {
        const idx = this.state.value.findIndex((val) => val === value);

        let delta = null;
        if (idx === -1) {
            delta = { hasBeenClicked: { $set: true }, value: { $push: [value] } };
        } else {
            delta = { hasBeenClicked: { $set: true }, value: { $splice: [[idx, 1]] } };
        }

        this.setState((state) => update(state, delta), () => {
            if (this.props.onChange) {
                this.props.onChange(this.state.value);
            }

            const isValid = !this.props.required || this.state.value.length;

            if (this.context.onChildValidationEvent) {
                this.context.onChildValidationEvent(
                    this.id,
                    true,
                    isValid ? null : 'At least one item must be checked'
                );
            }
        });
    }

    render() {

        const classes = classnames('form-group', {
            'has-error': this.props.required && this.state.hasBeenClicked && !this.state.value.length,
        });

        const helpBlock = this.props.required && this.state.hasBeenClicked && !this.state.value.length
            ? At least one item must be checked
            : '';

        return (

                {this.props.label
                    ? {this.props.label}
                    : null
                }
                {this.props.options.map((opt) =>

                            <input
                                type="checkbox"
                                value={opt.value}
                                checked={this.state.value.findIndex((val) => val === opt.value) !== -1}
                                onChange={() => this.onClick(opt.value)}
                                onClick={() => this.onClick(opt.value)}
                            />
                            {opt.name}

                )}
                {helpBlock}

        );
    }
}

export default CheckboxGroup;
<|endoftext|>


<commit_before>// dependencies
//
import React from 'react';
import uniqueId from 'lodash/uniqueId';
import isArray from 'lodash/isArray';

/*

        Cycles

                <input type="checkbox" value="1">
                1

                <input type="checkbox" value="2">
                2

*/

class CheckboxGroup extends React.Component {
    constructor(props) {
        super(props);

        let value = [];

        if (this.props.value) {
            value = isArray(this.props.value) ? this.props.value : [this.props.value];
        }

        this.state = { value };
    }

    render() {
        return (

                {this.props.label
                    ? {this.props.label}
                    : null
                }
                {this.props.options.map((opt) =>

                            <input type="checkbox" value={opt.value} />
                            {opt.name}

                )}

        );
    }
}

export default CheckboxGroup;
<commit_msg>added checked property to input element<commit_after>// dependencies
//
import React from 'react';
import uniqueId from 'lodash/uniqueId';
import isArray from 'lodash/isArray';

/*

        Cycles

                <input type="checkbox" value="1">
                1

                <input type="checkbox" value="2">
                2

*/

class CheckboxGroup extends React.Component {
    constructor(props) {
        super(props);

        let value = [];

        if (this.props.value) {
            value = isArray(this.props.value) ? this.props.value : [this.props.value];
        }

        this.state = { value };
    }

    render() {
        return (

                {this.props.label
                    ? {this.props.label}
                    : null
                }
                {this.props.options.map((opt) =>

                            <input
                                type="checkbox"
                                value={opt.value}
                                checked={this.state.value.findIndex((val) => val === opt.value) !== -1}
                            />
                            {opt.name}

                )}

        );
    }
}

export default CheckboxGroup;
<|endoftext|>


<commit_before>// the eslint "no-unused-expressions" rule is triggered by the `expect`
// assertions in the tests. So, in order to avoid problems with eslint, I'm
// disabling that rule in this file
//
/* eslint-disable no-unused-expressions */

import React from 'react';
import { shallow, render, mount } from 'enzyme';
import chai from 'chai';
import sinon from 'sinon';

import Form from '../Form';

const expect = chai.expect;

/* eslint-disable no-unused-vars */
const debug = (component) => {
    console.info('------------------------------------------------------------');
    console.info(component.debug());
    console.info('------------------------------------------------------------');
};
/* eslint-enable no-unused-vars */

/*

<Dropdown
    options={stateOptions}

    label="State/Province"
    required
    description="The state or province"
    value={this.props.form.state || ''}
    labelColumns={{ xs: 2, md: 3 }}
    dropdownColumns={{ xs: 10, md: 9 }}
    onChange={(value) =>
        this.props.updateField('state', value)
    }
    onValidation={(isValid, message) =>
        this.onValidation('state', isValid, message)
    }
/>

*/

/* *****************************************************************************
a Form component containing a Dropdown
    should include a <Form.Dropdown> as a child
    should be a select.form-control
    should have the options specified in the `options` prop
    should not include a label if none was specified
    should include a label if one was specified
*/
describe('a Form component containing a Dropdown', () => {

    it('should include a <Form.Dropdown> as a child', () => {
        const component = shallow(
            <Form>
                <Form.Dropdown />
            </Form>
        );

        expect(component.find(Form.Dropdown)).to.have.length(1);
    });

    it('should be a select.form-control', () => {
        const options = [
            { value: '1', name: 'one' },
            { value: '2', name: 'two' },
        ];

        const component = render(
            <Form>
                <Form.Dropdown options={options} />
            </Form>
        );

        expect(component.find('select.form-control')).to.have.length(1);
    });

    it('should have the options specified in the `options` prop', () => {

        const options = [
            { value: '1', name: 'one' },
            { value: '2', name: 'two' },
        ];

        const component = render(
            <Form>
                <Form.Dropdown options={options} />
            </Form>
        );

        expect(component.find('option')).to.have.length(options.length, 'options count');

        options.forEach((opt) => {
            expect(component.find(`option[value="${opt.value}"]`)).to.have.length(1, `value=${opt.value}`);
            expect(component.find(`option[value="${opt.value}"]`).text()).to.equal(opt.name, `name=${opt.name}`);

        });
    });

});
<commit_msg>added specs for component label<commit_after>// the eslint "no-unused-expressions" rule is triggered by the `expect`
// assertions in the tests. So, in order to avoid problems with eslint, I'm
// disabling that rule in this file
//
/* eslint-disable no-unused-expressions */

import React from 'react';
import { shallow, render, mount } from 'enzyme';
import chai from 'chai';
import sinon from 'sinon';

import Form from '../Form';

const expect = chai.expect;

/* eslint-disable no-unused-vars */
const debug = (component) => {
    console.info('------------------------------------------------------------');
    console.info(component.debug());
    console.info('------------------------------------------------------------');
};
/* eslint-enable no-unused-vars */

/*

<Dropdown
    options={stateOptions}

    label="State/Province"
    required
    description="The state or province"
    value={this.props.form.state || ''}
    labelColumns={{ xs: 2, md: 3 }}
    dropdownColumns={{ xs: 10, md: 9 }}
    onChange={(value) =>
        this.props.updateField('state', value)
    }
    onValidation={(isValid, message) =>
        this.onValidation('state', isValid, message)
    }
/>

*/

/* *****************************************************************************
a Form component containing a Dropdown
    should include a <Form.Dropdown> as a child
    should be a select.form-control
    should have the options specified in the `options` prop
    should not include a label if none was specified
    should include a label if one was specified
*/
describe('a Form component containing a Dropdown', () => {

    it('should include a <Form.Dropdown> as a child', () => {
        const component = shallow(
            <Form>
                <Form.Dropdown />
            </Form>
        );

        expect(component.find(Form.Dropdown)).to.have.length(1);
    });

    it('should be a select.form-control', () => {
        const options = [
            { value: '1', name: 'one' },
            { value: '2', name: 'two' },
        ];

        const component = render(
            <Form>
                <Form.Dropdown options={options} />
            </Form>
        );

        expect(component.find('select.form-control')).to.have.length(1);
    });

    it('should have the options specified in the `options` prop', () => {

        const options = [
            { value: '1', name: 'one' },
            { value: '2', name: 'two' },
        ];

        const component = render(
            <Form>
                <Form.Dropdown options={options} />
            </Form>
        );

        expect(component.find('option')).to.have.length(options.length, 'options count');

        options.forEach((opt) => {
            expect(component.find(`option[value="${opt.value}"]`)).to.have.length(1, `value=${opt.value}`);
            expect(component.find(`option[value="${opt.value}"]`).text()).to.equal(opt.name, `name=${opt.name}`);

        });
    });

    it('should not include a label if none was specified', () => {
        const options = [
            { value: '1', name: 'one' },
            { value: '2', name: 'two' },
        ];

        const component = render(
            <Form>
                <Form.Dropdown options={options} />
            </Form>
        );

        expect(component.find('label')).to.have.length(0);
    });

    it('should include a label if one was specified', () => {
        const options = [
            { value: '1', name: 'one' },
            { value: '2', name: 'two' },
        ];

        const label = 'some label';

        const component = render(
            <Form>
                <Form.Dropdown options={options} label={label} />
            </Form>
        );

        expect(component.find('label')).to.have.length(1);
        expect(component.find('label').text()).to.equal(label);
    });

});
<|endoftext|>


<commit_before>import Feature from 'ol/Feature'
import {register} from 'ol/proj/proj4'
import Icon from 'ol/style/Icon'
import Image from 'ol/layer/Image'
import ImageStatic from 'ol/source/ImageStatic'
import Map from 'ol/Map'
import Point from 'ol/geom/Point'
import proj4 from 'proj4'
import Projection from 'ol/proj/Projection'
import Style from 'ol/style/Style'
import Tile from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
import View from 'ol/View'
import XYZ from 'ol/source/XYZ'
import {fromLonLat} from 'ol/proj'
import VectorSource from 'ol/source/Vector'
import {defaults as defaultControls, Attribution} from 'ol/control'
import GeoJSON from 'ol/format/GeoJSON'

proj4.defs('EPSG:3067', '+proj=utm +zone=35 +ellps=GRS80 +units=m +no_defs')
register(proj4)
const imageProjection = new Projection({code: 'EPSG:3067'})
const imageExtent = [-118331.366, 6335621.167, 875567.732, 7907751.537]

function createMap(settings) {
  const {x, y, zoom} = settings
  const center = [x, y]
  const view = new View({
    center,
    minZoom: 5,
    maxZoom: 13,
    projection: 'EPSG:3857',
    zoom
  })

  const attribution = new Attribution({
    collapsible: false
  })
  const map = new Map({
    controls: defaultControls({attribution: false, altShiftDragRotate: false, pinchRotate: false}).extend([attribution]),
    layers: [createMapLayer(), createRadarLayer(), createLightningLayer(), createIconLayer(center)],
    target: 'map',
    view
  })

  // OpenLayers leaves the map distorted on some mobile browsers after screen orientation change
  window.addEventListener('orientationchange', () => location.reload())

  return map
}

function createMapLayer() {
  const attributions = ['© OpenStreetMap contributors']
  const source = new XYZ({url: '/tiles/{z}/{x}/{y}.png', attributions})
  return new Tile({source})
}

function createRadarLayer() {
  return new Image({opacity: 0.8, visible: false})
}

function createIconLayer(position) {
  const style = new Style({
    image: new Icon({
      anchor: [0.5, 1.0],
      anchorXUnits: 'fraction',
      anchorYUnits: 'fraction',
      scale: 0.33,
      src: '/img/pin.png'
    })
  })

  const iconFeature = new Feature({
    geometry: new Point(position)
  })
  iconFeature.setStyle(style)

  const source = new VectorSource({features: [iconFeature]})
  return new VectorLayer({source})
}

const radarImageSourcesCache = {}

function showRadarFrame(map, {image, lightnings}) {
  const radarImageSource = radarImageSourcesCache[image] || (radarImageSourcesCache[image] = createImageSource(image))
  const radarLayer = map.getLayers().getArray()[1]
  radarLayer.setSource(radarImageSource)
  radarLayer.setVisible(true)
  if (lightnings) {
    const lightningLayer = map.getLayers().getArray()[2]
    lightningLayer.setVisible(true)
    const featureObj = {
      type: 'Feature',
      geometry: {
        type: 'MultiPoint',
        coordinates: lightnings.map(coord => fromLonLat(coord))
      }
    }
    const lightningFeature = new GeoJSON().readFeature(featureObj)
    lightningLayer.setSource(new VectorSource({
      features: [lightningFeature]
    }))
  }
}

function createLightningLayer() {
  const source = new VectorSource()
  return new VectorLayer({
    source,
    style: new Style({
        image: new Icon({
          anchor: [0, 1.0],
          src: '/img/lightning.png'
        })
      })
  })
}

function createImageSource(url) {
  return new ImageStatic({
    imageExtent,
    projection: imageProjection,
    url
  })
}

function panTo(map, lonLat) {
  const center = fromLonLat(lonLat);
  const vectorLayer = map.getLayers().getArray()[3]
  const vectorFeature = vectorLayer.getSource().getFeatures()[0]
  vectorFeature.setGeometry(new Point(center))
  map.getView().animate({center, duration: 1000})
}

export {
  createMap,
  panTo,
  showRadarFrame
}
<commit_msg>Disable rotation interactions and controls properly<commit_after>import {defaults as defaultInteractions} from 'ol/interaction'
import Feature from 'ol/Feature'
import {register} from 'ol/proj/proj4'
import Icon from 'ol/style/Icon'
import Image from 'ol/layer/Image'
import ImageStatic from 'ol/source/ImageStatic'
import Map from 'ol/Map'
import Point from 'ol/geom/Point'
import proj4 from 'proj4'
import Projection from 'ol/proj/Projection'
import Style from 'ol/style/Style'
import Tile from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
import View from 'ol/View'
import XYZ from 'ol/source/XYZ'
import {fromLonLat} from 'ol/proj'
import VectorSource from 'ol/source/Vector'
import {defaults as defaultControls, Attribution} from 'ol/control'
import GeoJSON from 'ol/format/GeoJSON'

proj4.defs('EPSG:3067', '+proj=utm +zone=35 +ellps=GRS80 +units=m +no_defs')
register(proj4)
const imageProjection = new Projection({code: 'EPSG:3067'})
const imageExtent = [-118331.366, 6335621.167, 875567.732, 7907751.537]

function createMap(settings) {
  const {x, y, zoom} = settings
  const center = [x, y]
  const view = new View({
    center,
    minZoom: 5,
    maxZoom: 13,
    projection: 'EPSG:3857',
    zoom
  })

  const attribution = new Attribution({
    collapsible: false
  })
  const map = new Map({
    controls: defaultControls({attribution: false, rotate: false}).extend([attribution]),
    interactions: defaultInteractions({altShiftDragRotate: false, pinchRotate: false}),
    layers: [createMapLayer(), createRadarLayer(), createLightningLayer(), createIconLayer(center)],
    target: 'map',
    view
  })

  // OpenLayers leaves the map distorted on some mobile browsers after screen orientation change
  window.addEventListener('orientationchange', () => location.reload())

  return map
}

function createMapLayer() {
  const attributions = ['© OpenStreetMap contributors']
  const source = new XYZ({url: '/tiles/{z}/{x}/{y}.png', attributions})
  return new Tile({source})
}

function createRadarLayer() {
  return new Image({opacity: 0.8, visible: false})
}

function createIconLayer(position) {
  const style = new Style({
    image: new Icon({
      anchor: [0.5, 1.0],
      anchorXUnits: 'fraction',
      anchorYUnits: 'fraction',
      scale: 0.33,
      src: '/img/pin.png'
    })
  })

  const iconFeature = new Feature({
    geometry: new Point(position)
  })
  iconFeature.setStyle(style)

  const source = new VectorSource({features: [iconFeature]})
  return new VectorLayer({source})
}

const radarImageSourcesCache = {}

function showRadarFrame(map, {image, lightnings}) {
  const radarImageSource = radarImageSourcesCache[image] || (radarImageSourcesCache[image] = createImageSource(image))
  const radarLayer = map.getLayers().getArray()[1]
  radarLayer.setSource(radarImageSource)
  radarLayer.setVisible(true)
  if (lightnings) {
    const lightningLayer = map.getLayers().getArray()[2]
    lightningLayer.setVisible(true)
    const featureObj = {
      type: 'Feature',
      geometry: {
        type: 'MultiPoint',
        coordinates: lightnings.map(coord => fromLonLat(coord))
      }
    }
    const lightningFeature = new GeoJSON().readFeature(featureObj)
    lightningLayer.setSource(new VectorSource({
      features: [lightningFeature]
    }))
  }
}

function createLightningLayer() {
  const source = new VectorSource()
  return new VectorLayer({
    source,
    style: new Style({
        image: new Icon({
          anchor: [0, 1.0],
          src: '/img/lightning.png'
        })
      })
  })
}

function createImageSource(url) {
  return new ImageStatic({
    imageExtent,
    projection: imageProjection,
    url
  })
}

function panTo(map, lonLat) {
  const center = fromLonLat(lonLat);
  const vectorLayer = map.getLayers().getArray()[3]
  const vectorFeature = vectorLayer.getSource().getFeatures()[0]
  vectorFeature.setGeometry(new Point(center))
  map.getView().animate({center, duration: 1000})
}

export {
  createMap,
  panTo,
  showRadarFrame
}
<|endoftext|>