<commit_before>import {
  actions as formActions,
  SubmissionError,
  getFormValues
} from 'redux-form'
import {externalEvents, notifier, errorLogging, form, actions as actionUtil, actionEmitter, rest}
  from 'tocco-app-extensions'

import * as actions from './actions'
import {
  fetchEntity,
  updateEntity,
  fetchModel,
  createEntity
} from '../../util/api/entities'
import {submitValidate} from '../../util/detailView/asyncValidation'
import modes from '../../util/modes'

import {call, put, fork, select, takeLatest, takeEvery, all} from 'redux-saga/effects'

export const formInitialValueSelector = formId => state => state.form[formId].initial
export const entityDetailSelector = state => state.entityDetail

const FORM_ID = 'detailForm'

export default function* sagas() {
  yield all([
    fork(takeLatest, actions.LOAD_DETAIL_VIEW, loadDetailView),
    fork(takeLatest, actions.UNLOAD_DETAIL_VIEW, unloadDetailView),
    fork(takeLatest, actions.TOUCH_ALL_FIELDS, touchAllFields),
    fork(takeEvery, actions.SUBMIT_FORM, submitForm),
    fork(takeEvery, actions.FIRE_TOUCHED, fireTouched),
    fork(takeEvery, actionUtil.actions.ACTION_INVOKED, actionInvoked)
  ])
}

export function* loadDetailFormDefinition(formName) {
  const formDefinition = yield call(form.fetchForm, formName)
  yield put(actions.setFormDefinition(formDefinition))
  return formDefinition
}

export function* loadEntity(entityName, entityId, formDefinition, formName) {
  const fieldDefinitions = yield call(form.getFieldDefinitions, formDefinition)
  const paths = yield call(form.getUsedPaths, fieldDefinitions)
  const entity = yield call(fetchEntity, entityName, entityId, paths, formName)
  yield put(actions.setEntity(entity))
  return entity
}

export function* getTargetEntityName(entityName, modelPaths) {
  if (modelPaths && modelPaths.length > 0) {
    let model = yield call(fetchModel, entityName)

    for (const path of modelPaths) {
      const relation = model[path]
      if (!relation) {
        throw new Error(`No such path '${path}' found on entity model '${entityName}'`)
      }
      entityName = relation.targetEntity
      model = yield call(fetchModel, entityName)
    }
  }

  return entityName
}

export function* unloadDetailView() {
  yield put(actions.setEntity(null))
  yield put(formActions.destroy(FORM_ID))
}

export function* loadEntityModel(entityName) {
  const entityModel = yield call(fetchModel, entityName)
  yield put(actions.setEntityModel(entityModel))
  return entityModel
}

export function* loadDetailView() {
  const {entityName, formName, mode, defaultValues} = yield select(entityDetailSelector)

  const model = yield call(loadEntityModel, entityName)
  const formDefinition = yield call(loadDetailFormDefinition, formName)

  if (mode === modes.CREATE) {
    yield put(actions.setEntity({paths: {}, model: entityName}))
    const fieldDefinitions = yield call(form.getFieldDefinitions, formDefinition)
    const formDefaultValues = yield call(form.getDefaultValues, fieldDefinitions)
    const inputDefaultValues = yield call(form.loadDisplaysOfRelationFields, defaultValues, model)

    yield put(formActions.initialize(FORM_ID, {...formDefaultValues, ...inputDefaultValues}))
  } else {
    yield call(loadData)
  }
}

export function* updateFormSubmit(entity, paths) {
  const updatedEntity = yield call(updateEntity, entity, paths)
  const updatedFormValues = yield call(form.entityToFormValues, updatedEntity)
  yield put(formActions.initialize(FORM_ID, updatedFormValues))

  yield call(showNotification, 'success', 'saveSuccessfulTitle', 'saveSuccessfulMessage')
  yield put(actions.setLastSave())
  yield put(formActions.stopSubmit(FORM_ID))
}

export function* createFormSubmit(entity, paths) {
  const createdEntityId = yield call(createEntity, entity, paths)
  yield put(externalEvents.fireExternalEvent('onEntityCreated', {id: createdEntityId}))
  yield call(showNotification, 'success', 'createSuccessfulTitle', 'createSuccessfulMessage')
}

export function* touchAllFields() {
  const {formDefinition} = yield select(entityDetailSelector)
  const fieldDefinitions = yield call(form.getFieldDefinitions, formDefinition)
  yield put(formActions.touch(FORM_ID, ...(fieldDefinitions.map(f => f.id))))
}

export function* handleSubmitError(error) {
  if (error instanceof SubmissionError) {
    yield call(touchAllFields)
    yield put(formActions.stopSubmit(FORM_ID, error.errors))
  } else {
    if (!(error instanceof rest.ClientQuestionCancelledException)) {
      yield put(errorLogging.logError(
        'client.common.unexpectedError',
        'client.entity-detail.saveError',
        error
      ))
    }
    yield put(formActions.stopSubmit(FORM_ID))
  }

  yield call(showNotification, 'warning', 'saveAbortedTitle', 'saveAbortedMessage', 5000)
}

export function* getEntityForSubmit() {
  const values = yield select(getFormValues(FORM_ID))
  const initialValues = yield select(formInitialValueSelector(FORM_ID))
  yield put(formActions.startSubmit(FORM_ID))
  const {entityName, entityId, entityModel, mode} = yield select(entityDetailSelector)
  yield call(submitValidate, values, initialValues, entityName, entityId, entityModel, mode)
  const dirtyFields = yield call(form.getDirtyFields, initialValues, values, mode === modes.CREATE)
  return yield call(form.formValuesToEntity, values, dirtyFields, entityName, entityId, entityModel)
}

export function* getPaths() {
  const {formDefinition} = yield select(entityDetailSelector)
  const fieldDefinitions = yield call(form.getFieldDefinitions, formDefinition)
  return yield call(form.getUsedPaths, fieldDefinitions)
}

export function* submitForm() {
  try {
    const {mode} = yield select(entityDetailSelector)
    const entity = yield call(getEntityForSubmit)
    const paths = yield call(getPaths)
    if (mode === modes.UPDATE) {
      yield call(updateFormSubmit, entity, paths)
    } else if (mode === modes.CREATE) {
      yield call(createFormSubmit, entity, paths)
    }
  } catch (error) {
    yield call(handleSubmitError, error)
  }
}

export function* fireTouched({payload}) {
  const {touched: actionTouched} = payload
  const {touched: stateTouched} = yield select(entityDetailSelector)

  if (actionTouched !== stateTouched) {
    yield put(externalEvents.fireExternalEvent('onTouchedChange', {
      touched: actionTouched
    }))
    yield put(actions.setTouched(actionTouched))
  }
}

export function* showNotification(type, titleResourceName, messageResourceName, duration = 2000) {
  yield put(notifier.info(
    type,
    `client.entity-detail.${titleResourceName}`,
    `client.entity-detail.${messageResourceName}`,
    'check',
    duration
  ))
}

export function* loadData() {
  const {entityName, entityId, formName, formDefinition} = yield select(entityDetailSelector)
  const entity = yield call(loadEntity, entityName, entityId, formDefinition, formName)
  const formValues = yield call(form.entityToFormValues, entity)
  yield put(formActions.initialize(FORM_ID, formValues, {keepDirty: true}))
}

export function* actionInvoked(action) {
  yield call(loadData)
  yield put(actionEmitter.emitAction(action))
}
<commit_msg>refactor(entity-detail): create defaut values not as initial values<commit_after>import {
  actions as formActions,
  SubmissionError,
  getFormValues
} from 'redux-form'
import {externalEvents, notifier, errorLogging, form, actions as actionUtil, actionEmitter, rest}
  from 'tocco-app-extensions'

import * as actions from './actions'
import {
  fetchEntity,
  updateEntity,
  fetchModel,
  createEntity
} from '../../util/api/entities'
import {submitValidate} from '../../util/detailView/asyncValidation'
import modes from '../../util/modes'

import {call, put, fork, select, takeLatest, takeEvery, all} from 'redux-saga/effects'

export const formInitialValueSelector = formId => state => state.form[formId].initial
export const entityDetailSelector = state => state.entityDetail

const FORM_ID = 'detailForm'

export default function* sagas() {
  yield all([
    fork(takeLatest, actions.LOAD_DETAIL_VIEW, loadDetailView),
    fork(takeLatest, actions.UNLOAD_DETAIL_VIEW, unloadDetailView),
    fork(takeLatest, actions.TOUCH_ALL_FIELDS, touchAllFields),
    fork(takeEvery, actions.SUBMIT_FORM, submitForm),
    fork(takeEvery, actions.FIRE_TOUCHED, fireTouched),
    fork(takeEvery, actionUtil.actions.ACTION_INVOKED, actionInvoked)
  ])
}

export function* loadDetailFormDefinition(formName) {
  const formDefinition = yield call(form.fetchForm, formName)
  yield put(actions.setFormDefinition(formDefinition))
  return formDefinition
}

export function* loadEntity(entityName, entityId, formDefinition, formName) {
  const fieldDefinitions = yield call(form.getFieldDefinitions, formDefinition)
  const paths = yield call(form.getUsedPaths, fieldDefinitions)
  const entity = yield call(fetchEntity, entityName, entityId, paths, formName)
  yield put(actions.setEntity(entity))
  return entity
}

export function* getTargetEntityName(entityName, modelPaths) {
  if (modelPaths && modelPaths.length > 0) {
    let model = yield call(fetchModel, entityName)

    for (const path of modelPaths) {
      const relation = model[path]
      if (!relation) {
        throw new Error(`No such path '${path}' found on entity model '${entityName}'`)
      }
      entityName = relation.targetEntity
      model = yield call(fetchModel, entityName)
    }
  }

  return entityName
}

export function* unloadDetailView() {
  yield put(actions.setEntity(null))
  yield put(formActions.destroy(FORM_ID))
}

export function* loadEntityModel(entityName) {
  const entityModel = yield call(fetchModel, entityName)
  yield put(actions.setEntityModel(entityModel))
  return entityModel
}

export function* loadDetailView() {
  const {entityName, formName, mode, defaultValues} = yield select(entityDetailSelector)

  const model = yield call(loadEntityModel, entityName)
  const formDefinition = yield call(loadDetailFormDefinition, formName)

  if (mode === modes.CREATE) {
    yield put(actions.setEntity({paths: {}, model: entityName}))
    const fieldDefinitions = yield call(form.getFieldDefinitions, formDefinition)
    const formDefaultValues = yield call(form.getDefaultValues, fieldDefinitions)
    const inputDefaultValues = yield call(form.loadDisplaysOfRelationFields, defaultValues, model)
    const defaultValuesFields = {...formDefaultValues, ...inputDefaultValues}

    yield put(formActions.initialize(FORM_ID, {}))
    yield all(Object.keys(defaultValuesFields).map(key =>
      put(formActions.change(FORM_ID, key, defaultValuesFields[key]))
    ))
  } else {
    yield call(loadData)
  }
}

export function* updateFormSubmit(entity, paths) {
  const updatedEntity = yield call(updateEntity, entity, paths)
  const updatedFormValues = yield call(form.entityToFormValues, updatedEntity)
  yield put(formActions.initialize(FORM_ID, updatedFormValues))

  yield call(showNotification, 'success', 'saveSuccessfulTitle', 'saveSuccessfulMessage')
  yield put(actions.setLastSave())
  yield put(formActions.stopSubmit(FORM_ID))
}

