<commit_before>var chainMethods = 'select,from,where,orderBy,groupBy,having'.split(',');

buildFunctionalSQLPrototype();

var query = createQuery;

// return void(0);

function FunctionalSQL() {
	this.sources = [];
	this.selector = null;
	this.filters = [];
	this.groupBys = [];
	this.result = [];
}

function buildFunctionalSQLPrototype() {
	var proto = FunctionalSQL.prototype;

	proto.select = select;
	proto.doSelect = doSelect;

	proto.from = from;

	proto.where = where;
	proto.doFilter = doFilter;

	proto.orderBy = orderBy;

	proto.groupBy = groupBy;
	proto.doGroup = doGroup;

	proto.having = having;

	proto.execute = execute;

	chainMethods.forEach(function(methodName) {
		chinify(FunctionalSQL.prototype, methodName);
	});

	return void(0);

	function select(selector) {
		if(isFunction(selector)) {
			this.selector = selector;
		}
	}

	function doSelect() {
		if(this.selector) {
			this.result = this.result.map(this.selector);
		}
	}

	function from() {
		this.result =
			this.sources = argumentsToArray(arguments);
	}

	function where(filter) {
		if(isFunction(filter)) {
			this.filters.push(filter);
		}
	}

	function doFilter() {
		this.filters.forEach(function(filter) {
			this.result = this.result.filter(filter);
		}, this);
	}

	function orderBy() {}

	function groupBy(groupBy) {
		if(isFunction(groupBy)) {
			this.groupBys.push(groupBy);
		}
	}

	function doGroup() {
		this.result = group(this.result, this.groupBys);
	}

	function having() {}

	function execute() {
		this.doFilter();
		this.doGroup();
		this.doSelect();

		return this.result;
	}

}

function group(datas, groupBys) {
	if(groupBys.length < 1) {
		return datas;
	}

	var groupObjects = groupToGroupObjects(datas, groupBys);
	return convertToResult(groupObjects);
}

function convertToResult(groupObjects) {
	var container = new ConvertContainer();

	groupObjects.forEach(function(groupObject) {
		let currentContainer = container;

		groupObject.groups.forEach(function(group) {
			let nextContainer = currentContainer[group];
			if(!nextContainer) {
				nextContainer =
					currentContainer[group] = new ConvertContainer();

				currentContainer.result.push([group, nextContainer.result]);
			}
			currentContainer = nextContainer;
		});

		currentContainer.result.push(groupObject.data);
	});

	return container.result;
}

function ConvertContainer() {
	return {
		dic: createEmptyDic(),
		result: [],
	};
}

function groupToGroupObjects(datas, groupBys) {
	return datas.map(function(data) {
		var groupObject = new GroupObject(data);

		groupBys.forEach(function(groupBy) {
			groupObject.groups.push(groupBy(data));
		});

		return groupObject;
	});
}

function GroupObject(data) {
	this.data = data;
	this.groups = [];
}

function isFunction(fun) {
	return Object.prototype.toString.call(fun) === '[object Function]';
}

function createEmptyDic() {
	return Object.create(null);
}

function argumentsToArray(args) {
	return args.length === 1 ?
		args[0] :
		Array.prototype.slice.call(args);
}

function chinify(obj, methodName) {
	wrap.origin = obj[methodName];
	obj[methodName] = wrap;
	return void(0);

	function wrap() {
		wrap.origin.apply(this, arguments);
		return this;
	}
}

function createQuery() {
	return new FunctionalSQL();
}
<commit_msg>add createDuplicateCallErrorHandler<commit_after>var chainMethods = 'select,from,where,orderBy,groupBy,having'.split(',');

buildFunctionalSQLPrototype();

var query = createQuery;

// return void(0);

function FunctionalSQL() {
	this.sources = [];
	this.selector = null;
	this.filters = [];
	this.groupBys = [];
	this.result = [];
}

function buildFunctionalSQLPrototype() {
	var proto = FunctionalSQL.prototype;

	proto.select = select;
	proto.doSelect = doSelect;

	proto.from = from;

	proto.where = where;
	proto.doFilter = doFilter;

	proto.orderBy = orderBy;

	proto.groupBy = groupBy;
	proto.doGroup = doGroup;

	proto.having = having;

	proto.execute = execute;

	chainMethods.forEach(function(methodName) {
		chinify(FunctionalSQL.prototype, methodName);
	});

	return void(0);

	function select(selector) {
		if(isFunction(selector)) {
			this.selector = selector;
		}

		this.select = createDuplicateCallErrorHandler('SELECT');
	}

	function doSelect() {
		if(this.selector) {
			this.result = this.result.map(this.selector);
		}
	}

	function from() {
		this.result =
			this.sources = argumentsToArray(arguments);

		this.from = createDuplicateCallErrorHandler('FROM');
	}

	function where(filter) {
		if(isFunction(filter)) {
			this.filters.push(filter);
		}
	}

	function doFilter() {
		this.filters.forEach(function(filter) {
			this.result = this.result.filter(filter);
		}, this);
	}

	function orderBy() {
		this.orderBy = createDuplicateCallErrorHandler('ORDERBY');
	}

	function groupBy(groupBy) {
		if(isFunction(groupBy)) {
			this.groupBys.push(groupBy);
		}

		this.groupBy = createDuplicateCallErrorHandler('GROUPBY');
	}

	function doGroup() {
		this.result = group(this.result, this.groupBys);
	}

	function having() {}

	function execute() {
		this.doFilter();
		this.doGroup();
		this.doSelect();

		return this.result;
	}

	function createDuplicateCallErrorHandler(key) {
		return function() {
			throw new Error(key);
		}
	}
}

function group(datas, groupBys) {
	if(groupBys.length < 1) {
		return datas;
	}

	var groupObjects = groupToGroupObjects(datas, groupBys);
	return convertToResult(groupObjects);
}

function convertToResult(groupObjects) {
	var container = new ConvertContainer();

	groupObjects.forEach(function(groupObject) {
		let currentContainer = container;

		groupObject.groups.forEach(function(group) {
			let nextContainer = currentContainer[group];
			if(!nextContainer) {
				nextContainer =
					currentContainer[group] = new ConvertContainer();

				currentContainer.result.push([group, nextContainer.result]);
			}
			currentContainer = nextContainer;
		});

		currentContainer.result.push(groupObject.data);
	});

	return container.result;
}

function ConvertContainer() {
	return {
		dic: createEmptyDic(),
		result: [],
	};
}

function groupToGroupObjects(datas, groupBys) {
	return datas.map(function(data) {
		var groupObject = new GroupObject(data);

		groupBys.forEach(function(groupBy) {
			groupObject.groups.push(groupBy(data));
		});

		return groupObject;
	});
}

function GroupObject(data) {
	this.data = data;
	this.groups = [];
}

function isFunction(fun) {
	return Object.prototype.toString.call(fun) === '[object Function]';
}

function createEmptyDic() {
	return Object.create(null);
}

function argumentsToArray(args) {
	return args.length === 1 ?
		args[0] :
		Array.prototype.slice.call(args);
}

function chinify(obj, methodName) {
	wrap.origin = obj[methodName];
	obj[methodName] = wrap;
	return void(0);

	function wrap() {
		wrap.origin.apply(this, arguments);
		return this;
	}
}

function createQuery() {
	return new FunctionalSQL();
}
<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

// eslint-disable-next-line import/no-cycle
import { COLUMN_TYPES } from '../pages/dataTableUtilities';
import { UIDatabase, createRecord } from '../database';

const COLUMN_INDICATOR = {
  width: 1,
  sortable: false,
};

const COLUMN_INDICATOR_IMMUTABLE = {
  type: COLUMN_TYPES.STRING,
  editable: false,
  ...COLUMN_INDICATOR,
};

const COLUMN_INDICATOR_MUTABLE = {
  type: COLUMN_TYPES.EDITABLE_STRING,
  editable: true,
  ...COLUMN_INDICATOR,
};

const COLUMNS = {
  DESCRIPTION: {
    ...COLUMN_INDICATOR_IMMUTABLE,
    title: 'Description',
    key: 'description',
  },
  CODE: {
    ...COLUMN_INDICATOR_IMMUTABLE,
    title: 'Code',
    key: 'code',
  },
};

/**
 * Intialise a new indicator value.
 *
 * @param {IndicatorAttribute} row
 * @param {IndicatorAttribute} column
 * @param {Period} period
 */
const initialiseRowColumnValue = (row, column, period) => {
  UIDatabase.write(() => {
    createRecord(UIDatabase, 'IndicatorValue', row, column, period);
  });
};

const getIndicatorColumns = (indicator, code) =>
  indicator?.columns?.filter(({ description: columnCode }) => columnCode === code);

const getIndicatorRows = (indicator, code) =>
  indicator?.rows?.filter(({ id: rowCode }) => rowCode === code);

/**
 * Get value for indicator row, column tuple.
 *
 * @param {IndicatorAttribute} row
 * @param {IndicatorAttribute} column
 * @param {Period} period
 * @returns {IndicatorValue}
 */
const getIndicatorRowColumnValue = (row, column, period) => {
  const columnValues = column.values.filtered('period == $0', period);
  const rowValues = row.values.filter(({ period: valuePeriod }) => valuePeriod.ID === period.ID);
  const columnValueIds = columnValues?.map(({ id }) => id);
  const rowValueIds = rowValues?.map(({ id }) => id);
  const [rowColumnValueId] = columnValueIds?.filter(id => rowValueIds.includes(id)) || [];
  const rowColumnValue = column?.values?.find(({ id }) => id === rowColumnValueId);

  if (!rowColumnValue) {
    initialiseRowColumnValue(row, column, period);
    return getIndicatorRowColumnValue(row, column, period);
  }

  return rowColumnValue;
};

// eslint-disable-next-line no-unused-vars
const getIndicatorTableColumn = (columnCode, indicator, period) => {
  const [column] = indicator.columns.filter(({ code }) => code === columnCode);
  return {
    ...COLUMN_INDICATOR_MUTABLE,
    title: column.description,
    key: column.code,
  };
};

/**
 * Get indicator data table columns.
 *
 * @param {ProgramIndicator} indicator
 * @param {Period} period
 * @returns {Array.<object>}
 */
// eslint-disable-next-line no-unused-vars
const getIndicatorTableColumns = (indicator, period) => {
  const descriptionColumn = COLUMNS.DESCRIPTION;
  const codeColumn = COLUMNS.CODE;
  // eslint-disable-next-line no-unused-vars
  const valueColumns = indicator.columns.map(({ description, code }) => ({
    ...COLUMN_INDICATOR_MUTABLE,
    title: description,
    key: description,
  }));

  return [descriptionColumn, codeColumn, ...valueColumns];
};

const getIndicatorTableRow = (rowId, indicator, period) => {
  const [row] = indicator.rows.filter(({ id }) => id === rowId);
  const { description, code } = row;
  const values = indicator.columns.reduce((acc, column) => {
    const { description: key } = column;
    const value = getIndicatorRowColumnValue(row, column, period);
    return { ...acc, [key]: value.value };
  }, {});
  return { id: rowId, description, code, ...values };
};

/**
 * Get indicator data table rows.
 *
 * @param {ProgramIndicator} indicator
 * @param {Period} period
 * @returns {Array.<object>}
 */
const getIndicatorTableRows = (indicator, period) =>
  indicator.rows.map(({ id }) => getIndicatorTableRow(id, indicator, period));

/**
 * Get indicator data table rows and columns.
 *
 * @param {ProgramIndicator} indicator
 * @param {Period} period
 * @returns {object}
 */
const getIndicatorTableData = (indicator, period) => {
  const columns = getIndicatorTableColumns(indicator, period);
  const rows = getIndicatorTableRows(indicator, period);
  return { columns, rows };
};

export {
  getIndicatorRows,
  getIndicatorColumns,
  getIndicatorTableRow,
  getIndicatorTableRows,
  getIndicatorRowColumnValue,
  getIndicatorTableData,
};
<commit_msg>Update getIndicatorTableColumns helper<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

// eslint-disable-next-line import/no-cycle
import { COLUMN_TYPES } from '../pages/dataTableUtilities';
import { UIDatabase, createRecord } from '../database';

const COLUMN_INDICATOR = {
  width: 1,
  sortable: false,
};

const COLUMN_INDICATOR_IMMUTABLE = {
  type: COLUMN_TYPES.STRING,
  editable: false,
  ...COLUMN_INDICATOR,
};

