<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import {
    ListRow,
    Button,
    Icon,
    Text,
    TextLabel,
} from '@ichef/gypcrete';

import { PurePopover } from '@ichef/gypcrete/lib/Popover';
import anchored from '@ichef/gypcrete/lib/mixins/anchored';
import closable from '@ichef/gypcrete/lib/mixins/closable';
import renderToLayer from '@ichef/gypcrete/lib/mixins/renderToLayer';

import SelectList from './SelectList';

import formRow, { rowPropTypes } from './mixins/formRow';
import './styles/SelectRow.scss';

export const Popover = renderToLayer(
    closable({
        onEscape: true,
        onClickOutside: true,
        onClickInside: false,
    })(
        anchored()(PurePopover)
    )
);

class SelectRow extends PureComponent {
    static propTypes = {
        label: PropTypes.node.isRequired,
        disabled: PropTypes.bool,
        // from formRow()
        ineditable: PropTypes.bool,
        rowProps: rowPropTypes,
    };

    static defaultProps = {
        disabled: false,
        ineditable: false,
        rowProps: {},
    };

    state = {
        popoverOpen: false,
    };

    handleButtonClick = () => {
        this.setState({ popoverOpen: true });
    }

    handlePopoverClose = () => {
        this.setState({ popoverOpen: false });
    }

    renderPopover(selectListProps) {
        return (
            <Popover
                anchor={this.anchorNode}
                onClose={this.handlePopoverClose}>
                <SelectList
                    onChange={this.handleSelectChange}
                    {...selectListProps} />
            </Popover>
        );
    }

    render() {
        const {
            label,
            disabled,
            // from formRow()
            ineditable,
            rowProps,
            // React props
            className,
            ...selectListProps,
        } = this.props;
        const { popoverOpen } = this.state;

        const wrapperClassName = classNames(
            'gyp-form-select',
            className,
        );

        const Content = ineditable ? TextLabel : Button;
        const contentProps = ineditable ? {} : {
            onClick: this.handleButtonClick,
        };

        return (
            <ListRow className={wrapperClassName} {...rowProps}>
                <Content minified={false} disabled={disabled} {...contentProps}>
                    <Text
                        ref={(ref) => { this.anchorNode = ref; }}
                        bold={!ineditable}
                        basic={label} />
                    <Icon type="unfold" />

                    {popoverOpen && this.renderPopover(selectListProps)}
                </Content>
            </ListRow>
        );
    }
}

export { SelectRow as PureSelectRow };
export default formRow()(SelectRow);
<commit_msg>[form] Use unfold icon as anchor for <SelectRow><commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import {
    ListRow,
    Button,
    Icon,
    Text,
    TextLabel,
} from '@ichef/gypcrete';

import { PurePopover } from '@ichef/gypcrete/lib/Popover';
import anchored from '@ichef/gypcrete/lib/mixins/anchored';
import closable from '@ichef/gypcrete/lib/mixins/closable';
import renderToLayer from '@ichef/gypcrete/lib/mixins/renderToLayer';

import SelectList from './SelectList';

import formRow, { rowPropTypes } from './mixins/formRow';
import './styles/SelectRow.scss';

export const Popover = renderToLayer(
    closable({
        onEscape: true,
        onClickOutside: true,
        onClickInside: false,
    })(
        anchored()(PurePopover)
    )
);

class SelectRow extends PureComponent {
    static propTypes = {
        label: PropTypes.node.isRequired,
        disabled: PropTypes.bool,
        // from formRow()
        ineditable: PropTypes.bool,
        rowProps: rowPropTypes,
    };

    static defaultProps = {
        disabled: false,
        ineditable: false,
        rowProps: {},
    };

    state = {
        popoverOpen: false,
    };

    handleButtonClick = () => {
        this.setState({ popoverOpen: true });
    }

    handlePopoverClose = () => {
        this.setState({ popoverOpen: false });
    }

    renderPopover(selectListProps) {
        return (
            <Popover
                anchor={this.anchorNode}
                onClose={this.handlePopoverClose}>
                <SelectList
                    onChange={this.handleSelectChange}
                    {...selectListProps} />
            </Popover>
        );
    }

    render() {
        const {
            label,
            disabled,
            // from formRow()
            ineditable,
            rowProps,
            // React props
            className,
            ...selectListProps,
        } = this.props;
        const { popoverOpen } = this.state;

        const wrapperClassName = classNames(
            'gyp-form-select',
            className,
        );

        const Content = ineditable ? TextLabel : Button;
        const contentProps = ineditable ? {} : {
            onClick: this.handleButtonClick,
        };

        return (
            <ListRow className={wrapperClassName} {...rowProps}>
                <Content minified={false} disabled={disabled} {...contentProps}>
                    <Text
                        bold={!ineditable}
                        basic={label} />

                    <span ref={(ref) => { this.anchorNode = ref; }}>
                        <Icon type="unfold" />
                    </span>

                    {popoverOpen && this.renderPopover(selectListProps)}
                </Content>
            </ListRow>
        );
    }
}

export { SelectRow as PureSelectRow };
export default formRow()(SelectRow);
<|endoftext|>


<commit_before>var createHash = require('./create-hash')

var blocksize = 64
var zeroBuffer = new Buffer(blocksize); zeroBuffer.fill(0)

function hmac(fn, key, data) {
  if(!Buffer.isBuffer(key)) key = new Buffer(key)
  if(!Buffer.isBuffer(data)) data = new Buffer(data)

  if(key.length > blocksize) {
    key = fn(key)
  } else if(key.length < blocksize) {
    key = Buffer.concat([key, zeroBuffer], blocksize)
  }

  var ipad = new Buffer(blocksize), opad = new Buffer(blocksize)
  for(var i = 0; i < blocksize; i++) {
    ipad[i] = key[i] ^ 0x36
    opad[i] = key[i] ^ 0x5C
  }

  var hash = fn(Buffer.concat([ipad, data]))
  return fn(Buffer.concat([opad, hash]))
}

module.exports = createHmac

function createHmac (alg, key) {
  if(!Buffer.isBuffer(key)) key = new Buffer(key)
//  if(!Buffer.isBuffer(data)) data = new Buffer(data)

  if(key.length > blocksize) {
    key = createHash(alg).update(key).digest()
  } else if(key.length < blocksize) {
    key = Buffer.concat([key, zeroBuffer], blocksize)
  }

  var ipad = new Buffer(blocksize), opad = new Buffer(blocksize)
  for(var i = 0; i < blocksize; i++) {
    ipad[i] = key[i] ^ 0x36
    opad[i] = key[i] ^ 0x5C
  }
  hash = createHash(alg).update(ipad)//.update(data)
  var digest = hash.digest
  hash.digest = function (enc) {
    var h = digest.call(hash)
    return createHash(alg).update(opad).update(h).digest(enc)
  }
  return hash
}
<commit_msg>simpler hmac - that doesn't do anything weird to objects<commit_after>var createHash = require('./create-hash')

var blocksize = 64
var zeroBuffer = new Buffer(blocksize); zeroBuffer.fill(0)

module.exports = Hmac

function Hmac (alg, key) {
  if(!(this instanceof Hmac)) return new Hmac(alg, key)
  this._opad = opad
  this._alg = alg

  key = this._key = !Buffer.isBuffer(key) ? new Buffer(key) : key

  if(key.length > blocksize) {
    key = createHash(alg).update(key).digest()
  } else if(key.length < blocksize) {
    key = Buffer.concat([key, zeroBuffer], blocksize)
  }

  var ipad = this._ipad = new Buffer(blocksize)
  var opad = this._opad = new Buffer(blocksize)

  for(var i = 0; i < blocksize; i++) {
    ipad[i] = key[i] ^ 0x36
    opad[i] = key[i] ^ 0x5C
  }

  this._hash = createHash(alg).update(ipad)
}

Hmac.prototype.update = function (data, enc) {
  this._hash.update(data, enc)
  return this
}

Hmac.prototype.digest = function (enc) {
  var h = this._hash.digest()
  return createHash(this._alg).update(this._opad).update(h).digest(enc)
}

<|endoftext|>


<commit_before>Package.describe({
  summary: "Deprecated",
  internal: true
});

Package.on_use(function (api) {
  throw new Error(
    "The 'handlebars' package is deprecated. "
      + "`Handlebars.registerHelper` is now defined in the 'ui' package.");
});
<commit_msg>Unbreak `meteor test-packages`<commit_after>Package.describe({
  summary: "Deprecated",
  internal: true
});

Package.on_use(function (api) {
// XXX we unfortunately we can't do this since `meteor test-packages`
// tries to load all packages.
//
//  throw new Error(
//    "The 'handlebars' package is deprecated. "
//      + "`Handlebars.registerHelper` is now defined in the 'ui' package.");
});

<|endoftext|>


<commit_before>/*
 * biojs-io-biom
 * https://github.com/iimog/biojs-io-biom
 *
 * Copyright (c) 2016 Markus J. Ankenbrand
 * Licensed under the MIT license.
 */