export function* createFormSubmit(entity, paths) {
  const createdEntityId = yield call(createEntity, entity, paths)
  yield put(externalEvents.fireExternalEvent('onEntityCreated', {id: createdEntityId}))
  yield call(showNotification, 'success', 'createSuccessfulTitle', 'createSuccessfulMessage')
}

export function* touchAllFields() {
  const {formDefinition} = yield select(entityDetailSelector)
  const fieldDefinitions = yield call(form.getFieldDefinitions, formDefinition)
  yield put(formActions.touch(FORM_ID, ...(fieldDefinitions.map(f => f.id))))
}

export function* handleSubmitError(error) {
  if (error instanceof SubmissionError) {
    yield call(touchAllFields)
    yield put(formActions.stopSubmit(FORM_ID, error.errors))
  } else {
    if (!(error instanceof rest.ClientQuestionCancelledException)) {
      yield put(errorLogging.logError(
        'client.common.unexpectedError',
        'client.entity-detail.saveError',
        error
      ))
    }
    yield put(formActions.stopSubmit(FORM_ID))
  }

  yield call(showNotification, 'warning', 'saveAbortedTitle', 'saveAbortedMessage', 5000)
}

export function* getEntityForSubmit() {
  const values = yield select(getFormValues(FORM_ID))
  const initialValues = yield select(formInitialValueSelector(FORM_ID))
  yield put(formActions.startSubmit(FORM_ID))
  const {entityName, entityId, entityModel, mode} = yield select(entityDetailSelector)
  yield call(submitValidate, values, initialValues, entityName, entityId, entityModel, mode)
  const dirtyFields = yield call(form.getDirtyFields, initialValues, values, mode === modes.CREATE)
  return yield call(form.formValuesToEntity, values, dirtyFields, entityName, entityId, entityModel)
}

export function* getPaths() {
  const {formDefinition} = yield select(entityDetailSelector)
  const fieldDefinitions = yield call(form.getFieldDefinitions, formDefinition)
  return yield call(form.getUsedPaths, fieldDefinitions)
}

export function* submitForm() {
  try {
    const {mode} = yield select(entityDetailSelector)
    const entity = yield call(getEntityForSubmit)
    const paths = yield call(getPaths)
    if (mode === modes.UPDATE) {
      yield call(updateFormSubmit, entity, paths)
    } else if (mode === modes.CREATE) {
      yield call(createFormSubmit, entity, paths)
    }
  } catch (error) {
    yield call(handleSubmitError, error)
  }
}

export function* fireTouched({payload}) {
  const {touched: actionTouched} = payload
  const {touched: stateTouched} = yield select(entityDetailSelector)

  if (actionTouched !== stateTouched) {
    yield put(externalEvents.fireExternalEvent('onTouchedChange', {
      touched: actionTouched
    }))
    yield put(actions.setTouched(actionTouched))
  }
}

export function* showNotification(type, titleResourceName, messageResourceName, duration = 2000) {
  yield put(notifier.info(
    type,
    `client.entity-detail.${titleResourceName}`,
    `client.entity-detail.${messageResourceName}`,
    'check',
    duration
  ))
}

export function* loadData() {
  const {entityName, entityId, formName, formDefinition} = yield select(entityDetailSelector)
  const entity = yield call(loadEntity, entityName, entityId, formDefinition, formName)
  const formValues = yield call(form.entityToFormValues, entity)
  yield put(formActions.initialize(FORM_ID, formValues, {keepDirty: true}))
}

export function* actionInvoked(action) {
  yield call(loadData)
  yield put(actionEmitter.emitAction(action))
}
<|endoftext|>


<commit_before>'use strict';

const { join } = require('path');
const slugify = require('@sindresorhus/slugify');
const fs = require('fs-extra');
const { isKebabCase } = require('@strapi/utils');

const getDestinationPrompts = require('./prompts/get-destination-prompts');
const getFilePath = require('./utils/get-file-path');
const ctNamesPrompts = require('./prompts/ct-names-prompts');
const kindPrompts = require('./prompts/kind-prompts');
const draftAndPublishPrompts = require('./prompts/draft-and-publish-prompts');
const getAttributesPrompts = require('./prompts/get-attributes-prompts');
const bootstrapApiPrompts = require('./prompts/bootstrap-api-prompts');

module.exports = plop => {
  // Model generator
  plop.setGenerator('content-type', {
    description: 'Generate a content type for an API',
    async prompts(inquirer) {
      const config = await inquirer.prompt([
        ...ctNamesPrompts,
        ...kindPrompts,
        ...draftAndPublishPrompts,
      ]);
      const attributes = await getAttributesPrompts(inquirer);

      const api = await inquirer.prompt([
        ...getDestinationPrompts('model', plop.getDestBasePath()),
        {
          when: answers => answers.destination === 'new',
          type: 'input',
          name: 'id',
          default: config.singularName,
          message: 'Name of the new API?',
          async validate(input) {
            if (!isKebabCase(input)) {
              return 'Value must be in kebab-case';
            }

            const apiPath = join(plop.getDestBasePath(), 'api');
            const exists = await fs.pathExists(apiPath);

            if (!exists) {
              return true;
            }

            const apiDir = await fs.readdir(apiPath, { withFileTypes: true });
            const apiDirContent = apiDir.filter(fd => fd.isDirectory());

            if (apiDirContent.findIndex(api => api.name === input) !== -1) {
              throw new Error('This name is already taken.');
            }

            return true;
          },
        },
        ...bootstrapApiPrompts,
      ]);

      return {
        ...config,
        ...api,
        attributes,
      };
    },
    actions(answers) {
      const resolveFilePath = (isPlugin,filePath) => isPlugin ? `${filePath}/server` : filePath;
      const attributes = answers.attributes.reduce((object, answer) => {
        const val = { type: answer.attributeType };

        if (answer.attributeType === 'enumeration') {
          val.enum = answer.enum.split(',').map(item => item.trim());
        }

        if (answer.attributeType === 'media') {
          val.allowedTypes = ['images', 'files', 'videos'];
          val.multiple = answer.multiple;
        }

        return Object.assign(object, { [answer.attributeName]: val }, {});
      }, {});

      const filePath = resolveFilePath(answers.plugin,getFilePath(answers.destination));

      const baseActions = [
        {
          type: 'add',
          path: `${filePath}/content-types/{{ singularName }}/schema.json`,
          templateFile: 'templates/content-type.schema.json.hbs',
          data: {
            collectionName: slugify(answers.pluralName, { separator: '_' }),
          },
        },
      ];

      if (Object.entries(attributes).length > 0) {
        baseActions.push({
          type: 'modify',
          path: `${filePath}/content-types/{{ singularName }}/schema.json`,
          transform(template) {
            const parsedTemplate = JSON.parse(template);
            parsedTemplate.attributes = attributes;
            return JSON.stringify(parsedTemplate, null, 2);
          },
        });
      }

      if (answers.bootstrapApi) {
        const { singularName } = answers;

        let uid;
        if (answers.destination === 'new') {
          uid = `api::${answers.id}.${singularName}`;
        } else if (answers.api) {
          uid = `api::${answers.api}.${singularName}`;
        } else if (answers.plugin) {
          uid = `plugin::${answers.plugin}.${singularName}`;
        }

        baseActions.push(
          {
            type: 'add',
            path: `${filePath}/controllers/{{singularName}}.js`,
            templateFile: 'templates/core-controller.js.hbs',
            data: { uid },
          },
          {
            type: 'add',
            path: `${filePath}/services/{{singularName}}.js`,
            templateFile: 'templates/core-service.js.hbs',
            data: { uid },
          },
          {
            type: 'add',
            path: `${filePath}/routes/{{singularName}}.js`,
            templateFile: `templates/core-router.js.hbs`,
            data: { uid },
          }
        );
      }

      return baseActions;
    },
  });
};
<commit_msg>Revert "fixing file paths when generating CT inside plugins"<commit_after>'use strict';

const { join } = require('path');
const slugify = require('@sindresorhus/slugify');
const fs = require('fs-extra');
const { isKebabCase } = require('@strapi/utils');

const getDestinationPrompts = require('./prompts/get-destination-prompts');
const getFilePath = require('./utils/get-file-path');
const ctNamesPrompts = require('./prompts/ct-names-prompts');
const kindPrompts = require('./prompts/kind-prompts');
const draftAndPublishPrompts = require('./prompts/draft-and-publish-prompts');
const getAttributesPrompts = require('./prompts/get-attributes-prompts');
const bootstrapApiPrompts = require('./prompts/bootstrap-api-prompts');

module.exports = plop => {
  // Model generator
  plop.setGenerator('content-type', {
    description: 'Generate a content type for an API',
    async prompts(inquirer) {
      const config = await inquirer.prompt([
        ...ctNamesPrompts,
        ...kindPrompts,
        ...draftAndPublishPrompts,
      ]);
      const attributes = await getAttributesPrompts(inquirer);

      const api = await inquirer.prompt([
        ...getDestinationPrompts('model', plop.getDestBasePath()),
        {
          when: answers => answers.destination === 'new',
          type: 'input',
          name: 'id',
          default: config.singularName,
          message: 'Name of the new API?',
          async validate(input) {
            if (!isKebabCase(input)) {
              return 'Value must be in kebab-case';
            }

            const apiPath = join(plop.getDestBasePath(), 'api');
            const exists = await fs.pathExists(apiPath);

            if (!exists) {
              return true;
            }

            const apiDir = await fs.readdir(apiPath, { withFileTypes: true });
            const apiDirContent = apiDir.filter(fd => fd.isDirectory());

            if (apiDirContent.findIndex(api => api.name === input) !== -1) {
              throw new Error('This name is already taken.');
            }

            return true;
          },
        },
        ...bootstrapApiPrompts,
      ]);

      return {
        ...config,
        ...api,
        attributes,
      };
    },
    actions(answers) {
      const attributes = answers.attributes.reduce((object, answer) => {
        const val = { type: answer.attributeType };

        if (answer.attributeType === 'enumeration') {
          val.enum = answer.enum.split(',').map(item => item.trim());
        }

        if (answer.attributeType === 'media') {
          val.allowedTypes = ['images', 'files', 'videos'];
          val.multiple = answer.multiple;
        }

        return Object.assign(object, { [answer.attributeName]: val }, {});
      }, {});

      const filePath = getFilePath(answers.destination);

      const baseActions = [
        {
          type: 'add',
          path: `${filePath}/content-types/{{ singularName }}/schema.json`,
          templateFile: 'templates/content-type.schema.json.hbs',
          data: {
            collectionName: slugify(answers.pluralName, { separator: '_' }),
          },
        },
      ];

      if (Object.entries(attributes).length > 0) {
        baseActions.push({
          type: 'modify',
          path: `${filePath}/content-types/{{ singularName }}/schema.json`,
          transform(template) {
            const parsedTemplate = JSON.parse(template);
            parsedTemplate.attributes = attributes;
            return JSON.stringify(parsedTemplate, null, 2);
          },
        });
      }

      if (answers.bootstrapApi) {
        const { singularName } = answers;

        let uid;
        if (answers.destination === 'new') {
          uid = `api::${answers.id}.${singularName}`;
        } else if (answers.api) {
          uid = `api::${answers.api}.${singularName}`;
        } else if (answers.plugin) {
          uid = `plugin::${answers.plugin}.${singularName}`;
        }

        baseActions.push(
          {
            type: 'add',
            path: `${filePath}/controllers/{{singularName}}.js`,
            templateFile: 'templates/core-controller.js.hbs',
            data: { uid },
          },
          {
            type: 'add',
            path: `${filePath}/services/{{singularName}}.js`,
            templateFile: 'templates/core-service.js.hbs',
            data: { uid },
          },
          {
            type: 'add',
            path: `${filePath}/routes/{{singularName}}.js`,
            templateFile: `templates/core-router.js.hbs`,
            data: { uid },
          }
        );
      }

      return baseActions;
    },
  });
};
<|endoftext|>