const COLUMN_INDICATOR_MUTABLE = {
  type: COLUMN_TYPES.EDITABLE_STRING,
  editable: true,
  ...COLUMN_INDICATOR,
};

const COLUMNS = {
  DESCRIPTION: {
    ...COLUMN_INDICATOR_IMMUTABLE,
    title: 'Description',
    key: 'description',
  },
  CODE: {
    ...COLUMN_INDICATOR_IMMUTABLE,
    title: 'Code',
    key: 'code',
  },
};

/**
 * Intialise a new indicator value.
 *
 * @param {IndicatorAttribute} row
 * @param {IndicatorAttribute} column
 * @param {Period} period
 */
const initialiseRowColumnValue = (row, column, period) => {
  UIDatabase.write(() => {
    createRecord(UIDatabase, 'IndicatorValue', row, column, period);
  });
};

const getIndicatorColumns = (indicator, code) =>
  indicator?.columns?.filter(({ description: columnCode }) => columnCode === code);

const getIndicatorRows = (indicator, code) =>
  indicator?.rows?.filter(({ id: rowCode }) => rowCode === code);

/**
 * Get value for indicator row, column tuple.
 *
 * @param {IndicatorAttribute} row
 * @param {IndicatorAttribute} column
 * @param {Period} period
 * @returns {IndicatorValue}
 */
const getIndicatorRowColumnValue = (row, column, period) => {
  const columnValues = column.values.filtered('period == $0', period);
  const rowValues = row.values.filter(({ period: valuePeriod }) => valuePeriod.ID === period.ID);
  const columnValueIds = columnValues?.map(({ id }) => id);
  const rowValueIds = rowValues?.map(({ id }) => id);
  const [rowColumnValueId] = columnValueIds?.filter(id => rowValueIds.includes(id)) || [];
  const rowColumnValue = column?.values?.find(({ id }) => id === rowColumnValueId);

  if (!rowColumnValue) {
    initialiseRowColumnValue(row, column, period);
    return getIndicatorRowColumnValue(row, column, period);
  }

  return rowColumnValue;
};

// eslint-disable-next-line no-unused-vars
const getIndicatorTableColumn = (columnCode, indicator, period) => {
  const [column] = indicator.columns.filter(({ code }) => code === columnCode);
  return {
    ...COLUMN_INDICATOR_MUTABLE,
    title: column.description,
    key: column.code,
  };
};

/**
 * Get indicator data table columns.
 *
 * @param {ProgramIndicator} indicator
 * @param {Period} period
 * @returns {Array.<object>}
 */
// eslint-disable-next-line no-unused-vars
const getIndicatorTableColumns = (indicator, period) => {
  if (!indicator) return [];

  const descriptionColumn = COLUMNS.DESCRIPTION;
  const codeColumn = COLUMNS.CODE;
  // eslint-disable-next-line no-unused-vars
  const valueColumns = indicator.columns.map(({ code }) =>
    getIndicatorTableColumn(code, indicator, period)
  );

  return [descriptionColumn, codeColumn, ...valueColumns];
};

const getIndicatorTableRow = (rowId, indicator, period) => {
  const [row] = indicator.rows.filter(({ id }) => id === rowId);
  const { description, code } = row;
  const values = indicator.columns.reduce((acc, column) => {
    const { description: key } = column;
    const value = getIndicatorRowColumnValue(row, column, period);
    return { ...acc, [key]: value.value };
  }, {});
  return { id: rowId, description, code, ...values };
};

/**
 * Get indicator data table rows.
 *
 * @param {ProgramIndicator} indicator
 * @param {Period} period
 * @returns {Array.<object>}
 */
const getIndicatorTableRows = (indicator, period) =>
  indicator.rows.map(({ id }) => getIndicatorTableRow(id, indicator, period));

/**
 * Get indicator data table rows and columns.
 *
 * @param {ProgramIndicator} indicator
 * @param {Period} period
 * @returns {object}
 */
const getIndicatorTableData = (indicator, period) => {
  const columns = getIndicatorTableColumns(indicator, period);
  const rows = getIndicatorTableRows(indicator, period);
  return { columns, rows };
};

export {
  getIndicatorRows,
  getIndicatorColumns,
  getIndicatorTableRow,
  getIndicatorTableRows,
  getIndicatorRowColumnValue,
  getIndicatorTableData,
};
<|endoftext|>


<commit_before>/* eslint-env browser */

'use strict'

var debug = require('debug')('httpsnippet')
var es = require('event-stream')
var MultiPartForm = require('form-data')
var qs = require('querystring')
var reducer = require('./helpers/reducer')
var targets = require('./targets')
var url = require('url')
var validate = require('har-validator/lib/async')

const { formDataIterator, isBlob } = require('./helpers/form-data.js')

// constructor
var HTTPSnippet = function (data) {
  var entries
  var self = this
  var input = Object.assign({}, data)

  // prep the main container
  self.requests = []

  // is it har?
  if (input.log && input.log.entries) {
    entries = input.log.entries
  } else {
    entries = [{
      request: input
    }]
  }

  entries.forEach(function (entry) {
    // add optional properties to make validation successful
    entry.request.httpVersion = entry.request.httpVersion || 'HTTP/1.1'
    entry.request.queryString = entry.request.queryString || []
    entry.request.headers = entry.request.headers || []
    entry.request.cookies = entry.request.cookies || []
    entry.request.postData = entry.request.postData || {}
    entry.request.postData.mimeType = entry.request.postData.mimeType || 'application/octet-stream'

    entry.request.bodySize = 0
    entry.request.headersSize = 0
    entry.request.postData.size = 0

    validate.request(entry.request, function (err, valid) {
      if (!valid) {
        throw err
      }

      self.requests.push(self.prepare(entry.request))
    })
  })
}

HTTPSnippet.prototype.prepare = function (request) {
  // construct utility properties
  request.queryObj = {}
  request.headersObj = {}
  request.cookiesObj = {}
  request.allHeaders = {}
  request.postData.jsonObj = false
  request.postData.paramsObj = false

  // construct query objects
  if (request.queryString && request.queryString.length) {
    debug('queryString found, constructing queryString pair map')

    request.queryObj = request.queryString.reduce(reducer, {})
  }

  // construct headers objects
  if (request.headers && request.headers.length) {
    // loweCase header keys
    request.headersObj = request.headers.reduce(function (headers, header) {
      headers[header.name.toLowerCase()] = header.value
      return headers
    }, {})
  }

  // construct headers objects
  if (request.cookies && request.cookies.length) {
    request.cookiesObj = request.cookies.reduceRight(function (cookies, cookie) {
      cookies[cookie.name] = cookie.value
      return cookies
    }, {})
  }

  // construct Cookie header
  var cookies = request.cookies.map(function (cookie) {
    return encodeURIComponent(cookie.name) + '=' + encodeURIComponent(cookie.value)
  })

  if (cookies.length) {
    request.allHeaders.cookie = cookies.join('; ')
  }

  switch (request.postData.mimeType) {
    case 'multipart/mixed':
    case 'multipart/related':
    case 'multipart/form-data':
    case 'multipart/alternative':
      // reset values
      request.postData.text = ''
      request.postData.mimeType = 'multipart/form-data'

      if (request.postData.params) {
        var form = new MultiPartForm()

        // The `form-data` module returns one of two things: a native FormData object, or its own polyfill. Since this
        // polyfill support the full API of the native FormData object, when this library is running in a browser
        // environment it'll fail on two things:
        //
        //  - The API for `form.append()` has three arguments and the third should only be present when the second is a
        //    Blob or USVString.
        //  - `FormData.pipe()` isn't a function.
        //
        // Since the native FormData object is iterable, we easily detect what version of `form-data` we're working
        // with here to allow `multipart/form-data` requests to be compiled under both browser and Node environments.
        //
        // This hack is pretty awful but it's the only way we can use this library in the browser as if we code this
        // against just the native FormData object, we can't polyfill that back into Node because Blob and File objects,
        // which something like `formdata-polyfill` requires, don't exist there.
        const isNativeFormData = (typeof form[Symbol.iterator] === 'function')

        // easter egg
        const boundary = '---011000010111000001101001'
        if (!isNativeFormData) {
          form._boundary = boundary
        }

        request.postData.params.forEach(function (param) {
          if (isNativeFormData) {
            if (isBlob(param.value)) {
              form.append(param.name, param.value || '', param.fileName || null)
            } else {
              form.append(param.name, param.value || '')
            }
          } else {
            form.append(param.name, param.value || '', {
              filename: param.fileName || null,
              contentType: param.contentType || null
            })
          }
        })

        if (isNativeFormData) {
          for (var data of formDataIterator(form, boundary)) {
            request.postData.text += data
          }
        } else {
          form.pipe(es.map(function (data, cb) {
            request.postData.text += data
          }))
        }

        request.postData.boundary = boundary
        request.headersObj['content-type'] = 'multipart/form-data; boundary=' + boundary
      }
      break

    case 'application/x-www-form-urlencoded':
      if (!request.postData.params) {
        request.postData.text = ''
      } else {
        request.postData.paramsObj = request.postData.params.reduce(reducer, {})

        // always overwrite
        request.postData.text = qs.stringify(request.postData.paramsObj)
      }
      break

    case 'text/json':
    case 'text/x-json':
    case 'application/json':
    case 'application/x-json':
      request.postData.mimeType = 'application/json'

      if (request.postData.text) {
        try {
          request.postData.jsonObj = JSON.parse(request.postData.text)
        } catch (e) {
          debug(e)

          // force back to text/plain
          // if headers have proper content-type value, then this should also work
          request.postData.mimeType = 'text/plain'
        }
      }
      break
  }

  // create allHeaders object
  request.allHeaders = Object.assign(request.allHeaders, request.headersObj)

  // deconstruct the uri
  request.uriObj = url.parse(request.url, true, true)

  // merge all possible queryString values
  request.queryObj = Object.assign(request.queryObj, request.uriObj.query)

  // reset uriObj values for a clean url
  request.uriObj.query = null
  request.uriObj.search = null
  request.uriObj.path = request.uriObj.pathname

  // keep the base url clean of queryString
  request.url = url.format(request.uriObj)

  // update the uri object
  request.uriObj.query = request.queryObj
  request.uriObj.search = qs.stringify(request.queryObj)

  if (request.uriObj.search) {
    request.uriObj.path = request.uriObj.pathname + '?' + request.uriObj.search
  }

  // construct a full url
  request.fullUrl = url.format(request.uriObj)

  return request
}

HTTPSnippet.prototype.convert = function (target, client, opts) {
  if (!opts && client) {
    opts = client
  }

  var func = this._matchTarget(target, client)

  if (func) {
    var results = this.requests.map(function (request) {
      return func(request, opts)
    })

    return results.length === 1 ? results[0] : results
  }

  return false
}

HTTPSnippet.prototype._matchTarget = function (target, client) {
  // does it exist?
  if (!targets.hasOwnProperty(target)) {
    return false
  }

  // shorthand
  if (typeof client === 'string' && typeof targets[target][client] === 'function') {
    return targets[target][client]
  }

  // default target
  return targets[target][targets[target].info.default]
}

// exports
module.exports = HTTPSnippet

module.exports.addTarget = function (target) {
  if (!('info' in target)) {
    throw new Error('The supplied custom target must contain an `info` object.')
  } else if (!('key' in target.info) || !('title' in target.info) || !('extname' in target.info) || !('default' in target.info)) {
    throw new Error('The supplied custom target must have an `info` object with a `key`, `title`, `extname`, and `default` property.')
  } else if (targets.hasOwnProperty(target.info.key)) {
    throw new Error('The supplied custom target already exists.')
  } else if (Object.keys(target).length === 1) {
    throw new Error('A custom target must have a client defined on it.')
  }

  targets[target.info.key] = target
}

module.exports.addTargetClient = function (target, client) {
  if (!targets.hasOwnProperty(target)) {
    throw new Error(`Sorry, but no ${target} target exists to add clients to.`)
  } else if (!('info' in client)) {
    throw new Error('The supplied custom target client must contain an `info` object.')
  } else if (!('key' in client.info) || !('title' in client.info)) {
    throw new Error('The supplied custom target client must have an `info` object with a `key` and `title` property.')
  }

  targets[target][client.info.key] = client
}