/**
 * Version
 * @type {string} version of this module
 */
export const VERSION = '0.1.0';

/**
 * Default Biom Object for empty initialization
 * @type {{
 * id: null,
 * format: string,
 * format_url: string,
 * type: string,
 * generated_by: string,
 * date: Date,
 * rows: Array,
 * columns: Array,
 * matrix_type: string,
 * matrix_element_type: string,
 * shape: number[],
 * data: Array
 * }}
 */
export const DEFAULT_BIOM = {
    id: null,
    format: 'Biological Observation Matrix 1.0.0',
    format_url: 'http://biom-format.org',
    type: 'OTU table',
    generated_by: `biojs-io-biom v${VERSION}`,
    date: null, // will be set to Date.now() in the constructor
    rows: [],
    columns: [],
    matrix_type: 'sparse',
    matrix_element_type: 'float',
    shape: [0,0],
    data: []
};

/**
 * Controlled vocabulary for the type field of biom objects
 * @type {string[]}
 */
export const BIOM_TYPE_CV = [
    'OTU table',
    'Pathway table',
    'Function table',
    'Ortholog table',
    'Gene table',
    'Metabolite table',
    'Taxon table'
];

/**
 * @class Biom
 */
export class Biom {
    /**
     * constructor
     * @param _id
     * @param _format
     * @param _format_url
     * @param _type
     * @param _generated_by
     * @param _date
     * @param _rows
     * @param _columns
     * @param _matrix_type
     * @param _matrix_element_type
     * @param _shape
     * @param _data
     */
    constructor({
        id: _id = null,
        format: _format = DEFAULT_BIOM.format,
        format_url: _format_url = DEFAULT_BIOM.format_url,
        type: _type = DEFAULT_BIOM.type,
        generated_by: _generated_by = DEFAULT_BIOM.generated_by,
        date: _date = Date.now(),
        rows: _rows = DEFAULT_BIOM.rows,
        columns: _columns = DEFAULT_BIOM.columns,
        matrix_type: _matrix_type = DEFAULT_BIOM.matrix_type,
        matrix_element_type:
            _matrix_element_type = DEFAULT_BIOM.matrix_element_type,
        shape: _shape = DEFAULT_BIOM.shape,
        data: _data = DEFAULT_BIOM.data
    } = {}){
        this.id = _id;
        this._format = _format;
        this._format_url = _format_url;
        this._type = _type;
        this._generated_by = _generated_by;
        this._date = _date;
        this._rows = _rows;
        this._columns = _columns;
        this._matrix_type = _matrix_type;
        this._matrix_element_type = _matrix_element_type;
        this._shape = _shape;
        this._data = _data;
    }

    /**
     * Getter for id
     * @returns {string} - A field that can be used to id a table (or null)
     */
    get id(){
        return this._id;
    }

    /**
     * Setter for id
     * @param id {string} - A field that can be used to id a table (or null)
     * @throws {TypeError} if id is not a string (or null)
     */
    set id(id){
        if(id !== null && typeof id !== 'string'){
            throw new TypeError('id must be string or null');
        }
        this._id = id;
    }

    /**
     * Getter for format
     * @returns {string} - The name and version of the current biom format
     */
    get format(){
        return this._format;
    }

    /**
     * Setter for format
     * @param format {string} - The name and version of the current biom format
     * @throws {TypeError} if format is not a string
     */
    set format(format){
        if(typeof format !== 'string'){
            throw new TypeError('format must be string');
        }
        this._format = format;
    }

    /**
     * Getter for format_url
     * @returns {string} - A string with a static URL providing format details
     */
    get format_url(){
        return this._format_url;
    }

    /**
     * Setter for format_url
     * @param format_url {string} - A string with a static URL
     *                              providing format details
     *                              (not checked whether the string is an url)
     * @throws {TypeError} if format_url is not a string
     */
    set format_url(format_url){
        if(typeof format_url !== 'string'){
            throw new TypeError('format_url must be string' +
                ' (representing a static URL)');
        }
        this._format_url = format_url;
    }

    /**
     * Getter for type
     * @returns {string} - Table type (a controlled vocabulary)
     *                     Acceptable values:
     *                       'OTU table'
     *                       'Pathway table'
     *                       'Function table'
     *                       'Ortholog table'
     *                       'Gene table'
     *                       'Metabolite table'
     *                       'Taxon table'
     */
    get type(){
        return this._type;
    }

    /**
     * Setter for type
     * @param type {string} - Table type (a controlled vocabulary)
     *                        Acceptable values:
     *                          'OTU table'
     *                          'Pathway table'
     *                          'Function table'
     *                          'Ortholog table'
     *                          'Gene table'
     *                          'Metabolite table'
     *                          'Taxon table'
     * @throws {TypeError} if type is not a string
     * @throws {Error} if type is not in the controlled vocabulary
     */
    set type(type){
        if(typeof type !== 'string'){
            throw new TypeError('type must be string' +
                ' (part of the controlled vocabulary)');
        }
        if(BIOM_TYPE_CV.indexOf(type) === -1){
            throw new Error('type must be part of the controlled vocabulary');
        }
        this._type = type;
    }

    /**
     * Getter for generated_by
     * @returns {string} - Package and revision that built the table
     */
    get generated_by(){
        return this._generated_by;
    }

    /**
     * Getter for date
     * @returns {Date} - Date the table was built (ISO 8601 format)
     */
    get date(){
        return this._date;
    }

    /**
     * Getter for rows
     * @returns {Array} - An ORDERED list of obj describing the rows
     */
    get rows(){
        return this._rows;
    }

    /**
     * Getter for columns
     * @returns {Array} - An ORDERED list of obj describing the columns
     */
    get columns(){
        return this._columns;
    }

    /**
     * Getter for matrix_type
     * @returns {string} - Type of matrix data representation
     *                     (a controlled vocabulary) Acceptable values:
     *                       'sparse' : only non-zero values are specified
     *                       'dense' : every element must be specified
     */
    get matrix_type(){
        return this._matrix_type;
    }

    /**
     * Getter for matrix_element_type
     * @returns {string} - Value type in matrix (a controlled vocabulary)
     *                     Acceptable values:
     *                       'int' : integer
     *                       'float' : floating point
     *                       'unicode' : unicode string
     */
    get matrix_element_type(){
        return this._matrix_element_type;
    }

    /**
     * Getter for shape
     * @returns {Array} - the number of rows and number of columns in data
     */
    get shape(){
        return this._shape;
    }

    /**
     * Getter for data
     * @returns {Array} - counts of observations by sample
     *                   if matrix_type is 'sparse', [[row, column, value],
     *                                                 [row, column, value],
     *                                                                  ...]
     *                   if matrix_type is 'dense', [[value, value, value, ...],
     *                                               [value, value, value, ...],
     *                                                                      ...]
     */
    get data(){
        return this._data;
    }
}
<commit_msg>Add generated_by setter<commit_after>/*
 * biojs-io-biom
 * https://github.com/iimog/biojs-io-biom
 *
 * Copyright (c) 2016 Markus J. Ankenbrand
 * Licensed under the MIT license.
 */

/**
 * Version
 * @type {string} version of this module
 */
export const VERSION = '0.1.0';

/**
 * Default Biom Object for empty initialization
 * @type {{
 * id: null,
 * format: string,
 * format_url: string,
 * type: string,
 * generated_by: string,
 * date: Date,
 * rows: Array,
 * columns: Array,
 * matrix_type: string,
 * matrix_element_type: string,
 * shape: number[],
 * data: Array
 * }}
 */
export const DEFAULT_BIOM = {
    id: null,
    format: 'Biological Observation Matrix 1.0.0',
    format_url: 'http://biom-format.org',
    type: 'OTU table',
    generated_by: `biojs-io-biom v${VERSION}`,
    date: null, // will be set to Date.now() in the constructor
    rows: [],
    columns: [],
    matrix_type: 'sparse',
    matrix_element_type: 'float',
    shape: [0,0],
    data: []
};

/**
 * Controlled vocabulary for the type field of biom objects
 * @type {string[]}
 */
export const BIOM_TYPE_CV = [
    'OTU table',
    'Pathway table',
    'Function table',
    'Ortholog table',
    'Gene table',
    'Metabolite table',
    'Taxon table'
];

/**
 * @class Biom
 */