<commit_before>// Play a "movie" using text and/or cEl render objects.
// Movie(
//   x, y, w, h,
//   movieObject,
//   ()=> {
//     // Movie Completed
//   }
// );

// Frame properties:
// `fontOptions` - fillText style options
//   - use it in the first keyframe of text layers
//   - and in keyframes where the `symbol` property is given text
// `x` - mandatory in first keyframe
//   - optional in subsequent keyframes only if it never changes
// `y` - see `x`
// `rotation` - see `x`
// `remove` - layer will no longer render once keyframe time is exceeded
//   - use this only in a particular layer's final keyframe
// `symbol` - swap the given symbol for a different one
//   - only active until the keyframe is exceeded
//   - will be merged with the existing symbol,
//   - so only provide the parts of the symbol you want to overwrite
//   - can be text as well as cEl obj

import { createRectangle } from 'pura/geometry/tuple';
import { ctx, fillText } from 'pura/canvas/tuple';

const Movie = (x, y, width, height, timeline, callback)=> {
  // Determine movie duration.
  // Find max time among all layers in timeline.
  const duration = timeline.reduce((currDur, layer)=> {
    return Math.max(
      // Is prev element a number or array?
      currDur,
      layer[1][layer[1].length - 1][0]
    );
  }, 0);

  // Convert plaintext into a cEl render object.
  const bootstrapText = (text, fontOptions)=> {
    const { width, height } = ctx.measureText(text);

    return {
      geometry: createRectangle([0 ,0], 0, width, height),

      render() {
        fillText(fontOptions, [0, 0], text);
      }
    };
  };

  // Collect symbols in movie.
  const symbols = timeline.map((layer)=> {
    let symbol = layer[0];

    // Only fontOptions is optionsal in movieObject.
    const { fontOptions={}, x, y, rotation } = layer[1][0][1];

    // Convert plaintext.
    if(typeof symbol === `string`) {
      symbol = bootstrapText(symbol, fontOptions);
    }

    // Setup symbol for its first render.
    symbol.geometry.position = [x, y];
    symbol.geometry.rotation = rotation;

    return symbol;
  });

  let callbackFired = false;

  const start = Date.now();

  return {
    geometry: createRectangle([x, y], 0, width, height),

    children: symbols.map((symbol, index)=> {
      if(timeline[index][1][0][0] !== 0) {
        return {};
      }

      return symbol;
    }).reverse(),

    render({ children }) {
      const now = Date.now();
      const diff = now - start;

      if(diff > duration) {
        if(callback && !callbackFired) {
          callback();
          callbackFired = true;
        }
        return;
      }

      for(const [index, layer] of timeline.entries()) {
        const keyframes = layer[1];

        let prevframe = {};

        for(const [keyframeIndex, [time, keyframe]] of keyframes.entries()) {
          // Save old keyframe and move on.
          if(diff > time) {
            if(keyframeIndex === 0) {
              children[children.length - 1 - index] = symbols[index];
            }

            if(keyframe.remove) {
              children[children.length - 1 - index] = {};
              break;
            } else {
              prevframe = { time, keyframe };
              continue;
            }
          } else if(keyframeIndex === 0) {
            break;
          }

          if(keyframeIndex === 0) {
            prevframe = { time, keyframe };
          }

          // Percentage of way through keyframe; 0-1.
          let progress = (diff-prevframe.time)/(time - prevframe.time);

          if(progress > 0.995) {
            progress = 1;
          }

          // Setup frame.
          // Extract values from previous keyframe.
          // If previous keyframe used function-driven values,
          // set them to their end states.
          for(const prop in prevframe.keyframe) {
            const val = prevframe.keyframe[prop];

            if(typeof val === `function`) {
              prevframe.keyframe[prop] = val(1);
            }
          }

          // Use keyframe symbol or main one.
          if(keyframe.symbol) {
            if(typeof keyframe.symbol === `string`) {
              keyframe.symbol = bootstrapText(keyframe.symbol, keyframe.fontOptions);
            }

            children[children.length - 1 - index] = keyframe.symbol;
          } else {
            children[children.length - 1 - index] = symbols[index];
          }

          const symbol =
            keyframe.symbol
              ? Object.assign({}, symbols[index], keyframe.symbol)
              : symbols[index];

          // Abbreviations.
          const { x:prevX, y:prevY, rotation:prevRot } = prevframe.keyframe;
          const { x:keyX, y:keyY, rotation:keyRot } = keyframe;
          const { geometry:geo } = symbol;
          const { position:geoPos } = geo;

          // Tween properties.
          if(typeof keyX === `function`) {
            geoPos[0] = keyX(progress, prevX, prevY, prevRot, width, height);
          } else if(keyX !== undefined) {
            geoPos[0] = prevX + (keyX - prevX)*progress;
          }
          if(typeof keyY === `function`) {
            geoPos[1] = keyY(progress, prevX, prevY, prevRot, width, height);
          } else if(keyY !== undefined) {
            geoPos[1] = prevY + (keyY - prevY)*progress;
          }
          if(typeof keyRot === `function`) {
            geo.rotation = keyRot(progress, prevX, prevY, prevRot, width, height);
          } else if(keyRot !== undefined) {
            geo.rotation = prevRot + (keyRot - prevRot)*progress;
          }

          // Do not look at future keyframes.
          break;
        }
      }
    }
  };
};

export default Movie;
<commit_msg>Minor optimization<commit_after>// Play a "movie" using text and/or cEl render objects.
// Movie(
//   x, y, w, h,
//   movieObject,
//   ()=> {
//     // Movie Completed
//   }
// );

// Frame properties:
// `fontOptions` - fillText style options
//   - use it in the first keyframe of text layers
//   - and in keyframes where the `symbol` property is given text
// `x` - mandatory in first keyframe
//   - optional in subsequent keyframes only if it never changes
// `y` - see `x`
// `rotation` - see `x`
// `remove` - layer will no longer render once keyframe time is exceeded
//   - use this only in a particular layer's final keyframe
// `symbol` - swap the given symbol for a different one
//   - only active until the keyframe is exceeded
//   - will be merged with the existing symbol,
//   - so only provide the parts of the symbol you want to overwrite
//   - can be text as well as cEl obj

import { createRectangle } from 'pura/geometry/tuple';
import { ctx, fillText } from 'pura/canvas/tuple';

const Movie = (x, y, width, height, timeline, callback)=> {
  // Determine movie duration.
  // Find max time among all layers in timeline.
  const duration = Math.max(...timeline.map(layer=>layer[1][layer[1].length-1][0]));

  // Convert plaintext into a cEl render object.
  const bootstrapText = (text, fontOptions)=> {
    const { width, height } = ctx.measureText(text);

    return {
      geometry: createRectangle([0 ,0], 0, width, height),

      render() {
        fillText(fontOptions, [0, 0], text);
      }
    };
  };

  // Collect symbols in movie.
  const symbols = timeline.map((layer)=> {
    let symbol = layer[0];

    // Only fontOptions is optionsal in movieObject.
    const { fontOptions={}, x, y, rotation } = layer[1][0][1];

    // Convert plaintext.
    if(typeof symbol === `string`) {
      symbol = bootstrapText(symbol, fontOptions);
    }

    // Setup symbol for its first render.
    symbol.geometry.position = [x, y];
    symbol.geometry.rotation = rotation;

    return symbol;
  });

  let callbackFired = false;

  const start = Date.now();

  return {
    geometry: createRectangle([x, y], 0, width, height),

    children: symbols.map((symbol, index)=> {
      if(timeline[index][1][0][0] !== 0) {
        return {};
      }

      return symbol;
    }).reverse(),

    render({ children }) {
      const now = Date.now();
      const diff = now - start;

      if(diff > duration) {
        if(callback && !callbackFired) {
          callback();
          callbackFired = true;
        }
        return;
      }

      for(const [index, layer] of timeline.entries()) {
        const keyframes = layer[1];

        let prevframe = {};

        for(const [keyframeIndex, [time, keyframe]] of keyframes.entries()) {
          // Save old keyframe and move on.
          if(diff > time) {
            if(keyframeIndex === 0) {
              children[children.length - 1 - index] = symbols[index];
            }

            if(keyframe.remove) {
              children[children.length - 1 - index] = {};
              break;
            } else {
              prevframe = { time, keyframe };
              continue;
            }
          } else if(keyframeIndex === 0) {
            break;
          }

          if(keyframeIndex === 0) {
            prevframe = { time, keyframe };
          }

          // Percentage of way through keyframe; 0-1.
          let progress = (diff-prevframe.time)/(time - prevframe.time);

          if(progress > 0.995) {
            progress = 1;
          }

          // Setup frame.
          // Extract values from previous keyframe.
          // If previous keyframe used function-driven values,
          // set them to their end states.
          for(const prop in prevframe.keyframe) {
            const val = prevframe.keyframe[prop];

            if(typeof val === `function`) {
              prevframe.keyframe[prop] = val(1);
            }
          }

          // Use keyframe symbol or main one.
          if(keyframe.symbol) {
            if(typeof keyframe.symbol === `string`) {
              keyframe.symbol = bootstrapText(keyframe.symbol, keyframe.fontOptions);
            }

            children[children.length - 1 - index] = keyframe.symbol;
          } else {
            children[children.length - 1 - index] = symbols[index];
          }

          const symbol =
            keyframe.symbol
              ? Object.assign({}, symbols[index], keyframe.symbol)
              : symbols[index];

          // Abbreviations.
          const { x:prevX, y:prevY, rotation:prevRot } = prevframe.keyframe;
          const { x:keyX, y:keyY, rotation:keyRot } = keyframe;
          const { geometry:geo } = symbol;
          const { position:geoPos } = geo;

          // Tween properties.
          if(typeof keyX === `function`) {
            geoPos[0] = keyX(progress, prevX, prevY, prevRot, width, height);
          } else if(keyX !== undefined) {
            geoPos[0] = prevX + (keyX - prevX)*progress;
          }
          if(typeof keyY === `function`) {
            geoPos[1] = keyY(progress, prevX, prevY, prevRot, width, height);
          } else if(keyY !== undefined) {
            geoPos[1] = prevY + (keyY - prevY)*progress;
          }
          if(typeof keyRot === `function`) {
            geo.rotation = keyRot(progress, prevX, prevY, prevRot, width, height);
          } else if(keyRot !== undefined) {
            geo.rotation = prevRot + (keyRot - prevRot)*progress;
          }

          // Do not look at future keyframes.
          break;
        }
      }
    }
  };
};