module.exports.availableTargets = function () {
  return Object.keys(targets).map(function (key) {
    var target = Object.assign({}, targets[key].info)
    var clients = Object.keys(targets[key])

      .filter(function (prop) {
        return !~['info', 'index'].indexOf(prop)
      })

      .map(function (client) {
        return targets[key][client].info
      })

    if (clients.length) {
      target.clients = clients
    }

    return target
  })
}

module.exports.extname = function (target) {
  return targets[target] ? targets[target].info.extname : ''
}
<commit_msg>docs: adjusting some incorrect comments<commit_after>/* eslint-env browser */

'use strict'

var debug = require('debug')('httpsnippet')
var es = require('event-stream')
var MultiPartForm = require('form-data')
var qs = require('querystring')
var reducer = require('./helpers/reducer')
var targets = require('./targets')
var url = require('url')
var validate = require('har-validator/lib/async')

const { formDataIterator, isBlob } = require('./helpers/form-data.js')

// constructor
var HTTPSnippet = function (data) {
  var entries
  var self = this
  var input = Object.assign({}, data)

  // prep the main container
  self.requests = []

  // is it har?
  if (input.log && input.log.entries) {
    entries = input.log.entries
  } else {
    entries = [{
      request: input
    }]
  }

  entries.forEach(function (entry) {
    // add optional properties to make validation successful
    entry.request.httpVersion = entry.request.httpVersion || 'HTTP/1.1'
    entry.request.queryString = entry.request.queryString || []
    entry.request.headers = entry.request.headers || []
    entry.request.cookies = entry.request.cookies || []
    entry.request.postData = entry.request.postData || {}
    entry.request.postData.mimeType = entry.request.postData.mimeType || 'application/octet-stream'

    entry.request.bodySize = 0
    entry.request.headersSize = 0
    entry.request.postData.size = 0

    validate.request(entry.request, function (err, valid) {
      if (!valid) {
        throw err
      }

      self.requests.push(self.prepare(entry.request))
    })
  })
}

HTTPSnippet.prototype.prepare = function (request) {
  // construct utility properties
  request.queryObj = {}
  request.headersObj = {}
  request.cookiesObj = {}
  request.allHeaders = {}
  request.postData.jsonObj = false
  request.postData.paramsObj = false

  // construct query objects
  if (request.queryString && request.queryString.length) {
    debug('queryString found, constructing queryString pair map')

    request.queryObj = request.queryString.reduce(reducer, {})
  }

  // construct headers objects
  if (request.headers && request.headers.length) {
    // loweCase header keys
    request.headersObj = request.headers.reduce(function (headers, header) {
      headers[header.name.toLowerCase()] = header.value
      return headers
    }, {})
  }

  // construct headers objects
  if (request.cookies && request.cookies.length) {
    request.cookiesObj = request.cookies.reduceRight(function (cookies, cookie) {
      cookies[cookie.name] = cookie.value
      return cookies
    }, {})
  }

  // construct Cookie header
  var cookies = request.cookies.map(function (cookie) {
    return encodeURIComponent(cookie.name) + '=' + encodeURIComponent(cookie.value)
  })

  if (cookies.length) {
    request.allHeaders.cookie = cookies.join('; ')
  }

  switch (request.postData.mimeType) {
    case 'multipart/mixed':
    case 'multipart/related':
    case 'multipart/form-data':
    case 'multipart/alternative':
      // reset values
      request.postData.text = ''
      request.postData.mimeType = 'multipart/form-data'

      if (request.postData.params) {
        var form = new MultiPartForm()

        // The `form-data` module returns one of two things: a native FormData object, or its own polyfill. Since the
        // polyfill does not support the full API of the native FormData object, when this library is running in a
        // browser environment it'll fail on two things:
        //
        //  - The API for `form.append()` has three arguments and the third should only be present when the second is a
        //    Blob or USVString.
        //  - `FormData.pipe()` isn't a function.
        //
        // Since the native FormData object is iterable, we easily detect what version of `form-data` we're working
        // with here to allow `multipart/form-data` requests to be compiled under both browser and Node environments.
        //
        // This hack is pretty awful but it's the only way we can use this library in the browser as if we code this
        // against just the native FormData object, we can't polyfill that back into Node because Blob and File objects,
        // which something like `formdata-polyfill` requires, don't exist there.
        const isNativeFormData = (typeof form[Symbol.iterator] === 'function')

        // easter egg
        const boundary = '---011000010111000001101001'
        if (!isNativeFormData) {
          form._boundary = boundary
        }

        request.postData.params.forEach(function (param) {
          if (isNativeFormData) {
            if (isBlob(param.value)) {
              form.append(param.name, param.value || '', param.fileName || null)
            } else {
              form.append(param.name, param.value || '')
            }
          } else {
            form.append(param.name, param.value || '', {
              filename: param.fileName || null,
              contentType: param.contentType || null
            })
          }
        })

        if (isNativeFormData) {
          for (var data of formDataIterator(form, boundary)) {
            request.postData.text += data
          }
        } else {
          form.pipe(es.map(function (data, cb) {
            request.postData.text += data
          }))
        }

        request.postData.boundary = boundary
        request.headersObj['content-type'] = 'multipart/form-data; boundary=' + boundary
      }
      break

    case 'application/x-www-form-urlencoded':
      if (!request.postData.params) {
        request.postData.text = ''
      } else {
        request.postData.paramsObj = request.postData.params.reduce(reducer, {})

        // always overwrite
        request.postData.text = qs.stringify(request.postData.paramsObj)
      }
      break

    case 'text/json':
    case 'text/x-json':
    case 'application/json':
    case 'application/x-json':
      request.postData.mimeType = 'application/json'

      if (request.postData.text) {
        try {
          request.postData.jsonObj = JSON.parse(request.postData.text)
        } catch (e) {
          debug(e)

          // force back to text/plain
          // if headers have proper content-type value, then this should also work
          request.postData.mimeType = 'text/plain'
        }
      }
      break
  }

  // create allHeaders object
  request.allHeaders = Object.assign(request.allHeaders, request.headersObj)

  // deconstruct the uri
  request.uriObj = url.parse(request.url, true, true)

  // merge all possible queryString values
  request.queryObj = Object.assign(request.queryObj, request.uriObj.query)

  // reset uriObj values for a clean url
  request.uriObj.query = null
  request.uriObj.search = null
  request.uriObj.path = request.uriObj.pathname

  // keep the base url clean of queryString
  request.url = url.format(request.uriObj)

  // update the uri object
  request.uriObj.query = request.queryObj
  request.uriObj.search = qs.stringify(request.queryObj)

  if (request.uriObj.search) {
    request.uriObj.path = request.uriObj.pathname + '?' + request.uriObj.search
  }

  // construct a full url
  request.fullUrl = url.format(request.uriObj)

  return request
}

HTTPSnippet.prototype.convert = function (target, client, opts) {
  if (!opts && client) {
    opts = client
  }

  var func = this._matchTarget(target, client)

  if (func) {
    var results = this.requests.map(function (request) {
      return func(request, opts)
    })

    return results.length === 1 ? results[0] : results
  }

  return false
}

HTTPSnippet.prototype._matchTarget = function (target, client) {
  // does it exist?
  if (!targets.hasOwnProperty(target)) {
    return false
  }

  // shorthand
  if (typeof client === 'string' && typeof targets[target][client] === 'function') {
    return targets[target][client]
  }

  // default target
  return targets[target][targets[target].info.default]
}

// exports
module.exports = HTTPSnippet

module.exports.addTarget = function (target) {
  if (!('info' in target)) {
    throw new Error('The supplied custom target must contain an `info` object.')
  } else if (!('key' in target.info) || !('title' in target.info) || !('extname' in target.info) || !('default' in target.info)) {
    throw new Error('The supplied custom target must have an `info` object with a `key`, `title`, `extname`, and `default` property.')
  } else if (targets.hasOwnProperty(target.info.key)) {
    throw new Error('The supplied custom target already exists.')
  } else if (Object.keys(target).length === 1) {
    throw new Error('A custom target must have a client defined on it.')
  }

  targets[target.info.key] = target
}

module.exports.addTargetClient = function (target, client) {
  if (!targets.hasOwnProperty(target)) {
    throw new Error(`Sorry, but no ${target} target exists to add clients to.`)
  } else if (!('info' in client)) {
    throw new Error('The supplied custom target client must contain an `info` object.')
  } else if (!('key' in client.info) || !('title' in client.info)) {
    throw new Error('The supplied custom target client must have an `info` object with a `key` and `title` property.')
  }

  targets[target][client.info.key] = client
}

module.exports.availableTargets = function () {
  return Object.keys(targets).map(function (key) {
    var target = Object.assign({}, targets[key].info)
    var clients = Object.keys(targets[key])

      .filter(function (prop) {
        return !~['info', 'index'].indexOf(prop)
      })

      .map(function (client) {
        return targets[key][client].info
      })

    if (clients.length) {
      target.clients = clients
    }

    return target
  })
}

module.exports.extname = function (target) {
  return targets[target] ? targets[target].info.extname : ''
}
<|endoftext|>


<commit_before>'use strict';

var EntitySchema = require('./EntitySchema'),
    ArraySchema = require('./ArraySchema'),
    isObject = require('lodash/lang/isObject'),
    isEqual = require('lodash/lang/isEqual');

function visitObject(obj, schema, bag, assignEntity) {
  var normalized = {};

  for (var prop in obj) {
    if (obj.hasOwnProperty(prop)) {
      var entity = visit(obj[prop], schema[prop], bag);
      assignEntity(normalized, prop, entity);
    }
  }

  return normalized;
}

function visitArray(obj, arraySchema, bag) {
  var itemSchema = arraySchema.getItemSchema(),
      normalized;

  normalized = obj.map(function (childObj) {
    return visit(childObj, itemSchema, bag);
  });

  return normalized;
}

function mergeIntoEntity(entityA, entityB, entityKey) {
  for (var prop in entityB) {
    if (!entityB.hasOwnProperty(prop)) {
      continue;
    }

    if (!entityA.hasOwnProperty(prop) || isEqual(entityA[prop], entityB[prop])) {
      entityA[prop] = entityB[prop];
      continue;
    }

    console.warn(
      'When merging two ' + entityKey + ', found shallowly unequal data in their "' + prop + '" values. Using the earlier value.',
      entityA[prop], entityB[prop]
    );
  }
}

function visitEntity(entity, entitySchema, bag) {
  var entityKey = entitySchema.getKey(),
      idAttribute = entitySchema.getIdAttribute(),
      id = entity[idAttribute],
      stored,
      normalized;

  if (!bag[entityKey]) {
    bag[entityKey] = {};
  }

  if (!bag[entityKey][id]) {
    bag[entityKey][id] = {};
  }

  stored = bag[entityKey][id];
  normalized = visitObject(entity, entitySchema, bag);

  mergeIntoEntity(stored, normalized, entityKey);

  return id;
}

function visit(obj, schema, bag, assignEntity) {
  if (!isObject(obj) || !isObject(schema)) {
    return obj;
  }

  if (schema instanceof EntitySchema) {
    return visitEntity(obj, schema, bag);
  } else if (schema instanceof ArraySchema) {
    return visitArray(obj, schema, bag);
  } else {
    return visitObject(obj, schema, bag, assignEntity);
  }
}

function normalize(obj, schema, assignEntity) {
  if (!isObject(obj) && !Array.isArray(obj)) {
    throw new Error('Normalize accepts an object or an array as its input.');
  }

  if (!isObject(schema) || Array.isArray(schema)) {
    throw new Error('Normalize accepts an object for schema.');
  }

  var bag = {},
      result = visit(obj, schema, bag, assignEntity);

  return {
    entities: bag,
    result: result
  };
}

function arrayOf(schema) {
  return new ArraySchema(schema);
}

module.exports = {
  Schema: EntitySchema,
  arrayOf: arrayOf,
  normalize: normalize
};
<commit_msg>add check for assignEntity<commit_after>'use strict';

var EntitySchema = require('./EntitySchema'),
    ArraySchema = require('./ArraySchema'),
    isObject = require('lodash/lang/isObject'),
    isEqual = require('lodash/lang/isEqual');

function visitObject(obj, schema, bag, assignEntity) {
  var normalized = {};

  for (var prop in obj) {
    if (obj.hasOwnProperty(prop)) {
      var entity = visit(obj[prop], schema[prop], bag);
      if (assignEntity)
        assignEntity(normalized, prop, entity);
      else
        normalized[prop] = entity;
    }
  }

  return normalized;
}