export class Biom {
    /**
     * constructor
     * @param _id
     * @param _format
     * @param _format_url
     * @param _type
     * @param _generated_by
     * @param _date
     * @param _rows
     * @param _columns
     * @param _matrix_type
     * @param _matrix_element_type
     * @param _shape
     * @param _data
     */
    constructor({
        id: _id = null,
        format: _format = DEFAULT_BIOM.format,
        format_url: _format_url = DEFAULT_BIOM.format_url,
        type: _type = DEFAULT_BIOM.type,
        generated_by: _generated_by = DEFAULT_BIOM.generated_by,
        date: _date = Date.now(),
        rows: _rows = DEFAULT_BIOM.rows,
        columns: _columns = DEFAULT_BIOM.columns,
        matrix_type: _matrix_type = DEFAULT_BIOM.matrix_type,
        matrix_element_type:
            _matrix_element_type = DEFAULT_BIOM.matrix_element_type,
        shape: _shape = DEFAULT_BIOM.shape,
        data: _data = DEFAULT_BIOM.data
    } = {}){
        this.id = _id;
        this._format = _format;
        this._format_url = _format_url;
        this._type = _type;
        this._generated_by = _generated_by;
        this._date = _date;
        this._rows = _rows;
        this._columns = _columns;
        this._matrix_type = _matrix_type;
        this._matrix_element_type = _matrix_element_type;
        this._shape = _shape;
        this._data = _data;
    }

    /**
     * Getter for id
     * @returns {string} - A field that can be used to id a table (or null)
     */
    get id(){
        return this._id;
    }

    /**
     * Setter for id
     * @param id {string} - A field that can be used to id a table (or null)
     * @throws {TypeError} if id is not a string (or null)
     */
    set id(id){
        if(id !== null && typeof id !== 'string'){
            throw new TypeError('id must be string or null');
        }
        this._id = id;
    }

    /**
     * Getter for format
     * @returns {string} - The name and version of the current biom format
     */
    get format(){
        return this._format;
    }

    /**
     * Setter for format
     * @param format {string} - The name and version of the current biom format
     * @throws {TypeError} if format is not a string
     */
    set format(format){
        if(typeof format !== 'string'){
            throw new TypeError('format must be string');
        }
        this._format = format;
    }

    /**
     * Getter for format_url
     * @returns {string} - A string with a static URL providing format details
     */
    get format_url(){
        return this._format_url;
    }

    /**
     * Setter for format_url
     * @param format_url {string} - A string with a static URL
     *                              providing format details
     *                              (not checked whether the string is an url)
     * @throws {TypeError} if format_url is not a string
     */
    set format_url(format_url){
        if(typeof format_url !== 'string'){
            throw new TypeError('format_url must be string' +
                ' (representing a static URL)');
        }
        this._format_url = format_url;
    }

    /**
     * Getter for type
     * @returns {string} - Table type (a controlled vocabulary)
     *                     Acceptable values:
     *                       'OTU table'
     *                       'Pathway table'
     *                       'Function table'
     *                       'Ortholog table'
     *                       'Gene table'
     *                       'Metabolite table'
     *                       'Taxon table'
     */
    get type(){
        return this._type;
    }

    /**
     * Setter for type
     * @param type {string} - Table type (a controlled vocabulary)
     *                        Acceptable values:
     *                          'OTU table'
     *                          'Pathway table'
     *                          'Function table'
     *                          'Ortholog table'
     *                          'Gene table'
     *                          'Metabolite table'
     *                          'Taxon table'
     * @throws {TypeError} if type is not a string
     * @throws {Error} if type is not in the controlled vocabulary
     */
    set type(type){
        if(typeof type !== 'string'){
            throw new TypeError('type must be string' +
                ' (part of the controlled vocabulary)');
        }
        if(BIOM_TYPE_CV.indexOf(type) === -1){
            throw new Error('type must be part of the controlled vocabulary');
        }
        this._type = type;
    }

    /**
     * Getter for generated_by
     * @returns {string} - Package and revision that built the table
     */
    get generated_by(){
        return this._generated_by;
    }

    /**
     * Setter for generated_by
     * @param generated_by {string} - Package and revision that built the table
     * @throws {TypeError} if generated_by is not a string
     */
    set generated_by(generated_by){
        if(typeof generated_by !== 'string'){
            throw new TypeError('generated_by must be string');
        }
        this._generated_by = generated_by;
    }

    /**
     * Getter for date
     * @returns {Date} - Date the table was built (ISO 8601 format)
     */
    get date(){
        return this._date;
    }

    /**
     * Getter for rows
     * @returns {Array} - An ORDERED list of obj describing the rows
     */
    get rows(){
        return this._rows;
    }

    /**
     * Getter for columns
     * @returns {Array} - An ORDERED list of obj describing the columns
     */
    get columns(){
        return this._columns;
    }

    /**
     * Getter for matrix_type
     * @returns {string} - Type of matrix data representation
     *                     (a controlled vocabulary) Acceptable values:
     *                       'sparse' : only non-zero values are specified
     *                       'dense' : every element must be specified
     */
    get matrix_type(){
        return this._matrix_type;
    }

    /**
     * Getter for matrix_element_type
     * @returns {string} - Value type in matrix (a controlled vocabulary)
     *                     Acceptable values:
     *                       'int' : integer
     *                       'float' : floating point
     *                       'unicode' : unicode string
     */
    get matrix_element_type(){
        return this._matrix_element_type;
    }

    /**
     * Getter for shape
     * @returns {Array} - the number of rows and number of columns in data
     */
    get shape(){
        return this._shape;
    }

    /**
     * Getter for data
     * @returns {Array} - counts of observations by sample
     *                   if matrix_type is 'sparse', [[row, column, value],
     *                                                 [row, column, value],
     *                                                                  ...]
     *                   if matrix_type is 'dense', [[value, value, value, ...],
     *                                               [value, value, value, ...],
     *                                                                      ...]
     */
    get data(){
        return this._data;
    }
}
<|endoftext|>


<commit_before>/*
 * biojs-io-biom
 * https://github.com/iimog/biojs-io-biom
 *
 * Copyright (c) 2016 Markus J. Ankenbrand
 * Licensed under the MIT license.
 */

/**
 * Version
 * @type {string} version of this module
 */
export const VERSION = '0.1.0';

/**
 * Default Biom Object for empty initialization
 * @type {{
 * id: null,
 * format: string,
 * format_url: string,
 * type: string,
 * generated_by: string,
 * date: Date,
 * rows: Array,
 * columns: Array,
 * matrix_type: string,
 * matrix_element_type: string,
 * shape: number[],
 * data: Array
 * }}
 */
export const DEFAULT_BIOM = {
    id: null,
    format: 'Biological Observation Matrix 1.0.0',
    format_url: 'http://biom-format.org',
    type: 'OTU table',
    generated_by: `biojs-io-biom v${VERSION}`,
    date: null, // will be set to Date.now() in the constructor
    rows: [],
    columns: [],
    matrix_type: 'sparse',
    matrix_element_type: 'float',
    shape: [0,0],
    data: []
};

/**
 * Controlled vocabulary for the type field of biom objects
 * @type {string[]}
 */
export const TYPE_CV = [
    'OTU table',
    'Pathway table',
    'Function table',
    'Ortholog table',
    'Gene table',
    'Metabolite table',
    'Taxon table'
];

/**
 * Controlled vocabulary for the matrix_type field of biom objects
 * @type {string[]}
 */
export const MATRIX_TYPE_CV = [
    'sparse', // only non-zero values are specified
    'dense'   // every element must be specified
];

/**
 * Controlled vocabulary for the matrix_element_type field of biom objects
 * @type {string[]}
 */
export const MATRIX_ELEMENT_TYPE_CV = [
    'int',    // integer
    'float',  // floating point
    'unicode' // unicode string
];

/**
 * @class Biom
 */
export class Biom {
    /**
     * constructor
     * @param _id
     * @param _format
     * @param _format_url
     * @param _type
     * @param _generated_by
     * @param _date
     * @param _rows
     * @param _columns
     * @param _matrix_type
     * @param _matrix_element_type
     * @param _shape
     * @param _data
     */
    constructor({
        id: _id = null,
        format: _format = DEFAULT_BIOM.format,
        format_url: _format_url = DEFAULT_BIOM.format_url,
        type: _type = DEFAULT_BIOM.type,
        generated_by: _generated_by = DEFAULT_BIOM.generated_by,
        date: _date = null,
        rows: _rows = DEFAULT_BIOM.rows,
        columns: _columns = DEFAULT_BIOM.columns,
        matrix_type: _matrix_type = DEFAULT_BIOM.matrix_type,
        matrix_element_type:
            _matrix_element_type = DEFAULT_BIOM.matrix_element_type,
        shape: _shape = DEFAULT_BIOM.shape,
        data: _data = DEFAULT_BIOM.data
    } = {}){
        this.id = _id;
        this._format = _format;
        this._format_url = _format_url;
        this._type = _type;
        this._generated_by = _generated_by;
        if(_date === null){
            _date = new Date().toISOString();
        }
        this._date = _date;
        this._rows = _rows;
        this._columns = _columns;
        this._matrix_type = _matrix_type;
        this._matrix_element_type = _matrix_element_type;
        this._shape = _shape;
        this._data = _data;
    }

    /**
     * Getter for id
     * @returns {string} - A field that can be used to id a table (or null)
     */
    get id(){
        return this._id;
    }