export default Movie;
<|endoftext|>


<commit_before>goog.require('goog.userAgent');

goog.provide('ol');

/**
 * Constants defined with the define tag cannot be changed in application
 * code, but can be set at compile time.
 * Some reduce the size of the build in advanced compile mode.
 */

/**
 * @define {boolean} Assume touch.  Default is `false`.
 */
ol.ASSUME_TOUCH = false;

/**
 * @define {boolean} Replace unused entries with NaNs.
 */
ol.BUFFER_REPLACE_UNUSED_ENTRIES_WITH_NANS = goog.DEBUG;

/**
 * TODO: rename this to something having to do with tile grids
 * see https://github.com/openlayers/ol3/issues/2076
 * @define {number} Default maximum zoom for default tile grids.
 */
ol.DEFAULT_MAX_ZOOM = 42;

/**
 * @define {number} Default min zoom level for the map view.  Default is `0`.
 */
ol.DEFAULT_MIN_ZOOM = 0;

/**
 * @define {number} Default high water mark.
 */
ol.DEFAULT_TILE_CACHE_HIGH_WATER_MARK = 2048;

/**
 * @define {number} Default tile size.
 */
ol.DEFAULT_TILE_SIZE = 256;

/**
 * @define {string} Default WMS version.
 */
ol.DEFAULT_WMS_VERSION = '1.3.0';

/**
 * @define {number} Drag-rotate-zoom animation duration.
 */
ol.DRAGROTATEANDZOOM_ANIMATION_DURATION = 400;

/**
 * @define {number} Drag-rotate animation duration.
 */
ol.DRAGROTATE_ANIMATION_DURATION = 250;

/**
 * @define {number} Drag-zoom animation duration.
 */
ol.DRAGZOOM_ANIMATION_DURATION = 200;

/**
 * @define {number} Hysterisis pixels.
 */
ol.DRAG_BOX_HYSTERESIS_PIXELS = 8;

/**
 * @define {boolean} Enable the Canvas renderer.  Default is `true`. Setting
 *     this to false at compile time in advanced mode removes all code
 *     supporting the Canvas renderer from the build.
 */
ol.ENABLE_CANVAS = true;

/**
 * @define {boolean} Enable the DOM renderer (used as a fallback where Canvas is
 *     not available).  Default is `true`. Setting this to false at compile time
 *     in advanced mode removes all code supporting the DOM renderer from the
 *     build.
 */
ol.ENABLE_DOM = true;

/**
 * @define {boolean} Enable rendering of ol.layer.Image based layers.  Default
 *     is `true`. Setting this to false at compile time in advanced mode removes
 *     all code supporting Image layers from the build.
 */
ol.ENABLE_IMAGE = true;

/**
 * @define {boolean} Enable Closure named colors (`goog.color.names`).
 *     Enabling these colors adds about 3KB uncompressed / 1.5KB compressed to
 *     the final build size.  Default is `false`. This setting has no effect
 *     with Canvas renderer, which uses its own names, whether this is true or
 *     false.
 */
ol.ENABLE_NAMED_COLORS = false;

/**
 * @define {boolean} Enable integration with the Proj4js library.  Default is
 *     `true`.
 */
ol.ENABLE_PROJ4JS = true;

/**
 * @define {boolean} Enable rendering of ol.layer.Tile based layers.  Default is
 *     `true`. Setting this to false at compile time in advanced mode removes
 *     all code supporting Tile layers from the build.
 */
ol.ENABLE_TILE = true;

/**
 * @define {boolean} Enable rendering of ol.layer.Vector based layers.  Default
 *     is `true`. Setting this to false at compile time in advanced mode removes
 *     all code supporting Vector layers from the build.
 */
ol.ENABLE_VECTOR = true;

/**
 * @define {boolean} Enable the WebGL renderer.  Default is `true`. Setting
 *     this to false at compile time in advanced mode removes all code
 *     supporting the WebGL renderer from the build.
 */
ol.ENABLE_WEBGL = true;

/**
 * @define {boolean} Support legacy IE (7-8).  Default is `false`.
 */
ol.LEGACY_IE_SUPPORT = false;

/**
 * The page is loaded using HTTPS.
 * @const
 * @type {boolean}
 */
ol.IS_HTTPS = goog.global.location.protocol === 'https:';

/**
 * Whether the current browser is legacy IE
 * @const
 * @type {boolean}
 */
ol.IS_LEGACY_IE = goog.userAgent.IE &&
    !goog.userAgent.isVersionOrHigher('9.0') && goog.userAgent.VERSION !== '';

/**
 * @define {number} Keyboard pan duration.
 */
ol.KEYBOARD_PAN_DURATION = 100;

/**
 * @define {number} Maximum mouse wheel delta.
 */
ol.MOUSEWHEELZOOM_MAXDELTA = 1;

/**
 * @define {number} Mouse wheel timeout duration.
 */
ol.MOUSEWHEELZOOM_TIMEOUT_DURATION = 80;

/**
 * @define {number} Rotate animation duration.
 */
ol.ROTATE_ANIMATION_DURATION = 250;

/**
 * @define {number} Tolerance for geometry simplification in device pixels.
 */
ol.SIMPLIFY_TOLERANCE = 0.5;

/**
 * @define {number} Texture cache high water mark.
 */
ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK = 1024;

/**
 * @define {number} Zoom slider animation duration.
 */
ol.ZOOMSLIDER_ANIMATION_DURATION = 200;

/**
 * Inherit the prototype methods from one constructor into another.
 *
 * Usage:
 *
 *     function ParentClass(a, b) { }
 *     ParentClass.prototype.foo = function(a) { }
 *
 *     function ChildClass(a, b, c) {
 *       goog.base(this, a, b);
 *     }
 *     ol.inherits(ChildClass, ParentClass);
 *
 *     var child = new ChildClass('a', 'b', 'see');
 *     child.foo(); // This works.
 *
 * In addition, a superclass' implementation of a method can be invoked as
 * follows:
 *
 *     ChildClass.prototype.foo = function(a) {
 *       ChildClass.superClass_.foo.call(this, a);
 *       // Other code here.
 *     };
 *
 * @param {Function} childCtor Child constructor.
 * @param {Function} parentCtor Parent constructor.
 * @function
 * @api
 */
ol.inherits =
    goog.inherits;
// note that the newline above is necessary to satisfy the linter
<commit_msg>Fix ol.inherits docs<commit_after>goog.require('goog.userAgent');

goog.provide('ol');

/**
 * Constants defined with the define tag cannot be changed in application
 * code, but can be set at compile time.
 * Some reduce the size of the build in advanced compile mode.
 */

/**
 * @define {boolean} Assume touch.  Default is `false`.
 */
ol.ASSUME_TOUCH = false;

/**
 * @define {boolean} Replace unused entries with NaNs.
 */
ol.BUFFER_REPLACE_UNUSED_ENTRIES_WITH_NANS = goog.DEBUG;

/**
 * TODO: rename this to something having to do with tile grids
 * see https://github.com/openlayers/ol3/issues/2076
 * @define {number} Default maximum zoom for default tile grids.
 */
ol.DEFAULT_MAX_ZOOM = 42;

/**
 * @define {number} Default min zoom level for the map view.  Default is `0`.
 */
ol.DEFAULT_MIN_ZOOM = 0;

/**
 * @define {number} Default high water mark.
 */
ol.DEFAULT_TILE_CACHE_HIGH_WATER_MARK = 2048;

/**
 * @define {number} Default tile size.
 */
ol.DEFAULT_TILE_SIZE = 256;

/**
 * @define {string} Default WMS version.
 */
ol.DEFAULT_WMS_VERSION = '1.3.0';

/**
 * @define {number} Drag-rotate-zoom animation duration.
 */
ol.DRAGROTATEANDZOOM_ANIMATION_DURATION = 400;

/**
 * @define {number} Drag-rotate animation duration.
 */
ol.DRAGROTATE_ANIMATION_DURATION = 250;

/**
 * @define {number} Drag-zoom animation duration.
 */
ol.DRAGZOOM_ANIMATION_DURATION = 200;

/**
 * @define {number} Hysterisis pixels.
 */
ol.DRAG_BOX_HYSTERESIS_PIXELS = 8;

/**
 * @define {boolean} Enable the Canvas renderer.  Default is `true`. Setting
 *     this to false at compile time in advanced mode removes all code
 *     supporting the Canvas renderer from the build.
 */
ol.ENABLE_CANVAS = true;

/**
 * @define {boolean} Enable the DOM renderer (used as a fallback where Canvas is
 *     not available).  Default is `true`. Setting this to false at compile time
 *     in advanced mode removes all code supporting the DOM renderer from the
 *     build.
 */
ol.ENABLE_DOM = true;

/**
 * @define {boolean} Enable rendering of ol.layer.Image based layers.  Default
 *     is `true`. Setting this to false at compile time in advanced mode removes
 *     all code supporting Image layers from the build.
 */
ol.ENABLE_IMAGE = true;

/**
 * @define {boolean} Enable Closure named colors (`goog.color.names`).
 *     Enabling these colors adds about 3KB uncompressed / 1.5KB compressed to
 *     the final build size.  Default is `false`. This setting has no effect
 *     with Canvas renderer, which uses its own names, whether this is true or
 *     false.
 */
ol.ENABLE_NAMED_COLORS = false;

/**
 * @define {boolean} Enable integration with the Proj4js library.  Default is
 *     `true`.
 */
ol.ENABLE_PROJ4JS = true;

/**
 * @define {boolean} Enable rendering of ol.layer.Tile based layers.  Default is
 *     `true`. Setting this to false at compile time in advanced mode removes
 *     all code supporting Tile layers from the build.
 */
ol.ENABLE_TILE = true;

/**
 * @define {boolean} Enable rendering of ol.layer.Vector based layers.  Default
 *     is `true`. Setting this to false at compile time in advanced mode removes
 *     all code supporting Vector layers from the build.
 */
ol.ENABLE_VECTOR = true;

/**
 * @define {boolean} Enable the WebGL renderer.  Default is `true`. Setting
 *     this to false at compile time in advanced mode removes all code
 *     supporting the WebGL renderer from the build.
 */
ol.ENABLE_WEBGL = true;

/**
 * @define {boolean} Support legacy IE (7-8).  Default is `false`.
 */
ol.LEGACY_IE_SUPPORT = false;

/**
 * The page is loaded using HTTPS.
 * @const
 * @type {boolean}
 */
ol.IS_HTTPS = goog.global.location.protocol === 'https:';

/**
 * Whether the current browser is legacy IE
 * @const
 * @type {boolean}
 */
ol.IS_LEGACY_IE = goog.userAgent.IE &&
    !goog.userAgent.isVersionOrHigher('9.0') && goog.userAgent.VERSION !== '';

/**
 * @define {number} Keyboard pan duration.
 */
ol.KEYBOARD_PAN_DURATION = 100;

/**
 * @define {number} Maximum mouse wheel delta.
 */
ol.MOUSEWHEELZOOM_MAXDELTA = 1;

/**
 * @define {number} Mouse wheel timeout duration.
 */
ol.MOUSEWHEELZOOM_TIMEOUT_DURATION = 80;