function visitArray(obj, arraySchema, bag) {
  var itemSchema = arraySchema.getItemSchema(),
      normalized;

  normalized = obj.map(function (childObj) {
    return visit(childObj, itemSchema, bag);
  });

  return normalized;
}

function mergeIntoEntity(entityA, entityB, entityKey) {
  for (var prop in entityB) {
    if (!entityB.hasOwnProperty(prop)) {
      continue;
    }

    if (!entityA.hasOwnProperty(prop) || isEqual(entityA[prop], entityB[prop])) {
      entityA[prop] = entityB[prop];
      continue;
    }

    console.warn(
      'When merging two ' + entityKey + ', found shallowly unequal data in their "' + prop + '" values. Using the earlier value.',
      entityA[prop], entityB[prop]
    );
  }
}

function visitEntity(entity, entitySchema, bag) {
  var entityKey = entitySchema.getKey(),
      idAttribute = entitySchema.getIdAttribute(),
      id = entity[idAttribute],
      stored,
      normalized;

  if (!bag[entityKey]) {
    bag[entityKey] = {};
  }

  if (!bag[entityKey][id]) {
    bag[entityKey][id] = {};
  }

  stored = bag[entityKey][id];
  normalized = visitObject(entity, entitySchema, bag);

  mergeIntoEntity(stored, normalized, entityKey);

  return id;
}

function visit(obj, schema, bag, assignEntity) {
  if (!isObject(obj) || !isObject(schema)) {
    return obj;
  }

  if (schema instanceof EntitySchema) {
    return visitEntity(obj, schema, bag);
  } else if (schema instanceof ArraySchema) {
    return visitArray(obj, schema, bag);
  } else {
    return visitObject(obj, schema, bag, assignEntity);
  }
}

function normalize(obj, schema, assignEntity) {
  if (!isObject(obj) && !Array.isArray(obj)) {
    throw new Error('Normalize accepts an object or an array as its input.');
  }

  if (!isObject(schema) || Array.isArray(schema)) {
    throw new Error('Normalize accepts an object for schema.');
  }

  var bag = {},
      result = visit(obj, schema, bag, assignEntity);

  return {
    entities: bag,
    result: result
  };
}

function arrayOf(schema) {
  return new ArraySchema(schema);
}

module.exports = {
  Schema: EntitySchema,
  arrayOf: arrayOf,
  normalize: normalize
};
<|endoftext|>


<commit_before>import {
  connectState,
  registerGlobalActionCreators,
  registerReducer,
  registerReducers,
  getReducers
} from "./radux";
import stateFilters from "./state-filters";
import StateConnection from "./state-connection";
import Reducer from "./reducer";

export default {
  stateConnection,
  registerGlobalActionCreators,
  registereReducer,
  registerReducers,
  getReducers
};

export { Reducer, StateConnection, stateFilters };
<commit_msg>Fixed typo<commit_after>import {
  connectState,
  registerGlobalActionCreators,
  registerReducer,
  registerReducers,
  getReducers
} from "./radux";
import stateFilters from "./state-filters";
import StateConnection from "./state-connection";
import Reducer from "./reducer";

export default {
  stateConnection,
  registerGlobalActionCreators,
  registerReducer,
  registerReducers,
  getReducers
};

export { Reducer, StateConnection, stateFilters };
<|endoftext|>


<commit_before>import * as path from 'path';
import {childProcess, fs, promisify} from 'node-promise-es6';
import * as fse from 'fs-extra-promise-es6';
import {AwaitableObservable} from 'esnext-async';
import dedent from 'dedent';
import resolveModule from 'resolve';
import glob from 'glob';

export default class {
  constructor(basePath) {
    this.basePath = path.resolve(basePath);
  }

  contains(filePath) {
    return !path.relative(this.path(), this.path(filePath)).includes('..');
  }

  async create() {
    await fse.mkdirs(this.basePath);
  }

  async exec(command, params) {
    try {
      const {stdout} = await childProcess.execFile(command, params, {
        cwd: this.path()
      });
      return stdout.trim();
    } catch ({stderr}) {
      throw new Error(stderr.trim());
    }
  }

  execJs(code) {
    return new Promise((resolve, reject) => {
      const child = childProcess.spawn('dist-es6-run', {cwd: this.path()});
      child.stdin.write(code);
      child.stdin.end();

      let stdoutOutput = '';
      child.stdout.on('data', (output) => {
        stdoutOutput += output;
      });

      let stderrOutput = '';
      child.stderr.on('data', (output) => {
        stderrOutput += output;
      });

      child.on('close', (exitCode) => {
        if (exitCode === 0) {
          resolve(stdoutOutput.trim());
        } else {
          reject(stderrOutput.trim());
        }
      });
    });
  }

  async glob(pattern, options) {
    return await promisify(glob)(pattern, Object.assign({}, options, {
      cwd: this.path()
    }));
  }

  path(...components) {
    return path.resolve(this.basePath, ...components);
  }

  async read(filePath) {
    const contents = await fs.readFile(this.path(filePath), 'utf8');
    try {
      return JSON.parse(contents);
    } catch (error) {
      return contents;
    }
  }

  async remove(...pathComponents) {
    await fse.remove(this.path(...pathComponents));
  }

  async resolve(request) {
    return await new Promise((resolve, reject) => {
      resolveModule(request, {basedir: this.path()}, (error, result) => {
        if (error) {
          reject(error);
        } else {
          resolve(result);
        }
      });
    });
  }

  spawn(command, params) {
    const child = childProcess.spawn(command, params, {cwd: this.path()});
    const observable = new AwaitableObservable((observer) => {
      child.stdout.on('data', (data) => {
        observer.next(data.toString());
      });
      child.stderr.on('data', (data) => {
        observer.next(data.toString());
      });
    });
    observable.process = child;
    return observable;
  }

  async start(waitPattern = /^/) {
    this.server = this.spawn('sh', ['-c', 'npm start']);
    this.server.forEach((output) => {
      process.stderr.write(output);
    });
    await this.server.filter((output) => output.match(waitPattern));
  }

  async stat(filePath) {
    return await fs.stat(this.path(filePath));
  }

  async stop() {
    await new Promise((resolve) => {
      this.server.process.on('close', resolve);
      this.server.process.kill();
    });
  }

  async symlink(source, destination) {
    await fse.ensureSymlink(this.path(source), this.path(destination));
  }

  async write(files) {
    for (const [filePath, fileContents] of Object.entries(files)) {
      const absoluteFilePath = this.path(filePath);

      await fse.ensureFile(absoluteFilePath);

      if (typeof fileContents === 'object') {
        await fse.writeJson(absoluteFilePath, fileContents);
      } else {
        await fs.writeFile(absoluteFilePath, `${dedent(fileContents)}\n`);
      }
    }
  }
}
<commit_msg>Try killing by gid on travis<commit_after>import * as path from 'path';
import {childProcess, fs, promisify} from 'node-promise-es6';
import * as fse from 'fs-extra-promise-es6';
import {AwaitableObservable} from 'esnext-async';
import dedent from 'dedent';
import resolveModule from 'resolve';
import glob from 'glob';

export default class {
  constructor(basePath) {
    this.basePath = path.resolve(basePath);
  }

  contains(filePath) {
    return !path.relative(this.path(), this.path(filePath)).includes('..');
  }

  async create() {
    await fse.mkdirs(this.basePath);
  }

  async exec(command, params) {
    try {
      const {stdout} = await childProcess.execFile(command, params, {
        cwd: this.path()
      });
      return stdout.trim();
    } catch ({stderr}) {
      throw new Error(stderr.trim());
    }
  }

  execJs(code) {
    return new Promise((resolve, reject) => {
      const child = childProcess.spawn('dist-es6-run', {cwd: this.path()});
      child.stdin.write(code);
      child.stdin.end();

      let stdoutOutput = '';
      child.stdout.on('data', (output) => {
        stdoutOutput += output;
      });

      let stderrOutput = '';
      child.stderr.on('data', (output) => {
        stderrOutput += output;
      });

      child.on('close', (exitCode) => {
        if (exitCode === 0) {
          resolve(stdoutOutput.trim());
        } else {
          reject(stderrOutput.trim());
        }
      });
    });
  }

  async glob(pattern, options) {
    return await promisify(glob)(pattern, Object.assign({}, options, {
      cwd: this.path()
    }));
  }

  path(...components) {
    return path.resolve(this.basePath, ...components);
  }

  async read(filePath) {
    const contents = await fs.readFile(this.path(filePath), 'utf8');
    try {
      return JSON.parse(contents);
    } catch (error) {
      return contents;
    }
  }

  async remove(...pathComponents) {
    await fse.remove(this.path(...pathComponents));
  }

  async resolve(request) {
    return await new Promise((resolve, reject) => {
      resolveModule(request, {basedir: this.path()}, (error, result) => {
        if (error) {
          reject(error);
        } else {
          resolve(result);
        }
      });
    });
  }

  spawn(command, params) {
    const child = childProcess.spawn(command, params, {cwd: this.path()});
    const observable = new AwaitableObservable((observer) => {
      child.stdout.on('data', (data) => {
        observer.next(data.toString());
      });
      child.stderr.on('data', (data) => {
        observer.next(data.toString());
      });
    });
    observable.process = child;
    return observable;
  }

  async start(waitPattern = /^/) {
    this.server = this.spawn('sh', ['-c', 'npm start'], {detached: true});
    this.server.forEach((output) => {
      process.stderr.write(output);
    });
    await this.server.filter((output) => output.match(waitPattern));
  }

  async stat(filePath) {
    return await fs.stat(this.path(filePath));
  }

  async stop() {
    await new Promise((resolve) => {
      this.server.process.on('close', resolve);
      process.kill(-this.server.process.pid);
    });
  }

  async symlink(source, destination) {
    await fse.ensureSymlink(this.path(source), this.path(destination));
  }

  async write(files) {
    for (const [filePath, fileContents] of Object.entries(files)) {
      const absoluteFilePath = this.path(filePath);

      await fse.ensureFile(absoluteFilePath);

      if (typeof fileContents === 'object') {
        await fse.writeJson(absoluteFilePath, fileContents);
      } else {
        await fs.writeFile(absoluteFilePath, `${dedent(fileContents)}\n`);
      }
    }
  }
}
<|endoftext|>


<commit_before>import BaseModal from './BaseModal'
import CardModal from './CardModal'
import ImageModal from './ImageModal'
import Modal from './Modal'

export {
  BaseModal,
  CardModal,
  ImageModal,
  Modal,
}
<commit_msg>Modal<commit_after>import BaseModal from './BaseModal'
import CardModal from './CardModal'
import ImageModal from './ImageModal'
import Modal from './Modal'

export {
  BaseModal,
  CardModal,
  ImageModal,
  Modal
}
<|endoftext|>


<commit_before>/**
 * This software or document includes material copied from or derived from the
 * [JSON <=> URI selector converter](http://w3c.github.io/web-annotation/selector-note/converter/)
 * built for demoing the
 * [Selectors and States](http://w3c.github.io/web-annotation/selector-note/index-respec.html#media_selector)
 * Note. Copyright © 2017 W3C® (MIT, ERCIM, Keio, Beihang).
 **/

import Parser from './fragment.js'
import map from 'lodash.map'

function isSelector(selectorOrState) {
    return /Selector$/.test(selectorOrState.type)
}

function isState(selectorOrState) {
    return /State$/.test(selectorOrState.type)
}

export function uriToSpecificResource(the_uri) {
    var splitted = the_uri.split('#')
    var uri = splitted[0]
    var fragmentIdentifier = splitted[1]

    const specificResource = {
        source: uri,
    }
    if (fragmentIdentifier) {
        var selectorOrState = parse(fragmentIdentifier)
        if (isSelector(selectorOrState)) specificResource.selector = selectorOrState
        if (isState(selectorOrState)) specificResource.state = selectorOrState
    }
    return specificResource
}

export function specificResourceToUri(specificResource) {
    const uri = specificResource.source
    let fragmentIdentifier
    if ( specificResource.selector !== undefined ) {
        fragmentIdentifier = stringify(specificResource.selector)
    } else if ( specificResource.state !== undefined ) {
        fragmentIdentifier = stringify(specificResource.state)
    }
    return (uri || '') + (fragmentIdentifier ? '#' + fragmentIdentifier : '')
}