    /**
     * Setter for id
     * @param id {string} - A field that can be used to id a table (or null)
     * @throws {TypeError} if id is not a string (or null)
     */
    set id(id){
        if(id !== null && typeof id !== 'string'){
            throw new TypeError('id must be string or null');
        }
        this._id = id;
    }

    /**
     * Getter for format
     * @returns {string} - The name and version of the current biom format
     */
    get format(){
        return this._format;
    }

    /**
     * Setter for format
     * @param format {string} - The name and version of the current biom format
     * @throws {TypeError} if format is not a string
     */
    set format(format){
        if(typeof format !== 'string'){
            throw new TypeError('format must be string');
        }
        this._format = format;
    }

    /**
     * Getter for format_url
     * @returns {string} - A string with a static URL providing format details
     */
    get format_url(){
        return this._format_url;
    }

    /**
     * Setter for format_url
     * @param format_url {string} - A string with a static URL
     *                              providing format details
     *                              (not checked whether the string is an url)
     * @throws {TypeError} if format_url is not a string
     */
    set format_url(format_url){
        if(typeof format_url !== 'string'){
            throw new TypeError('format_url must be string' +
                ' (representing a static URL)');
        }
        this._format_url = format_url;
    }

    /**
     * Getter for type
     * @returns {string} - Table type (a controlled vocabulary)
     *                     Acceptable values:
     *                       'OTU table'
     *                       'Pathway table'
     *                       'Function table'
     *                       'Ortholog table'
     *                       'Gene table'
     *                       'Metabolite table'
     *                       'Taxon table'
     */
    get type(){
        return this._type;
    }

    /**
     * Setter for type
     * @param type {string} - Table type (a controlled vocabulary)
     *                        Acceptable values:
     *                          'OTU table'
     *                          'Pathway table'
     *                          'Function table'
     *                          'Ortholog table'
     *                          'Gene table'
     *                          'Metabolite table'
     *                          'Taxon table'
     * @throws {TypeError} if type is not a string
     * @throws {Error} if type is not in the controlled vocabulary
     */
    set type(type){
        if(typeof type !== 'string'){
            throw new TypeError('type must be string' +
                ' (part of the controlled vocabulary)');
        }
        if(TYPE_CV.indexOf(type) === -1){
            throw new Error('type must be part of the controlled vocabulary');
        }
        this._type = type;
    }

    /**
     * Getter for generated_by
     * @returns {string} - Package and revision that built the table
     */
    get generated_by(){
        return this._generated_by;
    }

    /**
     * Setter for generated_by
     * @param generated_by {string} - Package and revision that built the table
     * @throws {TypeError} if generated_by is not a string
     */
    set generated_by(generated_by){
        if(typeof generated_by !== 'string'){
            throw new TypeError('generated_by must be string');
        }
        this._generated_by = generated_by;
    }

    /**
     * Getter for date
     * @returns {string} - Date the table was built (ISO 8601 format)
     */
    get date(){
        return this._date;
    }

    /**
     * Setter for date
     * @param date {string} - Date the table was built (ISO 8601 format)
     *                       (not checked whether the string is a date)
     * @throws {TypeError} if date is not a string
     */
    set date(date){
        if(typeof date !== 'string'){
            throw new TypeError('date must be string (ISO 8601 format)');
        }
        this._date = date;
    }

    /**
     * Getter for rows
     * @returns {Array} - An ORDERED list of obj describing the rows
     */
    get rows(){
        return this._rows;
    }

    /**
     * Setter for rows
     * @param rows {Array} - An ORDERED list of obj describing the rows
     * @throws {TypeError} if date is not an Array
     */
    set rows(rows){
        if(Object.prototype.toString.call(rows) !== '[object Array]'){
            throw new TypeError('rows must be an Array');
        }
        this._rows = rows;
    }

    /**
     * Getter for columns
     * @returns {Array} - An ORDERED list of obj describing the columns
     */
    get columns() {
        return this._columns;
    }

    /**
     * Setter for columns
     * @param columns {Array} - An ORDERED list of obj describing the columns
     * @throws {TypeError} if date is not an Array
     */
    set columns(columns){
        if(Object.prototype.toString.call(columns) !== '[object Array]'){
            throw new TypeError('columns must be an Array');
        }
        this._columns = columns;
    }

    /**
     * Getter for matrix_type
     * @returns {string} - Type of matrix data representation
     *                     (a controlled vocabulary) Acceptable values:
     *                       'sparse' : only non-zero values are specified
     *                       'dense' : every element must be specified
     */
    get matrix_type(){
        return this._matrix_type;
    }

    /**
     * Setter for matrix_type
     * @param matrix_type {string} - Type of matrix data representation
     *                               (a controlled vocabulary)
     *                               Acceptable values:
     *                             'sparse' : only non-zero values are specified
     *                             'dense' : every element must be specified
     * @throws {TypeError} if matrix_type is not a string
     * @throws {Error} if matrix_type is not in the controlled vocabulary
     */
    set matrix_type(matrix_type){
        if(typeof matrix_type !== 'string'){
            throw new TypeError('matrix_type must be string' +
                ' (part of the controlled vocabulary: "dense" or "sparse")');
        }
        if(MATRIX_TYPE_CV.indexOf(matrix_type) === -1){
            throw new Error('matrix_type must be part of the' +
                ' controlled vocabulary: "dense" or "sparse"');
        }
        this._matrix_type = matrix_type;
    }

    /**
     * Getter for matrix_element_type
     * @returns {string} - Value type in matrix (a controlled vocabulary)
     *                     Acceptable values:
     *                       'int' : integer
     *                       'float' : floating point
     *                       'unicode' : unicode string
     */
    get matrix_element_type(){
        return this._matrix_element_type;
    }

    /**
     * Setter for matrix_element_type
     * @param matrix_element_type {string} - Value type in matrix
     *                               (a controlled vocabulary)
     *                               Acceptable values:
     *                                 'int' : integer
     *                                 'float' : floating point
     *                                 'unicode' : unicode string
     * @throws {TypeError} if matrix_element_type is not a string
     * @throws {Error} if matrix_element_type is not in controlled vocabulary
     */
    set matrix_element_type(matrix_element_type){
        if(typeof matrix_element_type !== 'string'){
            throw new TypeError('matrix_element_type must be string' +
                ' (part of the controlled vocabulary:' +
                ' "int", "float" or "unicode")');
        }
        if(MATRIX_ELEMENT_TYPE_CV.indexOf(matrix_element_type) === -1){
            throw new Error('matrix_element_type must be part of the' +
                ' controlled vocabulary: "int", "float" or "unicode"');
        }
        this._matrix_element_type = matrix_element_type;
    }

    /**
     * Getter for shape
     * @returns {Array} - the number of rows and number of columns in data
     */
    get shape(){
        return this._shape;
    }

    /**
     * Setter for shape
     * @param shape {Array} - the number of rows and number of columns in data
     * @throws {TypeError} if shape is not an Array
     * @throws {Error} if shape contains something other than two non-negative integers
     */
    set shape(shape){
        if(Object.prototype.toString.call(shape) !== '[object Array]'){
            throw new TypeError('shape must be an Array containing exactly two non-negative integers');
        }
        this._shape = shape;
    }

    /**
     * Getter for data
     * @returns {Array} - counts of observations by sample
     *                   if matrix_type is 'sparse', [[row, column, value],
     *                                                 [row, column, value],
     *                                                                  ...]
     *                   if matrix_type is 'dense', [[value, value, value, ...],
     *                                               [value, value, value, ...],
     *                                                                      ...]
     */
    get data(){
        return this._data;
    }
}
<commit_msg>Add checks to shape setter<commit_after>/*
 * biojs-io-biom
 * https://github.com/iimog/biojs-io-biom
 *
 * Copyright (c) 2016 Markus J. Ankenbrand
 * Licensed under the MIT license.
 */

/**
 * Version
 * @type {string} version of this module
 */
export const VERSION = '0.1.0';

/**
 * Default Biom Object for empty initialization
 * @type {{
 * id: null,
 * format: string,
 * format_url: string,
 * type: string,
 * generated_by: string,
 * date: Date,
 * rows: Array,
 * columns: Array,
 * matrix_type: string,
 * matrix_element_type: string,
 * shape: number[],
 * data: Array
 * }}
 */
export const DEFAULT_BIOM = {
    id: null,
    format: 'Biological Observation Matrix 1.0.0',
    format_url: 'http://biom-format.org',
    type: 'OTU table',
    generated_by: `biojs-io-biom v${VERSION}`,
    date: null, // will be set to Date.now() in the constructor
    rows: [],
    columns: [],
    matrix_type: 'sparse',
    matrix_element_type: 'float',
    shape: [0,0],
    data: []
};

/**
 * Controlled vocabulary for the type field of biom objects
 * @type {string[]}
 */
export const TYPE_CV = [
    'OTU table',
    'Pathway table',
    'Function table',
    'Ortholog table',
    'Gene table',
    'Metabolite table',
    'Taxon table'
];