/**
 * @define {number} Rotate animation duration.
 */
ol.ROTATE_ANIMATION_DURATION = 250;

/**
 * @define {number} Tolerance for geometry simplification in device pixels.
 */
ol.SIMPLIFY_TOLERANCE = 0.5;

/**
 * @define {number} Texture cache high water mark.
 */
ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK = 1024;

/**
 * @define {number} Zoom slider animation duration.
 */
ol.ZOOMSLIDER_ANIMATION_DURATION = 200;

/**
 * Inherit the prototype methods from one constructor into another.
 *
 * Usage:
 *
 *     function ParentClass(a, b) { }
 *     ParentClass.prototype.foo = function(a) { }
 *
 *     function ChildClass(a, b, c) {
 *       // Call parent constructor
 *       ParentClass.call(this, a, b);
 *     }
 *     ol.inherits(ChildClass, ParentClass);
 *
 *     var child = new ChildClass('a', 'b', 'see');
 *     child.foo(); // This works.
 *
 * In addition, a superclass' implementation of a method can be invoked as
 * follows:
 *
 *     ChildClass.prototype.foo = function(a) {
 *       ChildClass.base(this, 'foo', a);
 *       // Other code here.
 *     };
 *
 * @param {Function} childCtor Child constructor.
 * @param {Function} parentCtor Parent constructor.
 * @function
 * @api
 */
ol.inherits =
    goog.inherits;
// note that the newline above is necessary to satisfy the linter
<|endoftext|>


<commit_before>var fs = require("fs-extra");
var path = require("path");
var resolve = require("resolve");
var handlebars = require("handlebars");
var cwd = process.cwd();

var Bitbundler = requireModule("bit-bundler");
var jsPlugin = requireModule("bit-loader-js");
var eslintPlugin = requireModule("bit-eslint");
var babelPlugin = requireModule("bit-loader-babel");
var excludesPlugin = requireModule("bit-loader-excludes");
var extensionsPuglin = requireModule("bit-loader-extensions");
var nodeBuiltins = requireModule("bit-loader-builtins");
var cssPlugin = requireModule("bit-loader-css");
var jsonPlugin = requireModule("bit-loader-json");
var httpResourcePlugin = requireModule("bit-loader-httpresource");
var minifyjs = requireModule("bit-bundler-minifyjs");
var extractsm = requireModule("bit-bundler-extractsm");
var splitter = requireModule("bit-bundler-splitter");
var babelCore = requireModule("babel-core");

// Config file
var config = require(path.join(__dirname, "../", ".bundlerrc.json"));
try { config = Object.assign({}, config, require(path.join(cwd, ".bundlerrc.json"))); }
catch(e) {}

function createBundler(options) {
  settings = Object.assign({}, config, options);

  return new Bitbundler({
    watch: settings.watch,
    loader: {
      plugins: [
        excludesPlugin(settings.excludes),
        extensionsPuglin(settings.extensions),
        httpResourcePlugin(settings.httpResources),
        eslintPlugin(settings.eslint),
        jsPlugin(settings.js),
        babelPlugin(Object.assign({ core: babelCore, options: { presets: [], sourceMaps: "inline" }}, settings.babel)),
        cssPlugin(settings.css),
        jsonPlugin(settings.json),
        nodeBuiltins()
      ]
    },
    bundler: {
      plugins: configureShards(settings.shards).concat([
        minifyjs({ banner: buildBannerString() }),
        extractsm()
      ])
    }
  });
}

function configureShards(options) {
  return Object.keys(options || {}).map(function(name) {
    // Sample config
    // splitter("dist/vendor.js", { match: { path: /\/node_modules\// } })
    // The input config can a string and it will be coerced to a match.path matcher
    if (typeof options[name] === "string") {
      options[name] = { match: { path: options[name] } };
    }

    return splitter(name, configureSplitterOptions(name, options[name]));
  });
}

function configureSplitterOptions(name, options) {
  // this is specifically to convert all string matching rules to be regexps
  if (typeof options === "string") {
    return name === "extensions" ? options : new RegExp(options);
  }

  return Object.keys(options).reduce(function(result, option) {
    result[option] = configureSplitterOptions(option, options[option]);
    return result;
  }, {});
}

function buildBannerString() {
  var date = new Date();
  var pkg = {};
  try { pkg = require(path.join(process.cwd(), "package")); }
  catch(e) {}

  var template = handlebars.compile("/*! {{ pkg.name }} v{{ pkg.version }} - {{ date }}. (c) {{ fullYear }} {{{ pkg.author }}}. Licensed under {{ pkg.license }} */");
  return template({pkg: pkg, date: date, fullYear: date.getFullYear()});
}

function requireModule(name) {
  var modulePath;

  try {
    modulePath = resolve.sync(name, { basedir: cwd });
  }
  catch(ex) {
    modulePath = resolve.sync(name, { basedir: __dirname });
  }

  return require(modulePath);
}

module.exports = function(files, options) {
  return createBundler(options).bundle(files);
};

<commit_msg>adding mud option<commit_after>var fs = require("fs-extra");
var path = require("path");
var resolve = require("resolve");
var handlebars = require("handlebars");
var cwd = process.cwd();

var Bitbundler = requireModule("bit-bundler");
var jsPlugin = requireModule("bit-loader-js");
var eslintPlugin = requireModule("bit-eslint");
var babelPlugin = requireModule("bit-loader-babel");
var excludesPlugin = requireModule("bit-loader-excludes");
var extensionsPuglin = requireModule("bit-loader-extensions");
var nodeBuiltins = requireModule("bit-loader-builtins");
var cssPlugin = requireModule("bit-loader-css");
var jsonPlugin = requireModule("bit-loader-json");
var httpResourcePlugin = requireModule("bit-loader-httpresource");
var minifyjs = requireModule("bit-bundler-minifyjs");
var extractsm = requireModule("bit-bundler-extractsm");
var splitter = requireModule("bit-bundler-splitter");
var babelCore = requireModule("babel-core");

// Config file
var config = require(path.join(__dirname, "../", ".bundlerrc.json"));
try { config = Object.assign({}, config, require(path.join(cwd, ".bundlerrc.json"))); }
catch(e) {}

function createBundler(options) {
  settings = Object.assign({}, config, options);

  return new Bitbundler({
    umd: settings.umd,
    watch: settings.watch,
    loader: {
      plugins: [
        excludesPlugin(settings.excludes),
        extensionsPuglin(settings.extensions),
        httpResourcePlugin(settings.httpResources),
        eslintPlugin(settings.eslint),
        jsPlugin(settings.js),
        babelPlugin(Object.assign({ core: babelCore, options: { presets: [], sourceMaps: "inline" }}, settings.babel)),
        cssPlugin(settings.css),
        jsonPlugin(settings.json),
        nodeBuiltins()
      ]
    },
    bundler: {
      plugins: configureShards(settings.shards).concat([
        minifyjs({ banner: buildBannerString() }),
        extractsm()
      ])
    }
  });
}

function configureShards(options) {
  return Object.keys(options || {}).map(function(name) {
    // Sample config
    // splitter("dist/vendor.js", { match: { path: /\/node_modules\// } })
    // The input config can a string and it will be coerced to a match.path matcher
    if (typeof options[name] === "string") {
      options[name] = { match: { path: options[name] } };
    }

    return splitter(name, configureSplitterOptions(name, options[name]));
  });
}

function configureSplitterOptions(name, options) {
  // this is specifically to convert all string matching rules to be regexps
  if (typeof options === "string") {
    return name === "extensions" ? options : new RegExp(options);
  }

  return Object.keys(options).reduce(function(result, option) {
    result[option] = configureSplitterOptions(option, options[option]);
    return result;
  }, {});
}

function buildBannerString() {
  var date = new Date();
  var pkg = {};
  try { pkg = require(path.join(process.cwd(), "package")); }
  catch(e) {}

  var template = handlebars.compile("/*! {{ pkg.name }} v{{ pkg.version }} - {{ date }}. (c) {{ fullYear }} {{{ pkg.author }}}. Licensed under {{ pkg.license }} */");
  return template({pkg: pkg, date: date, fullYear: date.getFullYear()});
}

function requireModule(name) {
  var modulePath;

  try {
    modulePath = resolve.sync(name, { basedir: cwd });
  }
  catch(ex) {
    modulePath = resolve.sync(name, { basedir: __dirname });
  }

  return require(modulePath);
}

module.exports = function(files, options) {
  return createBundler(options).bundle(files);
};

<|endoftext|>


<commit_before>/**
 * Copyright (C) 2016 pantojs.xyz
 * sieve.js
 *
 * changelog
 * 2016-06-21[18:46:42]:revised
 *
 * @author yanni4night@gmail.com
 * @version 1.0.0
 * @since 1.0.0
 */
'use strict';

const glob = require('glob');

const fs = require('fs');
const chokidar = require('chokidar');
const path = require('path');
const mkdirp = require('mkdirp');
const minimatch = require('minimatch');

const logger = require('./logger');

const isString = require('lodash/isString');
const camelCase = require('lodash/camelCase');
const isFunction = require('lodash/isFunction');
const extend = require('lodash/extend');
const lodash = require('lodash');
const flattenDeep = require('lodash/flattenDeep');
const Stream = require('./stream');
const FileCollection = require('./file-collection');