// Parse a fragment identifier, return a selector or state object.
export function parse(fragmentIdentifier) {
    const specificResource = Parser.parse(fragmentIdentifier)
    // The selector/state identity is discarded here. The object's type is
    // relied upon to convey this knowledge.
    const selectorOrState = specificResource.selector || specificResource.state
    return selectorOrState
}

// Turn a selector or state object into a fragment identifier.
export function stringify(selectorOrState) {
    function state_or_selector(selectorOrState) {
        // Deciding whether the object is a selector or a state...
        return (isState(selectorOrState)) ? 'state' : 'selector'
    }

    function encode_value( val ) {
        return encodeURI(val)
            .replace(/#/g,'%23')
            .replace(/,/g,'%2C')
            .replace(/=/g,'%3D')
            .replace(/%5B/gi,'[')
            .replace(/%5D/gi,']')
            .replace(/%3E/gi,'>')
            .replace(/%3C/gi,'<')
    }

    function frag(fname, selectorOrState) {
        function key_val(val, key) {
            // Create either a key=val string or, for some specific key values
            // calls recursively the fragment generator with that key.
            // The only mini-complication is that the 'function' name for the recursion should
            // be derived from the object (which is either a state for refinement, or a range selector)
            // The unusual order of the arguments is because the function is to be used in _.map, which imposes
            // this order
            if( key === 'refinedBy' || key === 'startSelector' || key === 'endSelector' ) {
                return key + '=' + frag(state_or_selector(val), val)
            } else {
                return key + '=' + encode_value(val)
            }
        }

        if( typeof(selectorOrState) === 'string' ) {
            // in practice: this is a uri
            return fname + '=' + encode_value(selectorOrState)
        } else {
            return fname + '(' + map(selectorOrState, key_val) + ')'
        }
    }

    if (isSelector(selectorOrState)) return frag('selector', selectorOrState)
    if (isState(selectorOrState)) return frag('state', selectorOrState)
}
<commit_msg>Handle other types of fragment identifiers.<commit_after>/**
 * This software or document includes material copied from or derived from the
 * [JSON <=> URI selector converter](http://w3c.github.io/web-annotation/selector-note/converter/)
 * built for demoing the
 * [Selectors and States](http://w3c.github.io/web-annotation/selector-note/index-respec.html#media_selector)
 * Note. Copyright © 2017 W3C® (MIT, ERCIM, Keio, Beihang).
 **/

import Parser from './fragment.js'
import map from 'lodash.map'

function isSelector(selectorOrState) {
    return /Selector$/.test(selectorOrState.type)
}

function isState(selectorOrState) {
    return /State$/.test(selectorOrState.type)
}

export function uriToSpecificResource(the_uri) {
    var splitted = the_uri.split('#')
    var uri = splitted[0]
    var fragmentIdentifier = splitted[1]

    const specificResource = {
        source: uri,
    }
    if (fragmentIdentifier) {
        try {
            var selectorOrState = parse(fragmentIdentifier)
            if (isSelector(selectorOrState)) specificResource.selector = selectorOrState
            if (isState(selectorOrState)) specificResource.state = selectorOrState
        } catch (err) {
            // Apparently, the fragment identifier was not a serialised selector or state object.
            // We convert the fragment identifier string to its equivalent selector object.
            // (https://www.w3.org/TR/2017/NOTE-selectors-states-20170223/#FragmentSelector_def)
            specificResource.selector = {
                type: 'FragmentSelector',
                value: fragmentIdentifier,
                // According to the spec, we _should_ specify a 'conformsTo' link, but we cannot
                // know the semantics of this fragmentIdentifier, so we have to omit this relation.
            }
        }
    }
    return specificResource
}

export function specificResourceToUri(specificResource) {
    const uri = specificResource.source
    let fragmentIdentifier
    if ( specificResource.selector !== undefined ) {
        fragmentIdentifier = stringify(specificResource.selector)
    } else if ( specificResource.state !== undefined ) {
        fragmentIdentifier = stringify(specificResource.state)
    }
    return (uri || '') + (fragmentIdentifier ? '#' + fragmentIdentifier : '')
}

// Parse a fragment identifier, return a selector or state object.
export function parse(fragmentIdentifier) {
    const specificResource = Parser.parse(fragmentIdentifier)
    // The selector/state identity is discarded here. The object's type is
    // relied upon to convey this knowledge.
    const selectorOrState = specificResource.selector || specificResource.state
    return selectorOrState
}

// Turn a selector or state object into a fragment identifier.
export function stringify(selectorOrState) {
    function state_or_selector(selectorOrState) {
        // Deciding whether the object is a selector or a state...
        return (isState(selectorOrState)) ? 'state' : 'selector'
    }

    function encode_value( val ) {
        return encodeURI(val)
            .replace(/#/g,'%23')
            .replace(/,/g,'%2C')
            .replace(/=/g,'%3D')
            .replace(/%5B/gi,'[')
            .replace(/%5D/gi,']')
            .replace(/%3E/gi,'>')
            .replace(/%3C/gi,'<')
    }

    function frag(fname, selectorOrState) {
        function key_val(val, key) {
            // Create either a key=val string or, for some specific key values
            // calls recursively the fragment generator with that key.
            // The only mini-complication is that the 'function' name for the recursion should
            // be derived from the object (which is either a state for refinement, or a range selector)
            // The unusual order of the arguments is because the function is to be used in _.map, which imposes
            // this order
            if( key === 'refinedBy' || key === 'startSelector' || key === 'endSelector' ) {
                return key + '=' + frag(state_or_selector(val), val)
            } else {
                return key + '=' + encode_value(val)
            }
        }

        if( typeof(selectorOrState) === 'string' ) {
            // in practice: this is a uri
            return fname + '=' + encode_value(selectorOrState)
        } else {
            return fname + '(' + map(selectorOrState, key_val) + ')'
        }
    }

    if (isSelector(selectorOrState)) return frag('selector', selectorOrState)
    if (isState(selectorOrState)) return frag('state', selectorOrState)
}
<|endoftext|>


<commit_before>/*
	LuCI - Lua Configuration Interface

	Copyright 2008 Steven Barth <steven@midlink.org>
	Copyright 2008-2009 Jo-Philipp Wich <xm@subsignal.org>

	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

	$Id$
*/

var cbi_d = [];
var cbi_t = [];
var cbi_c = [];

function cbi_d_add(field, dep, next) {
	var obj = document.getElementById(field);
	if (obj) {
		var entry
		for (var i=0; i<cbi_d.length; i++) {
			if (cbi_d[i].id == field) {
				entry = cbi_d[i];
				break;
			}
		}
		if (!entry) {
			entry = {
				"node": obj,
				"id": field,
				"parent": obj.parentNode.id,
				"next": next,
				"deps": []
			};
			cbi_d.unshift(entry);
		}
		entry.deps.push(dep)
	}
}

function cbi_d_checkvalue(target, ref) {
	var t = document.getElementById(target);
	var value;

	if (!t) {
		var tl = document.getElementsByName(target);

		if( tl.length > 0 && tl[0].type == 'radio' )
			for( var i = 0; i < tl.length; i++ )
				if( tl[i].checked ) {
					value = tl[i].value;
					break;
				}

		value = value ? value : "";
	} else if (!t.value) {
		value = "";
	} else {
		value = t.value;

		if (t.type == "checkbox") {
			value = t.checked ? value : "";
		}
	}

	return (value == ref)
}

function cbi_d_check(deps) {
	var reverse;
	var def = false;
	for (var i=0; i<deps.length; i++) {
		var istat = true;
		reverse = false;
		for (var j in deps[i]) {
			if (j == "!reverse") {
				reverse = true;
			} else if (j == "!default") {
				def = true;
				istat = false;
			} else {
				istat = (istat && cbi_d_checkvalue(j, deps[i][j]))
			}
		}
		if (istat) {
			return !reverse;
		}
	}
	return def;
}

function cbi_d_update() {
	var state = false;
	for (var i=0; i<cbi_d.length; i++) {
		var entry = cbi_d[i];
		var next  = document.getElementById(entry.next)
		var node  = document.getElementById(entry.id)
		var parent = document.getElementById(entry.parent)

		if (node && node.parentNode && !cbi_d_check(entry.deps)) {
			node.parentNode.removeChild(node);
			state = true;
			if( entry.parent )
				cbi_c[entry.parent]--;
		} else if ((!node || !node.parentNode) && cbi_d_check(entry.deps)) {
			if (!next) {
				parent.appendChild(entry.node);
			} else {
				next.parentNode.insertBefore(entry.node, next);
			}
			state = true;
			if( entry.parent )
				cbi_c[entry.parent]++;
		}
	}

	if (entry.parent) {
		cbi_t_update();
	}

	if (state) {
		cbi_d_update();
	}
}

function cbi_bind(obj, type, callback, mode) {
	if (typeof mode == "undefined") {
		mode = false;
	}
	if (!obj.addEventListener) {
		ieCallback = function(){
			var e = window.event;
			if (!e.target && e.srcElement) {
				e.target = e.srcElement;
			};
			e.target['_eCB' + type + callback] = callback;
			e.target['_eCB' + type + callback](e);
			e.target['_eCB' + type + callback] = null;
		};
		obj.attachEvent('on' + type, ieCallback);
	} else {
		obj.addEventListener(type, callback, mode);
	}
	return obj;
}

function cbi_combobox(id, values, def, man) {
	var selid = "cbi.combobox." + id;
	if (document.getElementById(selid)) {
		return
	}

	var obj = document.getElementById(id)
	var sel = document.createElement("select");
	sel.id = selid;
	sel.className = 'cbi-input-select';
	if (obj.nextSibling) {
		obj.parentNode.insertBefore(sel, obj.nextSibling);
	} else {
		obj.parentNode.appendChild(sel);
	}

	if (!values[obj.value]) {
		if (obj.value == "") {
			var optdef = document.createElement("option");
			optdef.value = "";
			optdef.appendChild(document.createTextNode(def));
			sel.appendChild(optdef);
		} else {
			var opt = document.createElement("option");
			opt.value = obj.value;
			opt.selected = "selected";
			opt.appendChild(document.createTextNode(obj.value));
			sel.appendChild(opt);
		}
	}

	for (var i in values) {
		var opt = document.createElement("option");
		opt.value = i;

		if (obj.value == i) {
			opt.selected = "selected";
		}

		opt.appendChild(document.createTextNode(values[i]));
		sel.appendChild(opt);
	}

	var optman = document.createElement("option");
	optman.value = "";
	optman.appendChild(document.createTextNode(man));
	sel.appendChild(optman);

	obj.style.display = "none";

	cbi_bind(sel, "change", function() {
		if (sel.selectedIndex == sel.options.length - 1) {
			obj.style.display = "inline";
			sel.parentNode.removeChild(sel);
			obj.focus();
		} else {
			obj.value = sel.options[sel.selectedIndex].value;
		}

		try {
			cbi_d_update();
		} catch (e) {
			//Do nothing
		}
	})
}

function cbi_combobox_init(id, values, def, man) {
	var obj = document.getElementById(id);
	cbi_bind(obj, "blur", function() {
		cbi_combobox(id, values, def, man)
	});
	cbi_combobox(id, values, def, man);
}

function cbi_filebrowser(id, url, defpath) {
	var field   = document.getElementById(id);
	var browser = window.open(
		url + ( field.value || defpath || '' ) + '?field=' + id,
		"luci_filebrowser", "width=300,height=400,left=100,top=200,scrollbars=yes"
	);

	browser.focus();
}

//Hijacks the CBI form to send via XHR (requires Prototype)
function cbi_hijack_forms(layer, win, fail, load) {
	var forms = layer.getElementsByTagName('form');
	for (var i=0; i<forms.length; i++) {
		$(forms[i]).observe('submit', function(event) {
			// Prevent the form from also submitting the regular way
			event.stop();

			// Submit via XHR
			event.element().request({
				onSuccess: win,
				onFailure: fail
			});

			if (load) {
				load();
			}
		});
	}
}

function cbi_t_add(section, tab) {
	var t = document.getElementById('tab.' + section + '.' + tab);
	var c = document.getElementById('container.' + section + '.' + tab);

	if( t && c ) {
		cbi_t[section] = (cbi_t[section] || [ ]);
		cbi_t[section][tab] = { 'tab': t, 'container': c, 'cid': c.id };
	}
}

function cbi_t_switch(section, tab) {
	if( cbi_t[section] && cbi_t[section][tab] ) {
		var o = cbi_t[section][tab];
		var h = document.getElementById('tab.' + section);
		for( var tid in cbi_t[section] ) {
			var o2 = cbi_t[section][tid];
			if( o.tab.id != o2.tab.id ) {
				o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab( |$)/, " cbi-tab-disabled ");
				o2.container.style.display = 'none';
			}
			else {
				if(h) h.value = tab;
				o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab-disabled( |$)/, " cbi-tab ");
				o2.container.style.display = 'block';
			}
		}
	}
	return false
}