/**
 * Controlled vocabulary for the matrix_type field of biom objects
 * @type {string[]}
 */
export const MATRIX_TYPE_CV = [
    'sparse', // only non-zero values are specified
    'dense'   // every element must be specified
];

/**
 * Controlled vocabulary for the matrix_element_type field of biom objects
 * @type {string[]}
 */
export const MATRIX_ELEMENT_TYPE_CV = [
    'int',    // integer
    'float',  // floating point
    'unicode' // unicode string
];

/**
 * @class Biom
 */
export class Biom {
    /**
     * constructor
     * @param _id
     * @param _format
     * @param _format_url
     * @param _type
     * @param _generated_by
     * @param _date
     * @param _rows
     * @param _columns
     * @param _matrix_type
     * @param _matrix_element_type
     * @param _shape
     * @param _data
     */
    constructor({
        id: _id = null,
        format: _format = DEFAULT_BIOM.format,
        format_url: _format_url = DEFAULT_BIOM.format_url,
        type: _type = DEFAULT_BIOM.type,
        generated_by: _generated_by = DEFAULT_BIOM.generated_by,
        date: _date = null,
        rows: _rows = DEFAULT_BIOM.rows,
        columns: _columns = DEFAULT_BIOM.columns,
        matrix_type: _matrix_type = DEFAULT_BIOM.matrix_type,
        matrix_element_type:
            _matrix_element_type = DEFAULT_BIOM.matrix_element_type,
        shape: _shape = DEFAULT_BIOM.shape,
        data: _data = DEFAULT_BIOM.data
    } = {}){
        this.id = _id;
        this._format = _format;
        this._format_url = _format_url;
        this._type = _type;
        this._generated_by = _generated_by;
        if(_date === null){
            _date = new Date().toISOString();
        }
        this._date = _date;
        this._rows = _rows;
        this._columns = _columns;
        this._matrix_type = _matrix_type;
        this._matrix_element_type = _matrix_element_type;
        this._shape = _shape;
        this._data = _data;
    }

    /**
     * Getter for id
     * @returns {string} - A field that can be used to id a table (or null)
     */
    get id(){
        return this._id;
    }

    /**
     * Setter for id
     * @param id {string} - A field that can be used to id a table (or null)
     * @throws {TypeError} if id is not a string (or null)
     */
    set id(id){
        if(id !== null && typeof id !== 'string'){
            throw new TypeError('id must be string or null');
        }
        this._id = id;
    }

    /**
     * Getter for format
     * @returns {string} - The name and version of the current biom format
     */
    get format(){
        return this._format;
    }

    /**
     * Setter for format
     * @param format {string} - The name and version of the current biom format
     * @throws {TypeError} if format is not a string
     */
    set format(format){
        if(typeof format !== 'string'){
            throw new TypeError('format must be string');
        }
        this._format = format;
    }

    /**
     * Getter for format_url
     * @returns {string} - A string with a static URL providing format details
     */
    get format_url(){
        return this._format_url;
    }

    /**
     * Setter for format_url
     * @param format_url {string} - A string with a static URL
     *                              providing format details
     *                              (not checked whether the string is an url)
     * @throws {TypeError} if format_url is not a string
     */
    set format_url(format_url){
        if(typeof format_url !== 'string'){
            throw new TypeError('format_url must be string' +
                ' (representing a static URL)');
        }
        this._format_url = format_url;
    }

    /**
     * Getter for type
     * @returns {string} - Table type (a controlled vocabulary)
     *                     Acceptable values:
     *                       'OTU table'
     *                       'Pathway table'
     *                       'Function table'
     *                       'Ortholog table'
     *                       'Gene table'
     *                       'Metabolite table'
     *                       'Taxon table'
     */
    get type(){
        return this._type;
    }

    /**
     * Setter for type
     * @param type {string} - Table type (a controlled vocabulary)
     *                        Acceptable values:
     *                          'OTU table'
     *                          'Pathway table'
     *                          'Function table'
     *                          'Ortholog table'
     *                          'Gene table'
     *                          'Metabolite table'
     *                          'Taxon table'
     * @throws {TypeError} if type is not a string
     * @throws {Error} if type is not in the controlled vocabulary
     */
    set type(type){
        if(typeof type !== 'string'){
            throw new TypeError('type must be string' +
                ' (part of the controlled vocabulary)');
        }
        if(TYPE_CV.indexOf(type) === -1){
            throw new Error('type must be part of the controlled vocabulary');
        }
        this._type = type;
    }

    /**
     * Getter for generated_by
     * @returns {string} - Package and revision that built the table
     */
    get generated_by(){
        return this._generated_by;
    }

    /**
     * Setter for generated_by
     * @param generated_by {string} - Package and revision that built the table
     * @throws {TypeError} if generated_by is not a string
     */
    set generated_by(generated_by){
        if(typeof generated_by !== 'string'){
            throw new TypeError('generated_by must be string');
        }
        this._generated_by = generated_by;
    }

    /**
     * Getter for date
     * @returns {string} - Date the table was built (ISO 8601 format)
     */
    get date(){
        return this._date;
    }

    /**
     * Setter for date
     * @param date {string} - Date the table was built (ISO 8601 format)
     *                       (not checked whether the string is a date)
     * @throws {TypeError} if date is not a string
     */
    set date(date){
        if(typeof date !== 'string'){
            throw new TypeError('date must be string (ISO 8601 format)');
        }
        this._date = date;
    }

    /**
     * Getter for rows
     * @returns {Array} - An ORDERED list of obj describing the rows
     */
    get rows(){
        return this._rows;
    }

    /**
     * Setter for rows
     * @param rows {Array} - An ORDERED list of obj describing the rows
     * @throws {TypeError} if date is not an Array
     */
    set rows(rows){
        if(Object.prototype.toString.call(rows) !== '[object Array]'){
            throw new TypeError('rows must be an Array');
        }
        this._rows = rows;
    }

    /**
     * Getter for columns
     * @returns {Array} - An ORDERED list of obj describing the columns
     */
    get columns() {
        return this._columns;
    }

    /**
     * Setter for columns
     * @param columns {Array} - An ORDERED list of obj describing the columns
     * @throws {TypeError} if date is not an Array
     */
    set columns(columns){
        if(Object.prototype.toString.call(columns) !== '[object Array]'){
            throw new TypeError('columns must be an Array');
        }
        this._columns = columns;
    }

    /**
     * Getter for matrix_type
     * @returns {string} - Type of matrix data representation
     *                     (a controlled vocabulary) Acceptable values:
     *                       'sparse' : only non-zero values are specified
     *                       'dense' : every element must be specified
     */
    get matrix_type(){
        return this._matrix_type;
    }

    /**
     * Setter for matrix_type
     * @param matrix_type {string} - Type of matrix data representation
     *                               (a controlled vocabulary)
     *                               Acceptable values:
     *                             'sparse' : only non-zero values are specified
     *                             'dense' : every element must be specified
     * @throws {TypeError} if matrix_type is not a string
     * @throws {Error} if matrix_type is not in the controlled vocabulary
     */
    set matrix_type(matrix_type){
        if(typeof matrix_type !== 'string'){
            throw new TypeError('matrix_type must be string' +
                ' (part of the controlled vocabulary: "dense" or "sparse")');
        }
        if(MATRIX_TYPE_CV.indexOf(matrix_type) === -1){
            throw new Error('matrix_type must be part of the' +
                ' controlled vocabulary: "dense" or "sparse"');
        }
        this._matrix_type = matrix_type;
    }

    /**
     * Getter for matrix_element_type
     * @returns {string} - Value type in matrix (a controlled vocabulary)
     *                     Acceptable values:
     *                       'int' : integer
     *                       'float' : floating point
     *                       'unicode' : unicode string
     */
    get matrix_element_type(){
        return this._matrix_element_type;
    }

    /**
     * Setter for matrix_element_type
     * @param matrix_element_type {string} - Value type in matrix
     *                               (a controlled vocabulary)
     *                               Acceptable values:
     *                                 'int' : integer
     *                                 'float' : floating point
     *                                 'unicode' : unicode string
     * @throws {TypeError} if matrix_element_type is not a string
     * @throws {Error} if matrix_element_type is not in controlled vocabulary
     */
    set matrix_element_type(matrix_element_type){
        if(typeof matrix_element_type !== 'string'){
            throw new TypeError('matrix_element_type must be string' +
                ' (part of the controlled vocabulary:' +
                ' "int", "float" or "unicode")');
        }
        if(MATRIX_ELEMENT_TYPE_CV.indexOf(matrix_element_type) === -1){
            throw new Error('matrix_element_type must be part of the' +
                ' controlled vocabulary: "int", "float" or "unicode"');
        }
        this._matrix_element_type = matrix_element_type;
    }

    /**
     * Getter for shape
     * @returns {Array} - the number of rows and number of columns in data
     */
    get shape(){
        return this._shape;
    }