class Panto {
    constructor() {
        const defaultOpts = {
            cwd: process.cwd(),
            output: 'output',
            binaryResource: 'webp,png,jpg,jpeg,gif,bmp,tiff,swf,woff,woff2,ttf,eot,otf,cur,zip,gz,7z,gzip,tgz,lzh,lha,bz2,bzip2,tbz2,tbz,xz,txz,z,lzma,arj,cab,alz,egg,bh,jar,iso,img,udf,wim,rar,tar,bz2,apk,ipa,exe,pages,numbers,key,graffle,xmind,xls,xlsx,doc,docx,ppt,pptx,pot,potx,ppsx,pps,pptm,potm,ppsm,thmx,ppam,ppa,psd,dmg,pdf,rtf,dot,mht,dotm,docm,csv,xlt,xls,xltx,xla,xltm,xlsm,xlam,xlsb,slk,mobi,mp3,mp4,wma,rmvb,ogg,wav,aiff,midi,au,aac,flac,ape,avi,mov,asf,wmv,3gp,mkv,mov,flv,f4v,rmvb,webm,vob,rmf'
        };
        const options = extend({}, defaultOpts);

        const isBinary = filename => minimatch(filename, options.binaryResource);

        const L = name => path.join(options.cwd, name);

        const safeDirp = name => {
            const fpath = L(name);
            const dir = path.dirname(fpath);
            return new Promise(resolve => {
                fs.exists(dir, exist => {
                    resolve(exist);
                });
            }).then(exist => {
                if (!exist) {
                    return new Promise((resolve, reject) => {
                        mkdirp(dir, err => {
                            if (err) {
                                reject(err);
                            } else {
                                resolve(fpath);
                            }
                        });
                    });
                } else {
                    return fpath;
                }
            });
        };

        const R = name => {
            return safeDirp(name).then(fpath => {
                return new Promise((resolve, reject) => {
                    fs.readFile(fpath, {
                        encoding: isBinary(name) ? null : 'utf-8'
                    }, (err, content) => {
                        if (err) {
                            reject(err);
                        } else {
                            resolve(content);
                        }
                    });
                });
            });
        };
        const W = (name, content) => {
            return safeDirp(name).then(fpath => {
                return new Promise((resolve, reject) => {
                    fs.writeFile(fpath, content, err => {
                        if (err) {
                            reject(err);
                        } else {
                            resolve();
                        }
                    });
                });
            });
        };

        Object.defineProperties(this, {
            log: {
                value: logger,
                writable: false,
                configurable: false,
                enumerable: true
            },
            util: {
                value: lodash,
                writable: false,
                configurable: false,
                enumerable: true
            },
            fileCollectionGroup: {
                value: [],
                writable: false,
                configurable: false,
                enumerable: true
            },
            streams: {
                value: [],
                writable: false,
                configurable: false,
                enumerable: true
            },
            restStreamIdx: {
                value: -1,
                writable: true,
                configurable: false,
                enumerable: true
            },
            options: {
                value: options,
                writable: false,
                configurable: false,
                enumerable: true
            },
            isBinary: {
                value: isBinary,
                writable: false,
                configurable: false,
                enumerable: true
            },
            file: {
                value: {
                    read: R,
                    write: W
                },
                writable: false,
                configurable: false,
                enumerable: true
            }
        });
        Object.freeze(this.file);
    }
    setOptions(opt) {
        extend(this.options, opt);
    }
    getFiles() {
        return new Promise((resolve, reject) => {
            glob('**/*.*', {
                cwd: this.options.cwd
            }, (err, filenames) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(filenames);
                }
            });
        });
    }
    pick(pattern) {
        if (!pattern || !isString(pattern)) {
            throw new Error(`A string pattern is required to pick up some files`);
        }
        const stream = new Stream(null, pattern);
        stream.on('end', leaf => {
            this.streams.push(leaf);
        });
        return stream;
    }
    rest() {
        const restStream = new Stream(null, null);
        restStream.on('end', leaf => {
            this.streams.push(leaf);
        });
        return restStream;
    }
    build() {
        return this.getFiles().then(filenames => {
            return this._group(filenames);
        }).then(() => {
            return this._walkStream();
        });
    }
    loadTransformer(name) {
        const t = require(`panto-transformer-${name}`);
        this[camelCase(name)] = opts => {
            return new t();//Function('opts',`return new ${t}(opts)`)(opts);
        };
    }
    watch() {
        const {
            cwd,
            output
        } = this.options;
        info(`Watching ${cwd}...`);
        const watcher = chokidar.watch(`${cwd}/**/*`, {
            ignored: [`${output}/**/*`, /[\/\\]\./],
            persistent: true,
            ignoreInitial: true,
            cwd: cwd
        });
        watcher.on('add', path => {
                this.log.info(`File ${path} has been added`);
                this._onWatchFiles({
                    filename: path,
                    cmd: 'add'
                });
            })
            .on('change', path => {
                this.log.info(`File ${path} has been changed`);
                this._onWatchFiles({
                    filename: path,
                    cmd: 'change'
                });
            })
            .on('unlink', path => {
                this.log.info(`File ${path} has been removed`);
                this._onWatchFiles({
                    filename: path,
                    cmd: 'remove'
                });
            });

    }
    _walkStream(diffs) {
        return new Promise((resolve, reject) => {
            let ret = [];
            const startTime = process.hrtime();
            let startStreamIdx = 0;
            const walkStream = () => {
                if (startStreamIdx === this.streams.length) {
                    const diff = process.hrtime(startTime);
                    const millseconds = parseInt(diff[0] * 1e3 + diff[1] / 1e6, 10);
                    this.log.info(`Complete in ${millseconds}ms`);
                    resolve(flattenDeep(ret));
                } else {
                    const stream = this.streams[startStreamIdx];
                    stream.flow(this.fileCollectionGroup[startStreamIdx].values()).then(data => {
                        ret.push(data);
                        walkStream();
                    }).catch(reject);
                }
                startStreamIdx += 1;
            };
            walkStream();
        });
    }
    _onWatchFiles(...diffs) {

        for (let i = 0; i < diffs.length; ++i) {
            let matched = false;

            for (let j = 0; j < this.streams.length; ++j) {
                if (this.streams[j].match(diffs[i].filename)) {
                    matched = true;

                    this.fileCollectionGroup[j].update(diffs[i]);
                }
            }

            if (!matched && this.restStreamIdx >= 0) {
                this.fileCollectionGroup[this.restStreamIdx].update(diffs[i]);
            }
        }
        return this._walkStream(diffs);
    }
    _group(filenames) {
        const group = this.fileCollectionGroup;

        // Initialize group
        for (let k = 0; k < this.streams.length; ++k) {
            group[k] = new FileCollection();
        }

        const leftGroup = new FileCollection();

        for (let i = 0; i < filenames.length; ++i) {
            let filename = filenames[i];
            let matched = false;
            const file = {
                filename
            }; // Mutiple shares

            this.streams.forEach((stream, idx) => {
                if (!stream.pattern) {
                    this.restStreamIdx = idx;
                } else if (stream.match(filename)) {
                    matched = true;
                    group[idx].add(file);
                }
            });

            if (!matched) {
                leftGroup.add(file);
            }
        }

        if (this.restStreamIdx >= 0) {
            group[this.restStreamIdx] = leftGroup;
        }

    }
}

const panto = new Panto();

Object.defineProperty(global, 'panto', {
    value: panto,
    enumerable: true,
    writable: false,
    configurable: false
});

panto.loadTransformer('read');

module.exports = panto;<commit_msg>optimize glob options<commit_after>/**
 * Copyright (C) 2016 pantojs.xyz
 * sieve.js
 *
 * changelog
 * 2016-06-21[18:46:42]:revised
 *
 * @author yanni4night@gmail.com
 * @version 1.0.0
 * @since 1.0.0
 */
'use strict';

const glob = require('glob');

const fs = require('fs');
const chokidar = require('chokidar');
const path = require('path');
const mkdirp = require('mkdirp');
const minimatch = require('minimatch');

const logger = require('./logger');

const isString = require('lodash/isString');
const camelCase = require('lodash/camelCase');
const isFunction = require('lodash/isFunction');
const extend = require('lodash/extend');
const lodash = require('lodash');
const flattenDeep = require('lodash/flattenDeep');
const Stream = require('./stream');
const FileCollection = require('./file-collection');

class Panto {
    constructor() {
        const defaultOpts = {
            cwd: process.cwd(),
            output: 'output',
            binaryResource: 'webp,png,jpg,jpeg,gif,bmp,tiff,swf,woff,woff2,ttf,eot,otf,cur,zip,gz,7z,gzip,tgz,lzh,lha,bz2,bzip2,tbz2,tbz,xz,txz,z,lzma,arj,cab,alz,egg,bh,jar,iso,img,udf,wim,rar,tar,bz2,apk,ipa,exe,pages,numbers,key,graffle,xmind,xls,xlsx,doc,docx,ppt,pptx,pot,potx,ppsx,pps,pptm,potm,ppsm,thmx,ppam,ppa,psd,dmg,pdf,rtf,dot,mht,dotm,docm,csv,xlt,xls,xltx,xla,xltm,xlsm,xlam,xlsb,slk,mobi,mp3,mp4,wma,rmvb,ogg,wav,aiff,midi,au,aac,flac,ape,avi,mov,asf,wmv,3gp,mkv,mov,flv,f4v,rmvb,webm,vob,rmf'
        };
        const options = extend({}, defaultOpts);

        const isBinary = filename => minimatch(filename, options.binaryResource);

        const L = name => path.join(options.cwd, name);

        const safeDirp = name => {
            const fpath = L(name);
            const dir = path.dirname(fpath);
            return new Promise(resolve => {
                fs.exists(dir, exist => {
                    resolve(exist);
                });
            }).then(exist => {
                if (!exist) {
                    return new Promise((resolve, reject) => {
                        mkdirp(dir, err => {
                            if (err) {
                                reject(err);
                            } else {
                                resolve(fpath);
                            }
                        });
                    });
                } else {
                    return fpath;
                }
            });
        };

        const R = name => {
            return safeDirp(name).then(fpath => {
                return new Promise((resolve, reject) => {
                    fs.readFile(fpath, {
                        encoding: isBinary(name) ? null : 'utf-8'
                    }, (err, content) => {
                        if (err) {
                            reject(err);
                        } else {
                            resolve(content);
                        }
                    });
                });
            });
        };
        const W = (name, content) => {
            return safeDirp(name).then(fpath => {
                return new Promise((resolve, reject) => {
                    fs.writeFile(fpath, content, err => {
                        if (err) {
                            reject(err);
                        } else {
                            resolve();
                        }
                    });
                });
            });
        };

        Object.defineProperties(this, {
            log: {
                value: logger,
                writable: false,
                configurable: false,
                enumerable: true
            },
            util: {
                value: lodash,
                writable: false,
                configurable: false,
                enumerable: true
            },
            fileCollectionGroup: {
                value: [],
                writable: false,
                configurable: false,
                enumerable: true
            },
            streams: {
                value: [],
                writable: false,
                configurable: false,
                enumerable: true
            },
            restStreamIdx: {
                value: -1,
                writable: true,
                configurable: false,
                enumerable: true
            },
            options: {
                value: options,
                writable: false,
                configurable: false,
                enumerable: true
            },
            isBinary: {
                value: isBinary,
                writable: false,
                configurable: false,
                enumerable: true
            },
            file: {
                value: {
                    read: R,
                    write: W
                },
                writable: false,
                configurable: false,
                enumerable: true
            }
        });
        Object.freeze(this.file);
    }
    setOptions(opt) {
        extend(this.options, opt);
    }
    getFiles() {
        return new Promise((resolve, reject) => {
            glob('**/*', {
                cwd: this.options.cwd,
                nodir: true,
                ignore: `${this.options.output}/**/*`
            }, (err, filenames) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(filenames);
                }
            });
        });
    }
    pick(pattern) {
        if (!pattern || !isString(pattern)) {
            throw new Error(`A string pattern is required to pick up some files`);
        }
        const stream = new Stream(null, pattern);
        stream.on('end', leaf => {
            this.streams.push(leaf);
        });
        return stream;
    }
    rest() {
        const restStream = new Stream(null, null);
        restStream.on('end', leaf => {
            this.streams.push(leaf);
        });
        return restStream;
    }
    build() {
        return this.getFiles().then(filenames => {
            return this._group(filenames);
        }).then(() => {
            return this._walkStream();
        });
    }
    loadTransformer(name) {
        const t = require(`panto-transformer-${name}`);
        this[camelCase(name)] = opts => {
            return new t(); //Function('opts',`return new ${t}(opts)`)(opts);
        };
    }
    watch() {
        const {
            cwd,
            output
        } = this.options;
        info(`Watching ${cwd}...`);
        const watcher = chokidar.watch(`${cwd}/**/*`, {
            ignored: [`${output}/**/*`, /[\/\\]\./],
            persistent: true,
            ignoreInitial: true,
            cwd: cwd
        });
        watcher.on('add', path => {
                this.log.info(`File ${path} has been added`);
                this._onWatchFiles({
                    filename: path,
                    cmd: 'add'
                });
            })
            .on('change', path => {
                this.log.info(`File ${path} has been changed`);
                this._onWatchFiles({
                    filename: path,
                    cmd: 'change'
                });
            })
            .on('unlink', path => {
                this.log.info(`File ${path} has been removed`);
                this._onWatchFiles({
                    filename: path,
                    cmd: 'remove'
                });
            });

    }
    _walkStream(diffs) {
        return new Promise((resolve, reject) => {
            let ret = [];
            const startTime = process.hrtime();
            let startStreamIdx = 0;
            const walkStream = () => {
                if (startStreamIdx === this.streams.length) {
                    const diff = process.hrtime(startTime);
                    const millseconds = parseInt(diff[0] * 1e3 + diff[1] / 1e6, 10);
                    this.log.info(`Complete in ${millseconds}ms`);
                    resolve(flattenDeep(ret));
                } else {
                    const stream = this.streams[startStreamIdx];
                    stream.flow(this.fileCollectionGroup[startStreamIdx].values()).then(data => {
                        ret.push(data);
                        walkStream();
                    }).catch(reject);
                }
                startStreamIdx += 1;
            };
            walkStream();
        });
    }
    _onWatchFiles(...diffs) {

        for (let i = 0; i < diffs.length; ++i) {
            let matched = false;

            for (let j = 0; j < this.streams.length; ++j) {
                if (this.streams[j].match(diffs[i].filename)) {
                    matched = true;

                    this.fileCollectionGroup[j].update(diffs[i]);
                }
            }

            if (!matched && this.restStreamIdx >= 0) {
                this.fileCollectionGroup[this.restStreamIdx].update(diffs[i]);
            }
        }
        return this._walkStream(diffs);
    }
    _group(filenames) {
        const group = this.fileCollectionGroup;

        // Initialize group
        for (let k = 0; k < this.streams.length; ++k) {
            group[k] = new FileCollection();
        }

        const leftGroup = new FileCollection();

        for (let i = 0; i < filenames.length; ++i) {
            let filename = filenames[i];
            let matched = false;
            const file = {
                filename
            }; // Mutiple shares

            this.streams.forEach((stream, idx) => {
                if (!stream.pattern) {
                    this.restStreamIdx = idx;
                } else if (stream.match(filename)) {
                    matched = true;
                    group[idx].add(file);
                }
            });

            if (!matched) {
                leftGroup.add(file);
            }
        }

        if (this.restStreamIdx >= 0) {
            group[this.restStreamIdx] = leftGroup;
        }

    }
}