function cbi_t_update() {
	for( var sid in cbi_t )
		for( var tid in cbi_t[sid] )
			if( cbi_c[cbi_t[sid][tid].cid] == 0 ) {
				cbi_t[sid][tid].tab.style.display = 'none';
			}
			else if( cbi_t[sid][tid].tab && cbi_t[sid][tid].tab.style.display == 'none' ) {
				cbi_t[sid][tid].tab.style.display = '';

				var t = cbi_t[sid][tid].tab;
				window.setTimeout(function() { t.className = t.className.replace(/ cbi-tab-highlighted/g, '') }, 750);
				cbi_t[sid][tid].tab.className += ' cbi-tab-highlighted';
			}
}

<commit_msg>libs/cbi: add datatype validators for upcoming client side field validation<commit_after>/*
	LuCI - Lua Configuration Interface

	Copyright 2008 Steven Barth <steven@midlink.org>
	Copyright 2008-2009 Jo-Philipp Wich <xm@subsignal.org>

	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

	$Id$
*/

var cbi_d = [];
var cbi_t = [];
var cbi_c = [];

var cbi_validators = {

	'integer': function(v)
	{
		return (v.match(/^-?[0-9]+$/) != null);
	},

	'uinteger': function(v)
	{
		return (cbi_validators.integer(v) && (v >= 0));
	},

	'ipaddr': function(v)
	{
		return cbi_validators.ip4addr(v) || cbi_validators.ip6addr(v);
	},

	'ip4addr': function(v)
	{
		if( v.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)(\/(\d+))?$/) )
		{
			return (RegExp.$1 >= 0) && (RegExp.$1 <= 255) &&
			       (RegExp.$2 >= 0) && (RegExp.$2 <= 255) &&
			       (RegExp.$3 >= 0) && (RegExp.$3 <= 255) &&
			       (RegExp.$4 >= 0) && (RegExp.$4 <= 255) &&
			       (!RegExp.$5 || ((RegExp.$6 >= 0) && (RegExp.$6 <= 32)))
			;
		}

		return false;
	},

	'ip6addr': function(v)
	{
		if( v.match(/^([a-fA-F0-9:.]+)(\/(\d+))?$/) )
		{
			if( !RegExp.$2 || ((RegExp.$3 >= 0) && (RegExp.$3 <= 128)) )
			{
				var addr = RegExp.$1;

				if( addr == '::' )
				{
					return true;
				}

				if( addr.indexOf('.') > 0 )
				{
					var off = addr.lastIndexOf(':');

					if( !(off && cbi_validators.ip4addr(addr.substr(off+1))) )
						return false;

					addr = addr.substr(0, off) + ':0:0';
				}

				if( addr.indexOf('::') < 0 )
				{
					return (addr.match(/^(?:[a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/) != null);
				}

				var fields = 0;

				for( var i = 0, last = 0, comp = false; i <= addr.length; i++ )
				{
					if( (addr.charAt(i) == ':') || (i == addr.length) )
					{
						if( (i == last) && !comp )
						{
							comp = true;
						}
						else
						{
							var f = addr.substring(last, i);
							if( !(f && f.match(/^[a-fA-F0-9]{1,4}$/)) )
								return false;
						}

						fields++;
						last = i + 1;
					}
				}

				return (fields == 8);
			}
		}

		return false;
	},

	'port': function(v)
	{
		return cbi_validators.integer(v) && (v >= 0) && (v <= 65535);
	},

	'portrange': function(v)
	{
		if( v.match(/^(\d+)-(\d+)$/) )
		{
			var p1 = RegExp.$1;
			var p2 = RegExp.$2;

			return cbi_validators.port(p1) &&
			       cbi_validators.port(p2) &&
			       (parseInt(p1) <= parseInt(p2))
			;
		}
		else
		{
			return cbi_validators.port(v);
		}
	},

	'macaddr': function(v)
	{
		return (v.match(/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/) != null);
	},

	'host': function(v)
	{
		return cbi_validators.hostname(v) || cbi_validators.ipaddr(v);
	},

	'hostname': function(v)
	{
		return (v.match(/^[a-zA-Z_][a-zA-Z0-9_\-.]*$/) != null);
	},

	'wpakey': function(v)
	{
		if( v.length == 64 )
			return (v.match(/^[a-fA-F0-9]{64}$/) != null);
		else
			return (v.length >= 8) && (v.length <= 63);
	},

	'wepkey': function(v)
	{
		if( v.substr(0,2) == 's:' )
			v = v.substr(2);

		if( (v.length == 10) || (v.length == 26) )
			return (v.match(/^[a-fA-F0-9]{10,26}$/) != null);
		else
			return (v.length == 5) || (v.length == 13);
	},

};

function cbi_d_add(field, dep, next) {
	var obj = document.getElementById(field);
	if (obj) {
		var entry
		for (var i=0; i<cbi_d.length; i++) {
			if (cbi_d[i].id == field) {
				entry = cbi_d[i];
				break;
			}
		}
		if (!entry) {
			entry = {
				"node": obj,
				"id": field,
				"parent": obj.parentNode.id,
				"next": next,
				"deps": []
			};
			cbi_d.unshift(entry);
		}
		entry.deps.push(dep)
	}
}

function cbi_d_checkvalue(target, ref) {
	var t = document.getElementById(target);
	var value;

	if (!t) {
		var tl = document.getElementsByName(target);

		if( tl.length > 0 && tl[0].type == 'radio' )
			for( var i = 0; i < tl.length; i++ )
				if( tl[i].checked ) {
					value = tl[i].value;
					break;
				}

		value = value ? value : "";
	} else if (!t.value) {
		value = "";
	} else {
		value = t.value;

		if (t.type == "checkbox") {
			value = t.checked ? value : "";
		}
	}

	return (value == ref)
}

function cbi_d_check(deps) {
	var reverse;
	var def = false;
	for (var i=0; i<deps.length; i++) {
		var istat = true;
		reverse = false;
		for (var j in deps[i]) {
			if (j == "!reverse") {
				reverse = true;
			} else if (j == "!default") {
				def = true;
				istat = false;
			} else {
				istat = (istat && cbi_d_checkvalue(j, deps[i][j]))
			}
		}
		if (istat) {
			return !reverse;
		}
	}
	return def;
}

function cbi_d_update() {
	var state = false;
	for (var i=0; i<cbi_d.length; i++) {
		var entry = cbi_d[i];
		var next  = document.getElementById(entry.next)
		var node  = document.getElementById(entry.id)
		var parent = document.getElementById(entry.parent)

		if (node && node.parentNode && !cbi_d_check(entry.deps)) {
			node.parentNode.removeChild(node);
			state = true;
			if( entry.parent )
				cbi_c[entry.parent]--;
		} else if ((!node || !node.parentNode) && cbi_d_check(entry.deps)) {
			if (!next) {
				parent.appendChild(entry.node);
			} else {
				next.parentNode.insertBefore(entry.node, next);
			}
			state = true;
			if( entry.parent )
				cbi_c[entry.parent]++;
		}
	}

	if (entry.parent) {
		cbi_t_update();
	}

	if (state) {
		cbi_d_update();
	}
}

function cbi_bind(obj, type, callback, mode) {
	if (typeof mode == "undefined") {
		mode = false;
	}
	if (!obj.addEventListener) {
		ieCallback = function(){
			var e = window.event;
			if (!e.target && e.srcElement) {
				e.target = e.srcElement;
			};
			e.target['_eCB' + type + callback] = callback;
			e.target['_eCB' + type + callback](e);
			e.target['_eCB' + type + callback] = null;
		};
		obj.attachEvent('on' + type, ieCallback);
	} else {
		obj.addEventListener(type, callback, mode);
	}
	return obj;
}

function cbi_combobox(id, values, def, man) {
	var selid = "cbi.combobox." + id;
	if (document.getElementById(selid)) {
		return
	}

	var obj = document.getElementById(id)
	var sel = document.createElement("select");
	sel.id = selid;
	sel.className = 'cbi-input-select';
	if (obj.nextSibling) {
		obj.parentNode.insertBefore(sel, obj.nextSibling);
	} else {
		obj.parentNode.appendChild(sel);
	}

	if (!values[obj.value]) {
		if (obj.value == "") {
			var optdef = document.createElement("option");
			optdef.value = "";
			optdef.appendChild(document.createTextNode(def));
			sel.appendChild(optdef);
		} else {
			var opt = document.createElement("option");
			opt.value = obj.value;
			opt.selected = "selected";
			opt.appendChild(document.createTextNode(obj.value));
			sel.appendChild(opt);
		}
	}

	for (var i in values) {
		var opt = document.createElement("option");
		opt.value = i;

		if (obj.value == i) {
			opt.selected = "selected";
		}

		opt.appendChild(document.createTextNode(values[i]));
		sel.appendChild(opt);
	}

	var optman = document.createElement("option");
	optman.value = "";
	optman.appendChild(document.createTextNode(man));
	sel.appendChild(optman);

	obj.style.display = "none";

	cbi_bind(sel, "change", function() {
		if (sel.selectedIndex == sel.options.length - 1) {
			obj.style.display = "inline";
			sel.parentNode.removeChild(sel);
			obj.focus();
		} else {
			obj.value = sel.options[sel.selectedIndex].value;
		}

		try {
			cbi_d_update();
		} catch (e) {
			//Do nothing
		}
	})
}

function cbi_combobox_init(id, values, def, man) {
	var obj = document.getElementById(id);
	cbi_bind(obj, "blur", function() {
		cbi_combobox(id, values, def, man)
	});
	cbi_combobox(id, values, def, man);
}

function cbi_filebrowser(id, url, defpath) {
	var field   = document.getElementById(id);
	var browser = window.open(
		url + ( field.value || defpath || '' ) + '?field=' + id,
		"luci_filebrowser", "width=300,height=400,left=100,top=200,scrollbars=yes"
	);

	browser.focus();
}

//Hijacks the CBI form to send via XHR (requires Prototype)
function cbi_hijack_forms(layer, win, fail, load) {
	var forms = layer.getElementsByTagName('form');
	for (var i=0; i<forms.length; i++) {
		$(forms[i]).observe('submit', function(event) {
			// Prevent the form from also submitting the regular way
			event.stop();

			// Submit via XHR
			event.element().request({
				onSuccess: win,
				onFailure: fail
			});

			if (load) {
				load();
			}
		});
	}
}

function cbi_t_add(section, tab) {
	var t = document.getElementById('tab.' + section + '.' + tab);
	var c = document.getElementById('container.' + section + '.' + tab);

	if( t && c ) {
		cbi_t[section] = (cbi_t[section] || [ ]);
		cbi_t[section][tab] = { 'tab': t, 'container': c, 'cid': c.id };
	}
}

function cbi_t_switch(section, tab) {
	if( cbi_t[section] && cbi_t[section][tab] ) {
		var o = cbi_t[section][tab];
		var h = document.getElementById('tab.' + section);
		for( var tid in cbi_t[section] ) {
			var o2 = cbi_t[section][tid];
			if( o.tab.id != o2.tab.id ) {
				o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab( |$)/, " cbi-tab-disabled ");
				o2.container.style.display = 'none';
			}
			else {
				if(h) h.value = tab;
				o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab-disabled( |$)/, " cbi-tab ");
				o2.container.style.display = 'block';
			}
		}
	}
	return false
}

function cbi_t_update() {
	for( var sid in cbi_t )
		for( var tid in cbi_t[sid] )
			if( cbi_c[cbi_t[sid][tid].cid] == 0 ) {
				cbi_t[sid][tid].tab.style.display = 'none';
			}
			else if( cbi_t[sid][tid].tab && cbi_t[sid][tid].tab.style.display == 'none' ) {
				cbi_t[sid][tid].tab.style.display = '';

				var t = cbi_t[sid][tid].tab;
				window.setTimeout(function() { t.className = t.className.replace(/ cbi-tab-highlighted/g, '') }, 750);
				cbi_t[sid][tid].tab.className += ' cbi-tab-highlighted';
			}
}