    /**
     * Setter for shape
     * @param shape {Array} - the number of rows and number of columns in data
     * @throws {TypeError} if shape is not an Array
     * @throws {Error} if shape contains something other than two non-negative integers
     */
    set shape(shape){
        if(Object.prototype.toString.call(shape) !== '[object Array]'){
            throw new TypeError('shape must be an Array containing exactly two non-negative integers');
        }
        if(shape.length !== 2){
            throw new Error('shape does not contain exactly two elements');
        }
        if(!Number.isInteger(shape[0]) || shape[0] < 0 || !Number.isInteger(shape[1]) || shape[1] < 0){
            throw new Error('shape does not contain non-negative integers');
        }
        this._shape = shape;
    }

    /**
     * Getter for data
     * @returns {Array} - counts of observations by sample
     *                   if matrix_type is 'sparse', [[row, column, value],
     *                                                 [row, column, value],
     *                                                                  ...]
     *                   if matrix_type is 'dense', [[value, value, value, ...],
     *                                               [value, value, value, ...],
     *                                                                      ...]
     */
    get data(){
        return this._data;
    }
}
<|endoftext|>


<commit_before>const Crystalline = (function()
{
	"use strict";
	const libName = "Crystalline"
	const nameBindings = {};
	const keysInitialized = {};
	let CrElementCount = 0;
	let windowLoaded = false;
	const API = {
		data:{}
	};

	//TODO
	//How to handle objects
	//An object should make a table with keys as the column names and values as the cell values
	//An array of objects should therefore collect all keys and then fill in the cells with each object's value

	return (function()
	{
		//SETUP
		const dataStorage = function()
		{
			if(!sessionStorage._CrSession)
			{
				sessionStorage._CrSession = "{}";
			}
			const _data = JSON.parse(sessionStorage._CrSession);

			return Object.freeze(
			{
				set: function(name, value)
				{
					_data[name] = { value: value };
					_data[name].template = "";
					sessionStorage._CrSession = JSON.stringify(_data);
					if(Array.isArray(value))
					{
						value.push = function(pushedVal)
						{
							Array.prototype.push.call(value, pushedVal);
							API_set(name, value);
						}
					}
				},
				get: function(name, value)
				{
					return _data[name].value;
				},
				setTemplate: function(name, str)
				{
					_data[name].template = str;
				},
				get all()
				{
					return _data;
				}
			});
		}();

		for(const name in dataStorage.all)
		{
			if(!keysInitialized[name])
			{
				API_init(name, dataStorage.get(name));
			}
		}

		(function()
		{
			for(const event of ["onabort", "onafterprint", "onanimationcancel", "onanimationend", "onanimationiteration", "onappinstalled", "onauxclick", "onbeforeinstallprompt", "onbeforeprint", "onbeforeunload", "onblur", "onchange", "onclick", "onclose", "oncontextmenu", "ondblclick", "ondevicelight", "ondevicemotion", "ondeviceorientation", "ondeviceorientationabsolute", "ondeviceproximity", "ondragdrop", "onerror", "onfocus", "ongotpointercapture", "onhashchange", "oninput", "onkeydown", "onkeypress", "onkeyup", "onlanguagechange", "onload", "onloadend", "onloadstart", "onlostpointercapture", "onmousedown", "onmousemove", "onmouseout", "onmouseover", "onmouseup", "onmozbeforepaint", "onpaint", "onpointercancel", "onpointerdown", "onpointerenter", "onpointerleave", "onpointermove", "onpointerout", "onpointerover", "onpointerup", "onpopstate", "onrejectionhandled", "onreset", "onresize", "onscroll", "onselect", "onselectionchange", "onselectstart", "onstorage", "onsubmit", "ontouchcancel", "ontouchmove", "ontouchstart", "ontransitioncancel", "ontransitionend", "onunhandledrejection", "onunload", "onuserproximity", "onvrdisplayconnected", "onvrdisplaydisconnected", "onvrdisplaypresentchange"])
			{
				const funcs = [];

				if(window[event] !== undefined && window[event] !== null)
				{
					if(typeof window[event] === "function")
					{
						funcs.push(window[event]);
						console.warn(`${libName}: There was already a function in window.${event}. It has been included in the ${libName} event dispatcher's function list. It will still be called when window.${event} triggers.`);
					}
					else
					{
						console.warn(`${libName}: There was an event conflict with window.${event}. There was a non-function value in the event. It has been overwritten by the ${libName} event dispatcher.`);
					}
				}

				window[event] = function(e)
				{
					let result;
					funcs.forEach(function(f)
					{
						const fres = f(e);
						if(fres !== undefined)
						{
							result = fres;
						}
					});

					if(result !== undefined)
					{
						return result;
					}
				};

				Object.defineProperty(window, event,
				{
					set: function(f)
					{
						funcs.push(f);
					}
				});
			}

		})();

		window.onload = function()
		{
			windowLoaded = true;
		}
		//END SETUP

		//INTERNAL FUNCTIONS

		function generateElement(elementType)
		{
			const el = document.createElement(elementType);
			el.CrID = CrElementCount++;
			el.CrCleared = true;
			return el;
		}

		function clearElement(element)
		{
			if(!element.CrCleared)
			{
				const [...children] = element.childNodes;
				for(const child of children)
				{
					if(child.CrID !== undefined)
					{
						child.remove();
					}
				}
				element.CrCleared = true;
			}
		}

		function refreshElement(element)
		{
			updateDispatch(element, dataStorage.get(element.CrNameBind));
		}

		function refreshName(name)
		{
			for(const element of (nameBindings[name] || []))
			{
				updateDispatch(element, dataStorage.get(name));
			}
		}

		function updateDispatch(element, data)
		{
			clearElement(element);
			const defaultFunc = function()
			{
				if(data === undefined || data === null)
				{
					console.warn(`${libName}: The data bound to <${element.nodeName.toLowerCase()}> tag with id '${element.id}' is undefined.`);
					return;
				}
				else if(isHTMLElement(data))
				{
					element.appendChild(data);
				}
				else if(typeof data === "object")
				{
					const table = generateElement("table");
					updateDispatch(table, data);
					element.appendChild(table);
				}
				else
				{
					if(isTagOutBindable(element.nodeName))
					{
						element.value = data;
					}
					else
					{
						element.innerText = data;
					}
				}

			}

			function lists()
			{
				if(Array.isArray(data))
				{
					const fragment = document.createDocumentFragment();
					for(const item of data)
					{
						const li = generateElement("li");
						if(typeof item === "object")
						{
							updateDispatch(li, item);
						}
						else
						{
							li.innerText = item;
						}
						fragment.appendChild(li);
					}

					element.appendChild(fragment);
				}
				else
				{
					defaultFunc();
				}
			}

			function tables()
			{
				if(typeof data === "object")
				{
					let thead;
					let tbody;
					const theadFrag = document.createDocumentFragment();
					const tbodyFrag = document.createDocumentFragment();
					if(element.nodeName === "TABLE")
					{
						for(const child of element.childNodes)
						{
							if(child.nodeName === "THEAD")
							{
								thead = child;
							}
							else if(child.nodeName === "TBODY")
							{
								tbody = child;
							}
						}
					}

					if(Array.isArray(data))
					{
						const colNames = new Set();
						for(const item of data)
						{
							if(typeof item === "object" && !Array.isArray(item))
							{
								for(const key in item)
								{
									colNames.add(key);
								}
							}
						}

						const colNameArr = Array.from(colNames.values());

						if(colNames.size > 0)
						{
							const tr = generateElement("tr");
							for(const colName of colNameArr)
							{
								const th = generateElement("th");
								updateDispatch(th, colName);
								tr.appendChild(th);
							}
							theadFrag.appendChild(tr);
						}

						for(let i = 0; i < data.length; i++)
						{
							const arr = data[i];
							const tr = generateElement("tr");
							let attachRow = true;
							if(typeof arr === "object" && !Array.isArray(arr) && arr !== null)
							{
								let atLeastOneColumn = false;
								for(const colName of colNameArr)
								{
									const td = generateElement("td");
									if(arr[colName])
									{
										updateDispatch(td, arr[colName]);
										atLeastOneColumn = true;
									}
									tr.appendChild(td);
								}
								attachRow = atLeastOneColumn;
							}
							else if(arr !== undefined && arr !== null)
							{
								const inner = (Array.isArray(arr))?arr:[arr];
								for(const item of inner)
								{
									const td = generateElement("td");
									updateDispatch(td, item);
									tr.appendChild(td);
								}
							}
							else if(arr === null)
							{
								console.warn(`${libName}: Found null while building table from array [ ${data} ] at index ${i}.`);
							}
							else
							{
								console.warn(`${libName}: Found undefined while building table from array [ ${data} ] at index ${i}. This can be caused by forgetting a comma between an object and an array.`);
							}
							if(attachRow)
							{
								tbodyFrag.appendChild(tr);
							}
						}
					}
					else
					{
						updateDispatch(element, [data]);
					}

					if(!thead)
					{
						const fragment = document.createDocumentFragment();
						fragment.appendChild(theadFrag);
						fragment.appendChild(tbodyFrag);
						(tbody || element).appendChild(fragment);
					}
					else
					{
						thead.appendChild(theadFrag);
						(tbody || element).appendChild(tbodyFrag);
					}
				}
				else
				{
					defaultFunc();
				}
			};

			const functionMapping = {
				ol: lists,
				ul: lists,
				table: tables,
				tbody: tables,
				thead: tables,
				tfoot: tables
			};

			( functionMapping[element.nodeName.toLowerCase()] || defaultFunc )();
			element.CrCleared = false;
		}

		function isTagOutBindable(elementTag)
		{
			const elements = {
				input: true, textarea: true
			};
			return elements[elementTag.toLowerCase()];
		}

		function delayUntilWindowLoad(callback)
		{
			if(!windowLoaded)
			{
				window.onload = callback;
			}
			else
			{
				callback();
			}
		}

		function isHTMLElement(element)
		{
			let current = element.__proto__;
			while(current !== null)
			{
				if(current.toString() === "[object HTMLElement]")
				{
					return true;
				}
				current = current.__proto__;
			}
			return false;
		}

		//END INTERNAL FUNCTIONS

		//API FUNCTIONS

		function API_createElement(tagName, properties)
		{
			if(typeof tagName !== "string")
			{
				console.error(`${libName}: Type error. Invalid input for tagName. Must be a string.`);
				console.trace();
				return undefined;
			}
			if(typeof properties !== "object")
			{
				console.error(`${libName}: Type error. Invalid input for properties. Must be an object.`);
				console.trace();
				return undefined;
			}
			const el = document.createElement(tagName);
			for(const key in properties)
			{
				if(typeof properties[key] === "string")
				{
					el[key] = properties[key];
				}
				else if(typeof properties[key] === "object")
				{
					for(const inner in properties[key])
					{
						if(typeof properties[key][inner] === "string")
						{
							el[key][inner] = properties[key][inner];
						}
					}
				}
			}
			return el;
		}

		function API_template(dataKey, HTMLStringOrElement)
		{
			let str;
			if(typeof HTMLStringOrElement === "string")
			{
				str = HTMLStringOrElement;
			}
			else if(isHTMLElement(element))
			{
				str = element.outerHTML;
			}
			else
			{
				console.warn(`${libName}: Invalid template argument passed for the data key '${dataKey}'. It should be a string or html element.`);
			}
		}

		function API_eventListener(elementOrSelector, event, callback)
		{
			if(isHTMLElement(elementOrSelector))
			{
				elementOrSelector[event] = callback;
			}
			else
			{
				delayUntilWindowLoad(function(){ document.querySelector(elementOrSelector)[event] = callback; });
			}
		}

		function API_init(name, value)
		{
			if(!keysInitialized[name])
			{
				API_set(name, value);
			}
		}

		function API_set(name, value)
		{
			dataStorage.set(name, value);
			if(!keysInitialized[name])
			{
				keysInitialized[name]= true;
				Object.defineProperty(API.data, name,
				{
					set: function(value)
					{
						API_set(name, value);
					},
					get: function()
					{
						return API_get(name);
					}
				});
			}
			refreshName(name);
		}

		function API_get(name)
		{
			return dataStorage.get(name);
		}

		function API_bind(elementOrSelector, name)
		{
			const DOMelement = elementOrSelector;
			let DOMElementDirectRef = DOMelement;
			if(!isHTMLElement(DOMelement))
			{
				delayUntilWindowLoad(function()
				{
					DOMElementDirectRef = document.querySelector(DOMelement);
				});
			}
			if(name !== undefined)
			{
				delayUntilWindowLoad(function()
				{
					if(isTagOutBindable(DOMElementDirectRef.nodeName))
					{
						API_bind(DOMelement).out(name);
					}
				});

				return API_bind(DOMelement).in(name);
			}
			else
			{
				return{
					in: function(name)
					{
						delayUntilWindowLoad(function()
						{
							( nameBindings[name] || (nameBindings[name] = []) ).push(DOMElementDirectRef);
							DOMElementDirectRef.CrNameBind = name;
							refreshElement(DOMElementDirectRef);
						});
					},
					out: function(name)
					{
						delayUntilWindowLoad(function()
						{
							if(isTagOutBindable(DOMElementDirectRef.nodeName))
							{
								DOMElementDirectRef.oninput = function()
								{
									API_set(name, DOMElementDirectRef.value);
								}
								API_set(name, DOMElementDirectRef.value);
							}
							else
							{
								console.warn(`${libName}: out binding is not available for ${DOMelement} because it doesn't take user input.`);
							}
						});
						return API_bind;
					}
				}
			}
		}

		return Object.freeze(Object.assign(API, {
			init: API_init,
			set: API_set,
			get: API_get,
			bind: API_bind,
			eventListener: API_eventListener,
			createElement: API_createElement
		}));

	})();
})();<commit_msg>config object only uses empty strings or undefined<commit_after>const Crystalline = (function()
{
	"use strict";
	const libName = "Crystalline"
	const nameBindings = {};
	const keysInitialized = {};
	let CrElementCount = 0;
	let windowLoaded = false;
	const API = {
		data:{}
	};

	//TODO
	//How to handle objects
	//An object should make a table with keys as the column names and values as the cell values
	//An array of objects should therefore collect all keys and then fill in the cells with each object's value

	return (function()
	{
		//SETUP
		const dataStorage = function()
		{
			if(!sessionStorage._CrSession)
			{
				sessionStorage._CrSession = "{}";
			}
			const _data = JSON.parse(sessionStorage._CrSession);

			return Object.freeze(
			{
				set: function(name, value)
				{
					_data[name] = { value: value };
					_data[name].template = "";
					sessionStorage._CrSession = JSON.stringify(_data);
					if(Array.isArray(value))
					{
						value.push = function(pushedVal)
						{
							Array.prototype.push.call(value, pushedVal);
							API_set(name, value);
						}
					}
				},
				get: function(name, value)
				{
					return _data[name].value;
				},
				setTemplate: function(name, str)
				{
					_data[name].template = str;
				},
				get all()
				{
					return _data;
				}
			});
		}();

		for(const name in dataStorage.all)
		{
			if(!keysInitialized[name])
			{
				API_init(name, dataStorage.get(name));
			}
		}

		(function()
		{
			for(const event of ["onabort", "onafterprint", "onanimationcancel", "onanimationend", "onanimationiteration", "onappinstalled", "onauxclick", "onbeforeinstallprompt", "onbeforeprint", "onbeforeunload", "onblur", "onchange", "onclick", "onclose", "oncontextmenu", "ondblclick", "ondevicelight", "ondevicemotion", "ondeviceorientation", "ondeviceorientationabsolute", "ondeviceproximity", "ondragdrop", "onerror", "onfocus", "ongotpointercapture", "onhashchange", "oninput", "onkeydown", "onkeypress", "onkeyup", "onlanguagechange", "onload", "onloadend", "onloadstart", "onlostpointercapture", "onmousedown", "onmousemove", "onmouseout", "onmouseover", "onmouseup", "onmozbeforepaint", "onpaint", "onpointercancel", "onpointerdown", "onpointerenter", "onpointerleave", "onpointermove", "onpointerout", "onpointerover", "onpointerup", "onpopstate", "onrejectionhandled", "onreset", "onresize", "onscroll", "onselect", "onselectionchange", "onselectstart", "onstorage", "onsubmit", "ontouchcancel", "ontouchmove", "ontouchstart", "ontransitioncancel", "ontransitionend", "onunhandledrejection", "onunload", "onuserproximity", "onvrdisplayconnected", "onvrdisplaydisconnected", "onvrdisplaypresentchange"])
			{
				const funcs = [];

				if(window[event] !== undefined && window[event] !== null)
				{
					if(typeof window[event] === "function")
					{
						funcs.push(window[event]);
						console.warn(`${libName}: There was already a function in window.${event}. It has been included in the ${libName} event dispatcher's function list. It will still be called when window.${event} triggers.`);
					}
					else
					{
						console.warn(`${libName}: There was an event conflict with window.${event}. There was a non-function value in the event. It has been overwritten by the ${libName} event dispatcher.`);
					}
				}

				window[event] = function(e)
				{
					let result;
					funcs.forEach(function(f)
					{
						const fres = f(e);
						if(fres !== undefined)
						{
							result = fres;
						}
					});

					if(result !== undefined)
					{
						return result;
					}
				};

				Object.defineProperty(window, event,
				{
					set: function(f)
					{
						funcs.push(f);
					}
				});
			}

		})();

		window.onload = function()
		{
			windowLoaded = true;
		}
		//END SETUP

		//INTERNAL FUNCTIONS

		function generateElement(elementType)
		{
			const el = document.createElement(elementType);
			el.CrID = CrElementCount++;
			el.CrCleared = true;
			return el;
		}

		function clearElement(element)
		{
			if(!element.CrCleared)
			{
				const [...children] = element.childNodes;
				for(const child of children)
				{
					if(child.CrID !== undefined)
					{
						child.remove();
					}
				}
				element.CrCleared = true;
			}
		}

		function refreshElement(element)
		{
			updateDispatch(element, dataStorage.get(element.CrNameBind));
		}

		function refreshName(name)
		{
			for(const element of (nameBindings[name] || []))
			{
				updateDispatch(element, dataStorage.get(name));
			}
		}

		function updateDispatch(element, data)
		{
			clearElement(element);
			const defaultFunc = function()
			{
				if(data === undefined || data === null)
				{
					console.warn(`${libName}: The data bound to <${element.nodeName.toLowerCase()}> tag with id '${element.id}' is undefined.`);
					return;
				}
				else if(isHTMLElement(data))
				{
					element.appendChild(data);
				}
				else if(typeof data === "object")
				{
					const table = generateElement("table");
					updateDispatch(table, data);
					element.appendChild(table);
				}
				else
				{
					if(isTagOutBindable(element.nodeName))
					{
						element.value = data;
					}
					else
					{
						element.innerText = data;
					}
				}

			}

			function lists()
			{
				if(Array.isArray(data))
				{
					const fragment = document.createDocumentFragment();
					for(const item of data)
					{
						const li = generateElement("li");
						if(typeof item === "object")
						{
							updateDispatch(li, item);
						}
						else
						{
							li.innerText = item;
						}
						fragment.appendChild(li);
					}

					element.appendChild(fragment);
				}
				else
				{
					defaultFunc();
				}
			}

			function tables()
			{
				if(typeof data === "object")
				{
					let thead;
					let tbody;
					const theadFrag = document.createDocumentFragment();
					const tbodyFrag = document.createDocumentFragment();
					if(element.nodeName === "TABLE")
					{
						for(const child of element.childNodes)
						{
							if(child.nodeName === "THEAD")
							{
								thead = child;
							}
							else if(child.nodeName === "TBODY")
							{
								tbody = child;
							}
						}
					}

					if(Array.isArray(data))
					{
						const colNames = new Set();
						for(const item of data)
						{
							if(typeof item === "object" && !Array.isArray(item))
							{
								for(const key in item)
								{
									colNames.add(key);
								}
							}
						}

						const colNameArr = Array.from(colNames.values());

						if(colNames.size > 0)
						{
							const tr = generateElement("tr");
							for(const colName of colNameArr)
							{
								const th = generateElement("th");
								updateDispatch(th, colName);
								tr.appendChild(th);
							}
							theadFrag.appendChild(tr);
						}

						for(let i = 0; i < data.length; i++)
						{
							const arr = data[i];
							const tr = generateElement("tr");
							let attachRow = true;
							if(typeof arr === "object" && !Array.isArray(arr) && arr !== null)
							{
								let atLeastOneColumn = false;
								for(const colName of colNameArr)
								{
									const td = generateElement("td");
									if(arr[colName] !== "" && arr[colName] !== undefined)
									{
										updateDispatch(td, arr[colName]);
										atLeastOneColumn = true;
									}
									tr.appendChild(td);
								}
								attachRow = atLeastOneColumn;
							}
							else if(arr !== undefined && arr !== null)
							{
								const inner = (Array.isArray(arr))?arr:[arr];
								for(const item of inner)
								{
									const td = generateElement("td");
									updateDispatch(td, item);
									tr.appendChild(td);
								}
							}
							else if(arr === null)
							{
								console.warn(`${libName}: Found null while building table from array [ ${data} ] at index ${i}.`);
							}
							else
							{
								console.warn(`${libName}: Found undefined while building table from array [ ${data} ] at index ${i}. This can be caused by forgetting a comma between an object and an array.`);
							}
							if(attachRow)
							{
								tbodyFrag.appendChild(tr);
							}
						}
					}
					else
					{
						updateDispatch(element, [data]);
					}

					if(!thead)
					{
						const fragment = document.createDocumentFragment();
						fragment.appendChild(theadFrag);
						fragment.appendChild(tbodyFrag);
						(tbody || element).appendChild(fragment);
					}
					else
					{
						thead.appendChild(theadFrag);
						(tbody || element).appendChild(tbodyFrag);
					}
				}
				else
				{
					defaultFunc();
				}
			};

			const functionMapping = {
				ol: lists,
				ul: lists,
				table: tables,
				tbody: tables,
				thead: tables,
				tfoot: tables
			};

			( functionMapping[element.nodeName.toLowerCase()] || defaultFunc )();
			element.CrCleared = false;
		}

		function isTagOutBindable(elementTag)
		{
			const elements = {
				input: true, textarea: true
			};
			return elements[elementTag.toLowerCase()];
		}

		function delayUntilWindowLoad(callback)
		{
			if(!windowLoaded)
			{
				window.onload = callback;
			}
			else
			{
				callback();
			}
		}

		function isHTMLElement(element)
		{
			let current = element.__proto__;
			while(current !== null)
			{
				if(current.toString() === "[object HTMLElement]")
				{
					return true;
				}
				current = current.__proto__;
			}
			return false;
		}

		//END INTERNAL FUNCTIONS

		//API FUNCTIONS

		function API_createElement(tagName, properties)
		{
			if(typeof tagName !== "string")
			{
				console.error(`${libName}: Type error. Invalid input for tagName. Must be a string.`);
				console.trace();
				return undefined;
			}
			if(typeof properties !== "object")
			{
				console.error(`${libName}: Type error. Invalid input for properties. Must be an object.`);
				console.trace();
				return undefined;
			}
			const el = document.createElement(tagName);
			for(const key in properties)
			{
				if(typeof properties[key] === "string")
				{
					el[key] = properties[key];
				}
				else if(typeof properties[key] === "object")
				{
					for(const inner in properties[key])
					{
						if(typeof properties[key][inner] === "string")
						{
							el[key][inner] = properties[key][inner];
						}
					}
				}
			}
			return el;
		}

		function API_template(dataKey, HTMLStringOrElement)
		{
			let str;
			if(typeof HTMLStringOrElement === "string")
			{
				str = HTMLStringOrElement;
			}
			else if(isHTMLElement(element))
			{
				str = element.outerHTML;
			}
			else
			{
				console.warn(`${libName}: Invalid template argument passed for the data key '${dataKey}'. It should be a string or html element.`);
			}
		}

		function API_eventListener(elementOrSelector, event, callback)
		{
			if(isHTMLElement(elementOrSelector))
			{
				elementOrSelector[event] = callback;
			}
			else
			{
				delayUntilWindowLoad(function(){ document.querySelector(elementOrSelector)[event] = callback; });
			}
		}

		function API_init(name, value)
		{
			if(!keysInitialized[name])
			{
				API_set(name, value);
			}
		}

		function API_set(name, value)
		{
			dataStorage.set(name, value);
			if(!keysInitialized[name])
			{
				keysInitialized[name]= true;
				Object.defineProperty(API.data, name,
				{
					set: function(value)
					{
						API_set(name, value);
					},
					get: function()
					{
						return API_get(name);
					}
				});
			}
			refreshName(name);
		}

		function API_get(name)
		{
			return dataStorage.get(name);
		}

		function API_bind(elementOrSelector, name)
		{
			const DOMelement = elementOrSelector;
			let DOMElementDirectRef = DOMelement;
			if(!isHTMLElement(DOMelement))
			{
				delayUntilWindowLoad(function()
				{
					DOMElementDirectRef = document.querySelector(DOMelement);
				});
			}
			if(name !== undefined)
			{
				delayUntilWindowLoad(function()
				{
					if(isTagOutBindable(DOMElementDirectRef.nodeName))
					{
						API_bind(DOMelement).out(name);
					}
				});

				return API_bind(DOMelement).in(name);
			}
			else
			{
				return{
					in: function(name)
					{
						delayUntilWindowLoad(function()
						{
							( nameBindings[name] || (nameBindings[name] = []) ).push(DOMElementDirectRef);
							DOMElementDirectRef.CrNameBind = name;
							refreshElement(DOMElementDirectRef);
						});
					},
					out: function(name)
					{
						delayUntilWindowLoad(function()
						{
							if(isTagOutBindable(DOMElementDirectRef.nodeName))
							{
								DOMElementDirectRef.oninput = function()
								{
									API_set(name, DOMElementDirectRef.value);
								}
								API_set(name, DOMElementDirectRef.value);
							}
							else
							{
								console.warn(`${libName}: out binding is not available for ${DOMelement} because it doesn't take user input.`);
							}
						});
						return API_bind;
					}
				}
			}
		}

		return Object.freeze(Object.assign(API, {
			init: API_init,
			set: API_set,
			get: API_get,
			bind: API_bind,
			eventListener: API_eventListener,
			createElement: API_createElement
		}));

	})();
})();<|endoftext|>