const panto = new Panto();

Object.defineProperty(global, 'panto', {
    value: panto,
    enumerable: true,
    writable: false,
    configurable: false
});

panto.loadTransformer('read');

module.exports = panto;<|endoftext|>


<commit_before>const patch = {
  oscillators: [
    {
      type: 'sine',
      detune: 0,
      octave: 3,
      gain: .5
    }, {
      type: 'sawtooth',
      detune: 0,
      octave: 3,
      gain: .3
    }, {
      type: 'square',
      detune: -.1,
      octave: 3,
      gain: .6
    }
  ],
  filter: {
    type: 'lowpass',
    frequency: 10000,
    Q: 1,
    gain: 1,
    attack: 1000,
    decay: 3000,
    sustain: .4,
    release: 300
  },
  effectBus: [
    // {
    //   type: 'convolver',
    //   highCut: 22050, //20 to 22050
    //   lowCut: 20, //20 to 22050
    //   dryLevel: 1, //0 to 1+
    //   wetLevel: 1, //0 to 1+
    //   level: 1, //0 to 1+, adjusts total output of both wet and dry
    //   impulse: "impulses/impulse_rev.wav", //the path to your impulse response
    //   bypass: 1,
    //   order: 5
    //  },
	  //  {
    //   type: 'bitcrusher',
    //   bits: 1, //1 to 16
    //   normfreq: 0.1, //0 to 1
    //   bufferSize: 256, //256 to 16384
    //   order: 2
    // },
	  // {
    //   type: 'delay',
    //   feedback: 0.05, //0 to 1+
    //   delayTime: 400, //1 to 10000 milliseconds
    //   wetLevel: 0.5, //0 to 1+
    //   dryLevel: 1, //0 to 1+
    //   cutoff: 2000, //cutoff frequency of the built in lowpass-filter. 20 to 22050
    //   bypass: 1,
    //   order: 4
    // },
    // {
    //   type: 'chorus',
    //   rate: 1.5,
    //   feedback: 0.2,
    //   delay: 0.0045,
    //   bypass: 1
    // },
    // {
    //   type: 'moog',
    //   cutoff: 0.065,    //0 to 1
    //   resonance: 0,   //0 to 4
    //   bufferSize: 256
    // },
    {
      type: 'phaser',
      rate: 1.2,                     //0.01 to 8 is a decent range, but higher values are possible
      depth: 0.3,                    //0 to 1
      feedback: 0.2,                 //0 to 1+
      stereoPhase: 30,               //0 to 180
      baseModulationFrequency: 700,  //500 to 1500
      bypass: 0
    },
    // {
    //   type: 'ping_pong',
    //   wetLevel: 0, //0 to 1
    //   feedback: 0.3, //0 to 1
    //   delayTimeLeft: 200, //1 to 10000 (milliseconds)
    //   delayTimeRight: 200 //1 to 10000 (milliseconds)
    // },
    // {
    //   type: 'convolver',
    //   highCut: 20000,                         //20 to 22050
    //   lowCut: 20,                             //20 to 22050
    //   dryLevel: 1,                            //0 to 1+
    //   wetLevel: 1,                            //0 to 1+
    //   level: 1,                               //0 to 1+, adjusts total output of both wet and dry   //the path to your impulse response
    //   bypass: 1
<<<<<<< HEAD
    // },
=======
    // }
>>>>>>> a93f56fbd23c3a15baa3d25d71b0811c9d43ea39
	// {
  //     type: 'bitcrusher',
  //     bits: 1, //1 to 16
  //     normfreq: 0.1, //0 to 1
  //     bufferSize: 256, //256 to 16384
  //     order: 2
  //   },
	{
      type: 'delay',
      feedback: 0.05, //0 to 1+
      delayTime: 400, //1 to 10000 milliseconds
      wetLevel: 0.25, //0 to 1+
      dryLevel: 1, //0 to 1+
      cutoff: 2000, //cutoff frequency of the built in lowpass-filter. 20 to 22050
      bypass: 0,
      order: 4
    }
  ],
  compressor: {
    threshold: -1, //-100 to 0
    makeupGain: 1, //0 and up (in decibels)
    attack: 1000, //0 to 1000
    release: 3000, //0 to 3000
    ratio: 20, //1 to 20
    knee: 40, //0 to 40
    automakeup: true, //true/false
    bypass: 0
  },
  adsr: {
    attack: 1000,
    decay: 2000,
    sustain: .4,
    release: 300
  },
  masterGain: 1
}

export default patch;
<commit_msg>stuff<commit_after>const patch = {
  oscillators: [
    {
      type: 'sine',
      detune: 0,
      octave: 3,
      gain: .5
    }, {
      type: 'sawtooth',
      detune: 0,
      octave: 3,
      gain: .3
    }, {
      type: 'square',
      detune: -.1,
      octave: 3,
      gain: .6
    }
  ],
  filter: {
    type: 'lowpass',
    frequency: 10000,
    Q: 1,
    gain: 1,
    attack: 1000,
    decay: 3000,
    sustain: .4,
    release: 300
  },
  effectBus: [
    // {
    //   type: 'convolver',
    //   highCut: 22050, //20 to 22050
    //   lowCut: 20, //20 to 22050
    //   dryLevel: 1, //0 to 1+
    //   wetLevel: 1, //0 to 1+
    //   level: 1, //0 to 1+, adjusts total output of both wet and dry
    //   impulse: "impulses/impulse_rev.wav", //the path to your impulse response
    //   bypass: 1,
    //   order: 5
    //  },
	  //  {
    //   type: 'bitcrusher',
    //   bits: 1, //1 to 16
    //   normfreq: 0.1, //0 to 1
    //   bufferSize: 256, //256 to 16384
    //   order: 2
    // },
	  // {
    //   type: 'delay',
    //   feedback: 0.05, //0 to 1+
    //   delayTime: 400, //1 to 10000 milliseconds
    //   wetLevel: 0.5, //0 to 1+
    //   dryLevel: 1, //0 to 1+
    //   cutoff: 2000, //cutoff frequency of the built in lowpass-filter. 20 to 22050
    //   bypass: 1,
    //   order: 4
    // },
    // {
    //   type: 'chorus',
    //   rate: 1.5,
    //   feedback: 0.2,
    //   delay: 0.0045,
    //   bypass: 1
    // },
    // {
    //   type: 'moog',
    //   cutoff: 0.065,    //0 to 1
    //   resonance: 0,   //0 to 4
    //   bufferSize: 256
    // },
    {
      type: 'phaser',
      rate: 1.2,                     //0.01 to 8 is a decent range, but higher values are possible
      depth: 0.3,                    //0 to 1
      feedback: 0.2,                 //0 to 1+
      stereoPhase: 30,               //0 to 180
      baseModulationFrequency: 700,  //500 to 1500
      bypass: 0
    },
    // {
    //   type: 'ping_pong',
    //   wetLevel: 0, //0 to 1
    //   feedback: 0.3, //0 to 1
    //   delayTimeLeft: 200, //1 to 10000 (milliseconds)
    //   delayTimeRight: 200 //1 to 10000 (milliseconds)
    // },
    // {
    //   type: 'convolver',
    //   highCut: 20000,                         //20 to 22050
    //   lowCut: 20,                             //20 to 22050
    //   dryLevel: 1,                            //0 to 1+
    //   wetLevel: 1,                            //0 to 1+
    //   level: 1,                               //0 to 1+, adjusts total output of both wet and dry   //the path to your impulse response
    //   bypass: 1
    // }
	// {
  //     type: 'bitcrusher',
  //     bits: 1, //1 to 16
  //     normfreq: 0.1, //0 to 1
  //     bufferSize: 256, //256 to 16384
  //     order: 2
  //   },
	{
      type: 'delay',
      feedback: 0.05, //0 to 1+
      delayTime: 400, //1 to 10000 milliseconds
      wetLevel: 0.25, //0 to 1+
      dryLevel: 1, //0 to 1+
      cutoff: 2000, //cutoff frequency of the built in lowpass-filter. 20 to 22050
      bypass: 0,
      order: 4
    }
  ],
  compressor: {
    threshold: -1, //-100 to 0
    makeupGain: 1, //0 and up (in decibels)
    attack: 1000, //0 to 1000
    release: 3000, //0 to 3000
    ratio: 20, //1 to 20
    knee: 40, //0 to 40
    automakeup: true, //true/false
    bypass: 0
  },
  adsr: {
    attack: 1000,
    decay: 2000,
    sustain: .4,
    release: 300
  },
  masterGain: 1
}

export default patch;
<|endoftext|>


<commit_before>const Gtk = imports.gi.Gtk;
const Gio = imports.gi.Gio;
const GObject = imports.gi.GObject;

const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
const N_ = function(e) { return e; };

const Extension = imports.misc.extensionUtils.getCurrentExtension();
const Convenience = Extension.imports.convenience;

const ApiProvider = Extension.imports.ApiProvider;