<|endoftext|>


<commit_before>import React, {PropTypes, Component} from 'react'
import Pomodoro from 'containers/Pomodoro'
import CommonView from 'views/CommonView'

type Props = {

};
export class PomodoroView extends Component {
  props: Props;

  render () {
    return (
      <CommonView
        title="Pomodoro Timer"
        description="Simple apps that implement timers for Pomodoro technique"
        criteriaUrl="https://www.freecodecamp.com/challenges/build-a-pomodoro-clock"
        sourceCodeUrl="https://github.com/Vargentum/react-redux-apps/tree/pomodoro"
        Component={Pomodoro}
      />
    )
  }
}

export default PomodoroView
<commit_msg>correct link to github branch<commit_after>import React, {PropTypes, Component} from 'react'
import Pomodoro from 'containers/Pomodoro'
import CommonView from 'views/CommonView'

type Props = {

};
export class PomodoroView extends Component {
  props: Props;

  render () {
    return (
      <CommonView
        title="Pomodoro Timer"
        description="Simple apps that implement timers for Pomodoro technique"
        criteriaUrl="https://www.freecodecamp.com/challenges/build-a-pomodoro-clock"
        sourceCodeUrl="https://github.com/Vargentum/react-redux-apps/tree/new-pomodoro"
        Component={Pomodoro}
      />
    )
  }
}

export default PomodoroView
<|endoftext|>


<commit_before>// Store setTimeout reference so promise-polyfill will be unaffected by
// other code modifying setTimeout (like sinon.useFakeTimers())
var setTimeoutFunc = setTimeout;

function noop() {}

// Polyfill for Function.prototype.bind
function bind(fn, thisArg) {
  return function() {
    fn.apply(thisArg, arguments);
  };
}

function Promise(fn) {
  if (!(this instanceof Promise))
    throw new TypeError('Promises must be constructed via new');
  if (typeof fn !== 'function') throw new TypeError('not a function');
  this._state = 0;
  this._handled = false;
  this._value = undefined;
  this._deferreds = [];

  doResolve(fn, this);
}