const SETTINGS_SCHEMA = 'org.gnome.shell.extensions.bitcoin-markets';
const SETTINGS_FIRST_TIME = 'first-time';
const SETTINGS_MARKET = 'market';
const SETTINGS_CURRENCY = 'currency';

let _settings;

let initSettings = function () {
    _settings = Extension.getSettings();
}

let _defaults = [
    {
        api: 'mtgox',
        currency: 'USD',
        attribute: 'last_local'
    }, {
        api: 'mtgox',
        currency: 'EUR',
        attribute: 'last_local'
    }
];

const BitcoinMarketsSettingsWidget = new GObject.Class({
    Name: "BitcoinMarkets.BitcoinMarketsSettingsWidget",
    GTypeName: "BitcoinMarketsSettingsWidget",
    Extends: Gtk.Grid,

    _init: function (params) {
        this.parent(params);

        this.margin = 10;
        this.orientation = Gtk.Orientation.VERTICAL;

        this.add(new Gtk.Label({label: _("API Provider")}));

        for (let i=0; i < 10; i++) {
            this.attach(
                new Gtk.Label({label: _("foo " + i)}),
                i, 2, 1, 1);

        }
    }
});

function init() {
    initSettings();
    Convenience.initTranslations();
}

function buildPrefsWidget() {
    let widget = new BitcoinMarketsSettingsWidget();

    widget.show_all();

    return widget;
}
<commit_msg>initial preferences dialog<commit_after>const Lang = imports.lang;

const Gtk = imports.gi.Gtk;
const Gio = imports.gi.Gio;
const GObject = imports.gi.GObject;

const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
const N_ = function(e) { return e; };

const Extension = imports.misc.extensionUtils.getCurrentExtension();
const Convenience = Extension.imports.convenience;
const ApiProvider = Extension.imports.ApiProvider;

const INDICATORS_KEY = "indicators";

const _defaults = [
    {
        api: 'mtgox',
        currency: 'USD',
        attribute: 'last_local'
    }, {
        api: 'mtgox',
        currency: 'EUR',
        attribute: 'last_local'
    }
];

const IndicatorCollectionModel = new GObject.Class({
    Name: "BitcoinMarkets.IndicatorListModel",
    GTypeName: "IndicatorListModel",
    Extends: Gtk.ListStore,

    Columns: {
      LABEL: 0,
      CONFIG: 1
    },

    _init: function (params) {
        this.parent(params);
        this.set_column_types([GObject.TYPE_STRING, GObject.TYPE_STRING]);

        this._settings = Convenience.getSettings();

        this._reloadFromSettings();

        this.connect('row-changed', Lang.bind(this, this._onRowChanged));
        this.connect('row-inserted', Lang.bind(this, this._onRowInserted));
        this.connect('row-deleted', Lang.bind(this, this._onRowDeleted));
    },

    _getLabel: function (config) {
        return config.api + " " + config.currency;
    },

    _reloadFromSettings: function () {
        this.clear();

        let configs = this._settings.get_strv(INDICATORS_KEY);

        for each (let json in configs) {
            let c = JSON.parse(json);
            this.set(this.append(),
                    [this.Columns.LABEL, this.Columns.CONFIG],
                    [this._getLabel(c), json]);
        }
    },

    _onRowChanged: function () true,
    _onRowInserted: function () true,
    _onRowDeleted: function () true
});

const BitcoinMarketsSettingsWidget = new GObject.Class({
    Name: "BitcoinMarkets.BitcoinMarketsSettingsWidget",
    GTypeName: "BitcoinMarketsSettingsWidget",
    Extends: Gtk.Box,

    _init: function (params) {
        this.parent(params);
        this.margin = 10;
        this.orientation = Gtk.Orientation.HORIZONTAL;

        this._store = new IndicatorCollectionModel();

        this._initLayout();
        this._initBehavior();

        // this.add(new Gtk.Label({label: _("API Provider")}));
    },

    _initLayout: function () {
        this._indicatorList = new Gtk.Box({
            orientation: Gtk.Orientation.VERTICAL,
            'width-request': 200
        });

        this._treeView = new Gtk.TreeView({
            model: this._store,
            headers_visible: true,
            reorderable: true,
            hexpand: false,
            vexpand: true
        });

        let label = new Gtk.TreeViewColumn({title: "Label"});
        let renderer = new Gtk.CellRendererText()
        label.pack_start(renderer, true);
        label.add_attribute(renderer, "text", 0);
        this._treeView.insert_column(label, 0);

        this._indicatorList.add(this._treeView);

        let toolbar = new Gtk.Toolbar();
        toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR);

        let newButton = new Gtk.ToolButton({stock_id: Gtk.STOCK_NEW});
        newButton.connect('clicked', Lang.bind(this, this._newClicked));
        toolbar.add(newButton);

        let delButton = new Gtk.ToolButton({stock_id: Gtk.STOCK_DELETE});
        delButton.connect('clicked', Lang.bind(this, this._delClicked));
        toolbar.add(delButton);

        this._indicatorList.add(toolbar);

        this.add(this._indicatorList);

        this._configGrid = new Gtk.Grid({
            orientation: Gtk.Orientation.VERTICAL,
            margin: 10
        });

        this.add(this._configGrid);
    },

    _initBehavior: function () {
        this._selection = this._treeView.get_selection();
        this._selection.connect(
                'changed',
                Lang.bind(this, this._onSelectionChanged)
        );
    },

    _onSelectionChanged: function () {
        let [isSelected, model, iter] = this._selection.get_selected();
        let json = this._store.get_value(
            iter, this._store.Columns.CONFIG
        );
        this._displayConfig(JSON.parse(json));
    },

    _displayConfig: function (config) {

        for each (let w in this._configGridWidgets) {
            this._configGrid.remove(w);
        }

        this._configGridWidgets = [];

        let [x, y] = [1, 1];

        let add = Lang.bind(this, function (w) {
            this._configGridWidgets.push(w);
            this._configGrid.attach(w, x, y, 1, 1);
        });

        add(new Gtk.Label({label: _("Api Provider")}));
        y += 1;

        add(new Gtk.Label({label: _("Currency")}));
        y += 1;

        this._configGrid.show_all();
    },

    _newClicked: function () true,

    _delClicked: function () true
});

function init() {
    Convenience.initTranslations();
}

function buildPrefsWidget() {
    let widget = new BitcoinMarketsSettingsWidget();

    widget.show_all();

    return widget;
}
<|endoftext|>


<commit_before>import assert from 'assert';
import AMQP from './amqp';

export default class Queue {
  constructor(amqp, queue, options = {}, worker = null) {
    assert(amqp instanceof AMQP, 'error');

    // Make options optional
    if (typeof options === 'function') {
      worker = options;
      options = {};
    }

    const {prefetch} = options;
    this.queue = queue;
    this.worker = worker;
    this.AMQP = amqp;
    if (worker) {
      this.done = this.registerWorker(queue, worker, prefetch || 1);
    }
  }

  ready() {
    return this.done;
  }

  send(message, confirm = true) {
    return this.AMQP.send(this.queue, message, confirm);
  }

  async registerWorker(q, worker, prefetch) {

    // Connect to RabbitMQ
    if (! this.AMQP.connection) {
      await this.AMQP.connect();
    }

    // eslint-disable-next-line no-console
    console.log(`-> Registering worker on MQ: ${q}`);

    let retryQ = q + '-retry';
    let delay = 1000 * 60;

    // Set up a channel for the worker
    let ch = await this.AMQP.connection.createChannel();
    await ch.prefetch(prefetch);

    // The main queue
    await ch.assertQueue(q, {
      durable: true,
      deadLetterExchange: '',
      deadLetterRoutingKey: retryQ
    });

    // The retry queue - nacked jobs will go here, once the TTL expires they go
    // back into the main queue.
    await ch.assertQueue(retryQ, {
      durable: true,
      deadLetterExchange: '',
      deadLetterRoutingKey: q,
      messageTtl: delay
    });

    // Attach the worker
    return ch.consume(q, async function (msg) {
      try {
        let content = msg.content.toString();
        let data = JSON.parse(content);
        let result = await worker(data);

        // Remove the message from the queue
        if (result === true) {
          await ch.ack(msg);
        }

        // Move the message to the retry queue
        if (result === false) {
          await ch.nack(msg, false, false);
        }

        // Move the message to the retry queue after a provided delay.
        // Keeping a message unacked for some time can be used to temporarily
        // preventing the consumer from prefetching a new message, effectively
        // slowing down or block the queue. Ex. for handling rate limits.
        if (typeof result === 'number') {
          await new Promise(r => setTimeout(r, result));
          await ch.nack(msg, false, false);
        }

      } catch (e) {
        // eslint-disable-next-line no-console
        console.error('nack', q, e);
        await ch.nack(msg, false, false);
      }
    }, {noAck: false});
  }
}
<commit_msg>Remove queue options<commit_after>import assert from 'assert';
import AMQP from './amqp';

export default class Queue {
  constructor(amqp, queue, prefetch = 1, worker = null) {
    assert(amqp instanceof AMQP, 'error');

    // Make prefetch optional
    if (typeof prefetch === 'function') {
      worker = prefetch;
      prefetch = 1;
    }

    this.queue = queue;
    this.worker = worker;
    this.AMQP = amqp;
    if (worker) {
      this.done = this.registerWorker(queue, worker, prefetch || 1);
    }
  }

  ready() {
    return this.done;
  }

  send(message, confirm = true) {
    return this.AMQP.send(this.queue, message, confirm);
  }

  async registerWorker(q, worker, prefetch) {

    // Connect to RabbitMQ
    if (! this.AMQP.connection) {
      await this.AMQP.connect();
    }

    // eslint-disable-next-line no-console
    console.log(`-> Registering worker on MQ: ${q}`);

    let retryQ = q + '-retry';
    let delay = 1000 * 60;

    // Set up a channel for the worker
    let ch = await this.AMQP.connection.createChannel();
    await ch.prefetch(prefetch);

    // The main queue
    await ch.assertQueue(q, {
      durable: true,
      deadLetterExchange: '',
      deadLetterRoutingKey: retryQ
    });

    // The retry queue - nacked jobs will go here, once the TTL expires they go
    // back into the main queue.
    await ch.assertQueue(retryQ, {
      durable: true,
      deadLetterExchange: '',
      deadLetterRoutingKey: q,
      messageTtl: delay
    });

    // Attach the worker
    return ch.consume(q, async function (msg) {
      try {
        let content = msg.content.toString();
        let data = JSON.parse(content);
        let result = await worker(data);

        // Remove the message from the queue
        if (result === true) {
          await ch.ack(msg);
        }

        // Move the message to the retry queue
        if (result === false) {
          await ch.nack(msg, false, false);
        }

        // Move the message to the retry queue after a provided delay.
        // Keeping a message unacked for some time can be used to temporarily
        // preventing the consumer from prefetching a new message, effectively
        // slowing down or block the queue. Ex. for handling rate limits.
        if (typeof result === 'number') {
          await new Promise(r => setTimeout(r, result));
          await ch.nack(msg, false, false);
        }

      } catch (e) {
        // eslint-disable-next-line no-console
        console.error('nack', q, e);
        await ch.nack(msg, false, false);
      }
    }, {noAck: false});
  }
}
<|endoftext|>