function handle(self, deferred) {
  while (self._state === 3) {
    self = self._value;
  }
  if (self._state === 0) {
    self._deferreds.push(deferred);
    return;
  }
  self._handled = true;
  Promise._immediateFn(function() {
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
    if (cb === null) {
      (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
      return;
    }
    var ret;
    try {
      ret = cb(self._value);
    } catch (e) {
      reject(deferred.promise, e);
      return;
    }
    resolve(deferred.promise, ret);
  });
}

function resolve(self, newValue) {
  try {
    // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
    if (newValue === self)
      throw new TypeError('A promise cannot be resolved with itself.');
    if (
      newValue &&
      (typeof newValue === 'object' || typeof newValue === 'function')
    ) {
      var then = newValue.then;
      if (newValue instanceof Promise) {
        self._state = 3;
        self._value = newValue;
        finale(self);
        return;
      } else if (typeof then === 'function') {
        doResolve(bind(then, newValue), self);
        return;
      }
    }
    self._state = 1;
    self._value = newValue;
    finale(self);
  } catch (e) {
    reject(self, e);
  }
}

function reject(self, newValue) {
  self._state = 2;
  self._value = newValue;
  finale(self);
}

function finale(self) {
  if (self._state === 2 && self._deferreds.length === 0) {
    Promise._immediateFn(function() {
      if (!self._handled) {
        Promise._unhandledRejectionFn(self._value);
      }
    });
  }

  for (var i = 0, len = self._deferreds.length; i < len; i++) {
    handle(self, self._deferreds[i]);
  }
  self._deferreds = null;
}

function Handler(onFulfilled, onRejected, promise) {
  this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
  this.onRejected = typeof onRejected === 'function' ? onRejected : null;
  this.promise = promise;
}

/**
 * Take a potentially misbehaving resolver function and make sure
 * onFulfilled and onRejected are only called once.
 *
 * Makes no guarantees about asynchrony.
 */
function doResolve(fn, self) {
  var done = false;
  try {
    fn(
      function(value) {
        if (done) return;
        done = true;
        resolve(self, value);
      },
      function(reason) {
        if (done) return;
        done = true;
        reject(self, reason);
      }
    );
  } catch (ex) {
    if (done) return;
    done = true;
    reject(self, ex);
  }
}

Promise.prototype['catch'] = function(onRejected) {
  return this.then(null, onRejected);
};

Promise.prototype.then = function(onFulfilled, onRejected) {
  var prom = new this.constructor(noop);

  handle(this, new Handler(onFulfilled, onRejected, prom));
  return prom;
};

Promise.prototype['finally'] = function(callback) {
  if (typeof callback !== 'function') {
    return this;
  }
  var constructor = this.constructor;
  return this.then(
    function(value) {
      return constructor.resolve(callback()).then(function() {
        return value;
      });
    },
    function(reason) {
      return constructor.resolve(callback()).then(function() {
        return constructor.reject(reason);
      });
    }
  );
};

Promise.all = function(arr) {
  return new Promise(function(resolve, reject) {
    if (!arr || typeof arr.length === 'undefined')
      throw new TypeError('Promise.all accepts an array');
    var args = Array.prototype.slice.call(arr);
    if (args.length === 0) return resolve([]);
    var remaining = args.length;

    function res(i, val) {
      try {
        if (val && (typeof val === 'object' || typeof val === 'function')) {
          var then = val.then;
          if (typeof then === 'function') {
            then.call(
              val,
              function(val) {
                res(i, val);
              },
              reject
            );
            return;
          }
        }
        args[i] = val;
        if (--remaining === 0) {
          resolve(args);
        }
      } catch (ex) {
        reject(ex);
      }
    }

    for (var i = 0; i < args.length; i++) {
      res(i, args[i]);
    }
  });
};

Promise.resolve = function(value) {
  if (value && typeof value === 'object' && value.constructor === Promise) {
    return value;
  }

  return new Promise(function(resolve) {
    resolve(value);
  });
};

Promise.reject = function(value) {
  return new Promise(function(resolve, reject) {
    reject(value);
  });
};

Promise.race = function(values) {
  return new Promise(function(resolve, reject) {
    for (var i = 0, len = values.length; i < len; i++) {
      values[i].then(resolve, reject);
    }
  });
};

// Use polyfill for setImmediate for performance gains
Promise._immediateFn =
  (typeof setImmediate === 'function' &&
    function(fn) {
      setImmediate(fn);
    }) ||
  function(fn) {
    setTimeoutFunc(fn, 0);
  };

Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {
  if (typeof console !== 'undefined' && console) {
    console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
  }
};

export default Promise;
<commit_msg>Removed typecheck of callback<commit_after>// Store setTimeout reference so promise-polyfill will be unaffected by
// other code modifying setTimeout (like sinon.useFakeTimers())
var setTimeoutFunc = setTimeout;

function noop() {}

// Polyfill for Function.prototype.bind
function bind(fn, thisArg) {
  return function() {
    fn.apply(thisArg, arguments);
  };
}

function Promise(fn) {
  if (!(this instanceof Promise))
    throw new TypeError('Promises must be constructed via new');
  if (typeof fn !== 'function') throw new TypeError('not a function');
  this._state = 0;
  this._handled = false;
  this._value = undefined;
  this._deferreds = [];

  doResolve(fn, this);
}

function handle(self, deferred) {
  while (self._state === 3) {
    self = self._value;
  }
  if (self._state === 0) {
    self._deferreds.push(deferred);
    return;
  }
  self._handled = true;
  Promise._immediateFn(function() {
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
    if (cb === null) {
      (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
      return;
    }
    var ret;
    try {
      ret = cb(self._value);
    } catch (e) {
      reject(deferred.promise, e);
      return;
    }
    resolve(deferred.promise, ret);
  });
}

function resolve(self, newValue) {
  try {
    // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
    if (newValue === self)
      throw new TypeError('A promise cannot be resolved with itself.');
    if (
      newValue &&
      (typeof newValue === 'object' || typeof newValue === 'function')
    ) {
      var then = newValue.then;
      if (newValue instanceof Promise) {
        self._state = 3;
        self._value = newValue;
        finale(self);
        return;
      } else if (typeof then === 'function') {
        doResolve(bind(then, newValue), self);
        return;
      }
    }
    self._state = 1;
    self._value = newValue;
    finale(self);
  } catch (e) {
    reject(self, e);
  }
}

function reject(self, newValue) {
  self._state = 2;
  self._value = newValue;
  finale(self);
}

function finale(self) {
  if (self._state === 2 && self._deferreds.length === 0) {
    Promise._immediateFn(function() {
      if (!self._handled) {
        Promise._unhandledRejectionFn(self._value);
      }
    });
  }

  for (var i = 0, len = self._deferreds.length; i < len; i++) {
    handle(self, self._deferreds[i]);
  }
  self._deferreds = null;
}

function Handler(onFulfilled, onRejected, promise) {
  this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
  this.onRejected = typeof onRejected === 'function' ? onRejected : null;
  this.promise = promise;
}

/**
 * Take a potentially misbehaving resolver function and make sure
 * onFulfilled and onRejected are only called once.
 *
 * Makes no guarantees about asynchrony.
 */
function doResolve(fn, self) {
  var done = false;
  try {
    fn(
      function(value) {
        if (done) return;
        done = true;
        resolve(self, value);
      },
      function(reason) {
        if (done) return;
        done = true;
        reject(self, reason);
      }
    );
  } catch (ex) {
    if (done) return;
    done = true;
    reject(self, ex);
  }
}

Promise.prototype['catch'] = function(onRejected) {
  return this.then(null, onRejected);
};

Promise.prototype.then = function(onFulfilled, onRejected) {
  var prom = new this.constructor(noop);

  handle(this, new Handler(onFulfilled, onRejected, prom));
  return prom;
};

Promise.prototype['finally'] = function(callback) {
  var constructor = this.constructor;
  return this.then(
    function(value) {
      return constructor.resolve(callback()).then(function() {
        return value;
      });
    },
    function(reason) {
      return constructor.resolve(callback()).then(function() {
        return constructor.reject(reason);
      });
    }
  );
};

Promise.all = function(arr) {
  return new Promise(function(resolve, reject) {
    if (!arr || typeof arr.length === 'undefined')
      throw new TypeError('Promise.all accepts an array');
    var args = Array.prototype.slice.call(arr);
    if (args.length === 0) return resolve([]);
    var remaining = args.length;

    function res(i, val) {
      try {
        if (val && (typeof val === 'object' || typeof val === 'function')) {
          var then = val.then;
          if (typeof then === 'function') {
            then.call(
              val,
              function(val) {
                res(i, val);
              },
              reject
            );
            return;
          }
        }
        args[i] = val;
        if (--remaining === 0) {
          resolve(args);
        }
      } catch (ex) {
        reject(ex);
      }
    }

    for (var i = 0; i < args.length; i++) {
      res(i, args[i]);
    }
  });
};

Promise.resolve = function(value) {
  if (value && typeof value === 'object' && value.constructor === Promise) {
    return value;
  }

  return new Promise(function(resolve) {
    resolve(value);
  });
};

Promise.reject = function(value) {
  return new Promise(function(resolve, reject) {
    reject(value);
  });
};

Promise.race = function(values) {
  return new Promise(function(resolve, reject) {
    for (var i = 0, len = values.length; i < len; i++) {
      values[i].then(resolve, reject);
    }
  });
};

// Use polyfill for setImmediate for performance gains
Promise._immediateFn =
  (typeof setImmediate === 'function' &&
    function(fn) {
      setImmediate(fn);
    }) ||
  function(fn) {
    setTimeoutFunc(fn, 0);
  };

Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {
  if (typeof console !== 'undefined' && console) {
    console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
  }
};

export default Promise;
<|endoftext|>


<commit_before>//TODO deal with update image assets without making children

include("assets/asset.js", true);
include("assets/imageasset.js", true);
include("assets/assetmanager.js", true);
include("timing/timer.js", true);

var floor = Math.floor;
var Vec = EN.Vector;
var Timer = EN.Timer;

function AnimationAsset(sFileName)
{
    //Super constructor
    this._Asset(sFileName);

    this.m_bLoaded = false;

    this.Renderable = true;

    this.CurrentFrame = 0;

    this.m_cAnimationInfo = {};
    this.m_aImages = [];

    this.m_sAnimation = "";
    this.m_cCurrentImage = null;
    this.m_cCurrentAnimation = null;
    this.m_nPreviousFramesElapsed = 0;
    this.m_bAnimationRunning = false;

    this.m_cOffset = new EN.Vector();

    var self = this;

    this.m_cOffset.OnChange(function(nNewX, nOldX, nNewY, nOldY){
        self.__OffsetChanged(nNewX, nNewY);
    });
};

inherits(AnimationAsset, EN.Asset);

Object.defineProperty(AnimationAsset.prototype, "Offset", {
    get: function(){
        return this.m_cOffset;
    },
    set: function(cOffset){
        this.m_cOffset.Set(cOffset);
    }
});

AnimationAsset.prototype.__OffsetChanged = function(x, y){
    if (this.m_cCurrentAnimation)
    {
        this.m_cCurrentImage.Pos.x = -this.m_cCurrentAnimation.width * x;
        this.m_cCurrentImage.Pos.y = -this.m_cCurrentAnimation.height * y;
    }
};

AnimationAsset.prototype.__SetFrame = function() {
    var nOffsetX = (this.CurrentFrame * this.m_cCurrentAnimation.width) % this.m_cCurrentAnimation.origWidth;
    var nOffsetY = floor((this.CurrentFrame * this.m_cCurrentAnimation.width) / this.m_cCurrentAnimation.origWidth) * this.m_cCurrentAnimation.height + this.m_cCurrentAnimation.rowOffset;

    this.m_cCurrentImage.Offset = new Vec(nOffsetX, nOffsetY);
};

AnimationAsset.prototype.Load = function(fOnLoad){
    var self = this;

    //TODO gen file name once
    EN.AssetManager.LoadFile("animations/" + this.m_sFileName + ".json", function(cErr, sSprite){
        if (!cErr)
        {
            var cSprite = JSON.parse(sSprite);

            self.m_aImages = [];

            for (var sAnimKey in cSprite.spriteSheets)
            {
                var cImage = new EN.ImageAsset(cSprite.spriteSheets[sAnimKey]);
                self.m_aImages.push(cImage);

                for (var sAnimation in cSprite.animations[sAnimKey])
                {
                    var cBaseInfo = extend({}, cSprite.baseInfo.base, cSprite.baseInfo[sAnimKey]);

                    self.m_cAnimationInfo[sAnimation] = extend({}, cBaseInfo, cSprite.animations[sAnimKey][sAnimation]);
                    self.m_cAnimationInfo[sAnimation].image = cImage;
                }
            }

            EN.Loader.Load([
                self.m_aImages
            ], function(){

                for (var sAnimation in self.m_cAnimationInfo)
                {
                    var cImage = self.m_cAnimationInfo[sAnimation].image;

                    self.m_cAnimationInfo[sAnimation].origWidth = cImage.Width;
                    self.m_cAnimationInfo[sAnimation].origHeight = cImage.Height;
                }

                self.m_bLoaded = true;
                fOnLoad();
            });
        }
        else
        {
            throw cErr;
        }
    });
};

AnimationAsset.prototype.Init = function(){
    this._Init_Asset();

    var self = this;

    this.m_aImages.forEach(function(cImage){
        cImage.Renderable = false;
        self.AddChild(cImage);
    });
};

AnimationAsset.prototype.Update = function(){
    this._Update_Asset();

    if (this.m_bAnimationRunning)
    {
        this.m_nPreviousFramesElapsed += Timer.DeltaTime / this.m_cCurrentAnimation.frameDelta;

        if (this.m_nPreviousFramesElapsed >= 1)
        {
            this.CurrentFrame = floor(this.CurrentFrame + this.m_nPreviousFramesElapsed) % this.m_cCurrentAnimation.frames;
            this.m_nPreviousFramesElapsed = this.m_nPreviousFramesElapsed - floor(this.m_nPreviousFramesElapsed);
        }

        this.__SetFrame();
    }
};

AnimationAsset.prototype.Draw = function(cRenderer){
    if (this.m_cCurrentAnimation)
    {
        cRenderer.DrawImage(this.m_cCurrentImage);
    }
};

AnimationAsset.prototype.ChangeAnimation = function(sAnimation){
    if (sAnimation != this.m_sAnimation && this.m_bLoaded)
    {
        this.m_sAnimation = sAnimation;

        this.CurrentFrame = 0;
        this.m_nPreviousFramesElapsed = 0;

        var cCurrentAnimation = this.m_cAnimationInfo[this.m_sAnimation];

        cCurrentAnimation.frameDelta = 1000 / cCurrentAnimation.fps;
        this.m_cCurrentAnimation = cCurrentAnimation;

        this.m_cCurrentImage = cCurrentAnimation.image;

        this.m_cCurrentImage.Width = this.m_cCurrentImage.ImageWidth = cCurrentAnimation.width;
        this.m_cCurrentImage.Height = this.m_cCurrentImage.ImageHeight = cCurrentAnimation.height;

        this.__OffsetChanged(this.m_cOffset.x, this.m_cOffset.y);
        this.__SetFrame();
    }
};

AnimationAsset.prototype.Reset = function(){
    this.CurrentFrame = 0;
    this.m_nPreviousFramesElapsed = 0;
};

AnimationAsset.prototype.Play = function(bPlay){
    this.m_bAnimationRunning = bPlay;
};

AnimationAsset.prototype.CleanUp = function(){
    this._CleanUp_Asset();
    EN.AssetManager.ReleaseFile("animations/" + this.m_sFileName + ".json");

    this.m_aImages.forEach(function(cImage){
        cImage.CleanUp();
    });
};

EN.AnimationAsset = AnimationAsset;
<commit_msg>added support for non looping anims<commit_after>//TODO deal with update image assets without making children

include("assets/asset.js", true);
include("assets/imageasset.js", true);
include("assets/assetmanager.js", true);
include("timing/timer.js", true);

var floor = Math.floor;

var Vec = EN.Vector;
var Timer = EN.Timer;

function AnimationAsset(sFileName)
{
    //Super constructor
    this._Asset(sFileName);

    this.m_bLoaded = false;

    this.Renderable = true;

    this.CurrentFrame = 0;

    this.m_cAnimationInfo = {};
    this.m_aImages = [];

    this.m_sAnimation = "";
    this.m_cCurrentImage = null;
    this.m_cCurrentAnimation = null;
    this.m_nPreviousFramesElapsed = 0;
    this.m_bAnimationRunning = false;

    this.m_cOffset = new EN.Vector();

    var self = this;

    this.m_cOffset.OnChange(function(nNewX, nOldX, nNewY, nOldY){
        self.__OffsetChanged(nNewX, nNewY);
    });
};

inherits(AnimationAsset, EN.Asset);

Object.defineProperty(AnimationAsset.prototype, "Offset", {
    get: function(){
        return this.m_cOffset;
    },
    set: function(cOffset){
        this.m_cOffset.Set(cOffset);
    }
});

Object.defineProperty(AnimationAsset.prototype, "CurrentAnim", {
    get: function(){
        return this.m_sAnimation;
    }
});

AnimationAsset.prototype.__OffsetChanged = function(x, y){
    if (this.m_cCurrentAnimation)
    {
        this.m_cCurrentImage.Pos.x = -this.m_cCurrentAnimation.width * x;
        this.m_cCurrentImage.Pos.y = -this.m_cCurrentAnimation.height * y;
    }
};

AnimationAsset.prototype.__SetFrame = function() {
    var nOffsetX = (this.CurrentFrame * this.m_cCurrentAnimation.width) % this.m_cCurrentAnimation.origWidth;
    var nOffsetY = floor((this.CurrentFrame * this.m_cCurrentAnimation.width) / this.m_cCurrentAnimation.origWidth) * this.m_cCurrentAnimation.height + this.m_cCurrentAnimation.rowOffset;

    this.m_cCurrentImage.Offset = new Vec(nOffsetX, nOffsetY);
};

AnimationAsset.prototype.Load = function(fOnLoad){
    var self = this;

    //TODO gen file name once
    EN.AssetManager.LoadFile("animations/" + this.m_sFileName + ".json", function(cErr, sSprite){
        if (!cErr)
        {
            var cSprite = JSON.parse(sSprite);

            self.m_aImages = [];

            for (var sAnimKey in cSprite.spriteSheets)
            {
                var cImage = new EN.ImageAsset(cSprite.spriteSheets[sAnimKey]);
                self.m_aImages.push(cImage);

                for (var sAnimation in cSprite.animations[sAnimKey])
                {
                    var cBaseInfo = extend({}, cSprite.baseInfo.base, cSprite.baseInfo[sAnimKey]);

                    self.m_cAnimationInfo[sAnimation] = extend({}, cBaseInfo, cSprite.animations[sAnimKey][sAnimation]);
                    self.m_cAnimationInfo[sAnimation].image = cImage;
                }
            }

            EN.Loader.Load([
                self.m_aImages
            ], function(){

                for (var sAnimation in self.m_cAnimationInfo)
                {
                    var cImage = self.m_cAnimationInfo[sAnimation].image;

                    self.m_cAnimationInfo[sAnimation].origWidth = cImage.Width;
                    self.m_cAnimationInfo[sAnimation].origHeight = cImage.Height;
                }

                self.m_bLoaded = true;
                fOnLoad();
            });
        }
        else
        {
            throw cErr;
        }
    });
};

AnimationAsset.prototype.Init = function(){
    this._Init_Asset();

    var self = this;

    this.m_aImages.forEach(function(cImage){
        cImage.Renderable = false;
        self.AddChild(cImage);
    });
};

AnimationAsset.prototype.Update = function(){
    this._Update_Asset();

    if (this.m_bAnimationRunning)
    {
        this.m_nPreviousFramesElapsed += Timer.DeltaTime / this.m_cCurrentAnimation.frameDelta;

        if (this.m_nPreviousFramesElapsed >= 1)
        {
            var nNextFrame = floor(this.CurrentFrame + this.m_nPreviousFramesElapsed) % this.m_cCurrentAnimation.frames;

            if (nNextFrame < this.CurrentFrame && !this.m_cCurrentAnimation.looping)
            {
                this.CurrentFrame = this.m_cCurrentAnimation.frames - 1;
                this.m_bAnimationRunning = false;
            }
            else
            {
                this.CurrentFrame = nNextFrame;
            }

            this.m_nPreviousFramesElapsed = this.m_nPreviousFramesElapsed - floor(this.m_nPreviousFramesElapsed);
        }

        this.__SetFrame();
    }
};

AnimationAsset.prototype.Draw = function(cRenderer){
    if (this.m_cCurrentAnimation)
    {
        cRenderer.DrawImage(this.m_cCurrentImage);
    }
};

AnimationAsset.prototype.ChangeAnimation = function(sAnimation){
    if (sAnimation != this.m_sAnimation && this.m_bLoaded)
    {
        this.m_sAnimation = sAnimation;

        this.CurrentFrame = 0;
        this.m_nPreviousFramesElapsed = 0;

        var cCurrentAnimation = this.m_cAnimationInfo[this.m_sAnimation];

        cCurrentAnimation.frameDelta = 1000 / cCurrentAnimation.fps;
        this.m_cCurrentAnimation = cCurrentAnimation;

        this.m_cCurrentImage = cCurrentAnimation.image;

        this.m_cCurrentImage.Width = this.m_cCurrentImage.ImageWidth = cCurrentAnimation.width;
        this.m_cCurrentImage.Height = this.m_cCurrentImage.ImageHeight = cCurrentAnimation.height;

        this.__OffsetChanged(this.m_cOffset.x, this.m_cOffset.y);
        this.__SetFrame();
    }
};

AnimationAsset.prototype.Reset = function(){
    this.CurrentFrame = 0;
    this.m_nPreviousFramesElapsed = 0;
};

AnimationAsset.prototype.Play = function(bPlay){
    if (this.IsFinished())
    {
        this.Reset();
    }

    this.m_bAnimationRunning = bPlay;
};

AnimationAsset.prototype.IsFinished = function(){
    return this.m_bAnimationRunning && this.CurrentFrame == (this.m_cCurrentAnimation.frames - 1);
};

AnimationAsset.prototype.CleanUp = function(){
    this._CleanUp_Asset();
    EN.AssetManager.ReleaseFile("animations/" + this.m_sFileName + ".json");

    this.m_aImages.forEach(function(cImage){
        cImage.CleanUp();
    });
};

EN.AnimationAsset = AnimationAsset;
<|endoftext|>