<commit_before>require("should");
var dataUtil = require("../../data-util/sales/production-order-data-util");
var helper = require("../../helper");
var validate = require("dl-models").validator.sales.productionOrder;
var codeGenerator = require('../../../src/utils/code-generator');
var ProductionOrderManager= require("../../../src/managers/sales/production-order-manager");
var manager;

before('#00. connect db', function(done) {
    helper.getDb()
        .then(db => {
            manager = new ProductionOrderManager(db, {
                username: 'dev'
            });

            done();
        })
        .catch(e => {
            done(e);
        });
});

it('#01. should error when create new data with shippingQuantityTolerance more than 100', function (done) {
    dataUtil.getNewData()
        .then(sc => {

            sc.shippingQuantityTolerance = 120;

            manager.create(sc)
                .then(id => {
                    done("should error when create new data with shippingQuantityTolerance more than 100");
                })
                .catch(e => {
                    try {
                        e.errors.should.have.property('shippingQuantityTolerance');
                        done();
                    }
                    catch (ex) {
                        done(ex);
                    }
                });
        })
        .catch(e => {
            done(e);
        });
});

it('#02. it should error when create new data with different total quantity', function (done) {
    dataUtil.getNewData()
        .then(sc => {
            sc.orderQuantity=100;
            sc.detail = [{
                        quantity:10,
                    }, {
                        quantity:5,
                    }];

            manager.create(sc)
                .then(id => {
                    done("should error when create new data without detail");
                })
                .catch(e => {
                    try {
                        e.errors.should.have.property('details');
                        done();
                    }
                    catch (ex) {
                        done(ex);
                    }
                });
        })
        .catch(e => {
            done(e);
        });
});<commit_msg>fix unit test<commit_after>require("should");
var dataUtil = require("../../data-util/sales/production-order-data-util");
var helper = require("../../helper");
var validate = require("dl-models").validator.sales.productionOrder;
var codeGenerator = require('../../../src/utils/code-generator');
var ProductionOrderManager= require("../../../src/managers/sales/production-order-manager");
var manager;

before('#00. connect db', function(done) {
    helper.getDb()
        .then(db => {
            manager = new ProductionOrderManager(db, {
                username: 'dev'
            });

            done();
        })
        .catch(e => {
            done(e);
        });
});

it('#01. should error when create new data with shippingQuantityTolerance more than 100', function (done) {
    dataUtil.getNewData()
        .then(sc => {

            sc.shippingQuantityTolerance = 120;

            manager.create(sc)
                .then(id => {
                    done("should error when create new data with shippingQuantityTolerance more than 100");
                })
                .catch(e => {
                    try {
                        e.errors.should.have.property('shippingQuantityTolerance');
                        done();
                    }
                    catch (ex) {
                        done(ex);
                    }
                });
        })
        .catch(e => {
            done(e);
        });
});

it('#02. it should error when create new data with different total quantity', function (done) {
    dataUtil.getNewData()
        .then(sc => {
            sc.orderQuantity=100;
            sc.detail = [{
                        quantity:10,
                    }, {
                        quantity:5,
                    }];

            manager.create(sc)
                .then(id => {
                    done("should error when create new data without detail");
                })
                .catch(e => {
                    try {
                        e.errors.should.have.property('details');
                        done();
                    }
                    catch (ex) {
                        done(ex);
                    }
                });
        })
        .catch(e => {
            done(e);
        });
});

it('#03. it should error when create new data with invalid LampStandard', function (done) {
    dataUtil.getNewData()
        .then(sc => {
            sc.lampStandards= [{
                        lampStandardId: {},
                        lampStandard:{}
            }];

            manager.create(sc)
                .then(id => {
                    done("should error when create new data with invalid LampStandard");
                })
                .catch(e => {
                    try {
                        e.errors.should.have.property('lampStandards');
                        done();
                    }
                    catch (ex) {
                        done(ex);
                    }
                });
        })
        .catch(e => {
            done(e);
        });
});<|endoftext|>


<commit_before>if (Meteor.isClient) {
  Accounts.ui.config({
    passwordSignupFields: 'USERNAME_AND_EMAIL'
  });
}
else {
  Meteor.publish("allUserNames", function () {
    if (this.userId) { // We should only send data to logged in users.
      return Meteor.users.find({}, {fields: {'profile.username': 1, 'emails': 1}});
    }
  });
}
<commit_msg>The correct field is username not profile.username<commit_after>if (Meteor.isClient) {
  Accounts.ui.config({
    passwordSignupFields: 'USERNAME_AND_EMAIL'
  });
}
else {
  Meteor.publish("allUserNames", function () {
    if (this.userId) { // We should only send data to logged in users.
      return Meteor.users.find({}, {fields: {'username': 1, 'emails': 1}});
    }
  });
}
<|endoftext|>


<commit_before>'use strict';

var React = require('react-native');

var {
  requireNativeComponent,
  DeviceEventEmitter,
  View
} = React;

var Component = requireNativeComponent(
                                  'RSSignatureView',
                                  null
                                );
var styles = {
  signatureBox: {
    flex: 1
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'stretch',
    backgroundColor: '#F5FCFF',
  }
};

var subscription;

var SignatureCapture = React.createClass({
  propTypes: {
    pitchEnabled: React.PropTypes.bool
  },

  componentDidMount: function() {
    subscription = DeviceEventEmitter.addListener(
        'onSaveEvent',
        this.props.onSaveEvent
    );
  },

  componentWillUnmount: function() {
    subscription.remove();
  },

  render: function() {
    return (
      <View style={styles.container}>
        <Component style={styles.signatureBox} />
      </View>
    )
  }
});

module.exports = SignatureCapture;<commit_msg>fixed main component to handle new properties<commit_after>'use strict';

var React = require('react-native');

var {
  requireNativeComponent,
  DeviceEventEmitter,
  View
} = React;

var Component = requireNativeComponent(
                                  'RSSignatureView',
                                  null
                                );
var styles = {
  signatureBox: {
    flex: 1
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'stretch',
    backgroundColor: '#F5FCFF',
  }
};

var subscription;

var SignatureCapture = React.createClass({
  componentDidMount: function() {
    subscription = DeviceEventEmitter.addListener(
        'onSaveEvent',
        this.props.onSaveEvent
    );
  },

  componentWillUnmount: function() {
    subscription.remove();
  },

  render: function() {
    return (
      <View style={styles.container}>
        <Component
          style={styles.signatureBox}
          rotateClockwise={this.props.rotateClockwise}
          square={this.props.square}
        />
      </View>
    )
  }
});

module.exports = SignatureCapture;<|endoftext|>


<commit_before>"use strict";

var browserSync = require("../../../../index");

var request = require("supertest");
var assert = require("chai").assert;

describe("E2E server test with directory listings", function () {

    var instance;

    before(function (done) {

        browserSync.reset();

        var config = {
            server:    {
                baseDir: [
                    "test/fixtures/alt",
                    "test/fixtures"
                ],
                index:   "index.htm"
            },
            logLevel: "silent",
            open:      false
        };

        instance = browserSync.init(config, done).instance;
    });

    after(function () {
        instance.cleanup();
    });

    it("serves files from index.htm with multiple base dirs", function (done) {

        request(instance.server)
            .get("/")
            .set("accept", "text/html")
            .expect(200)
            .end(function (err, res) {
                assert.include(res.text, "Hello from the test");
                done();
            });
    });
});
describe("E2E server test with base dir option", function () {

    var instance;

    before(function (done) {

        browserSync.reset();

        var config = {
            server:    {
                baseDir: "./test/fixtures"
            },
            logLevel: "silent",
            open:      false
        };

        instance = browserSync.init(config, done).instance;
    });

    after(function () {
        instance.cleanup();
    });

    it("Serves files when baseDir given with leading dot.", function (done) {

        request(instance.server)
            .get("/")
            .set("accept", "text/html")
            .expect(200)
            .end(function (err, res) {
                assert.include(res.text, "<title>Test HTML Page</title>");
                done();
            });
    });
});

describe("E2E server test with base dir array option", function () {

    var instance;

    before(function (done) {

        browserSync.reset();

        var config = {
            server: ["./test/fixtures", "./test/fixtures/alt"],
            logLevel: "silent",
            open:      false
        };

        instance = browserSync.init(config, done).instance;
    });

    after(function () {
        instance.cleanup();
    });

    it("Serves files when baseDir given with leading dot.", function (done) {

        request(instance.server)
            .get("/")
            .set("accept", "text/html")
            .expect(200)
            .end(function (err, res) {
                assert.include(res.text, "<title>Test HTML Page</title>");
                done();
            });
    });
});

describe("E2E server test with base dir array option + directory", function () {

    var instance;

    before(function (done) {

        browserSync.reset();

        var config = {
            server: {
                baseDir: ["test", "app"],
                directory: true
            },
            logLevel: "silent",
            open:      false
        };

        instance = browserSync.init(config, done).instance;
    });

    after(function () {
        instance.cleanup();
    });

    it("Serves files when baseDir given with leading dot.", function (done) {

        request(instance.server)
            .get("/")
            .set("accept", "text/html")
            .expect(200)
            .end(function (err, res) {
                assert.include(res.text, "listing directory /");
                done();
            });
    });
});

describe("E2E server test with base dir array = false", function () {

    it.only("should ignore the directory option if a falsey value was given", function (done) {
        browserSync.reset();

        var config = {
            server: {
                baseDir: ["test", "app"],
                directory: false
            },
            logLevel: "silent",
            open:      false
        };

        browserSync.init(config, function (err, bs) {
            request(bs.server)
                .get("/")
                .set("accept", "text/html")
                .expect(200)
                .end(function (err, res) {
                    assert.notInclude(res.text, "listing directory /");
                    done();
                });
        });
    });
});
<commit_msg>test: allow all<commit_after>"use strict";

var browserSync = require("../../../../index");

var request = require("supertest");
var assert = require("chai").assert;

describe("E2E server test with directory listings", function () {

    var instance;

    before(function (done) {

        browserSync.reset();

        var config = {
            server:    {
                baseDir: [
                    "test/fixtures/alt",
                    "test/fixtures"
                ],
                index:   "index.htm"
            },
            logLevel: "silent",
            open:      false
        };

        instance = browserSync.init(config, done).instance;
    });

    after(function () {
        instance.cleanup();
    });

    it("serves files from index.htm with multiple base dirs", function (done) {

        request(instance.server)
            .get("/")
            .set("accept", "text/html")
            .expect(200)
            .end(function (err, res) {
                assert.include(res.text, "Hello from the test");
                done();
            });
    });
});
describe("E2E server test with base dir option", function () {

    var instance;

    before(function (done) {

        browserSync.reset();

        var config = {
            server:    {
                baseDir: "./test/fixtures"
            },
            logLevel: "silent",
            open:      false
        };

        instance = browserSync.init(config, done).instance;
    });

    after(function () {
        instance.cleanup();
    });

    it("Serves files when baseDir given with leading dot.", function (done) {

        request(instance.server)
            .get("/")
            .set("accept", "text/html")
            .expect(200)
            .end(function (err, res) {
                assert.include(res.text, "<title>Test HTML Page</title>");
                done();
            });
    });
});

describe("E2E server test with base dir array option", function () {

    var instance;

    before(function (done) {

        browserSync.reset();

        var config = {
            server: ["./test/fixtures", "./test/fixtures/alt"],
            logLevel: "silent",
            open:      false
        };

        instance = browserSync.init(config, done).instance;
    });

    after(function () {
        instance.cleanup();
    });

    it("Serves files when baseDir given with leading dot.", function (done) {

        request(instance.server)
            .get("/")
            .set("accept", "text/html")
            .expect(200)
            .end(function (err, res) {
                assert.include(res.text, "<title>Test HTML Page</title>");
                done();
            });
    });
});

describe("E2E server test with base dir array option + directory", function () {

    var instance;

    before(function (done) {

        browserSync.reset();

        var config = {
            server: {
                baseDir: ["test", "app"],
                directory: true
            },
            logLevel: "silent",
            open:      false
        };

        instance = browserSync.init(config, done).instance;
    });

    after(function () {
        instance.cleanup();
    });

    it("Serves files when baseDir given with leading dot.", function (done) {

        request(instance.server)
            .get("/")
            .set("accept", "text/html")
            .expect(200)
            .end(function (err, res) {
                assert.include(res.text, "listing directory /");
                done();
            });
    });
});

describe("E2E server test with base dir array = false", function () {

    it("should ignore the directory option if a falsey value was given", function (done) {
        browserSync.reset();

        var config = {
            server: {
                baseDir: ["test", "app"],
                directory: false
            },
            logLevel: "silent",
            open:      false
        };

        browserSync.init(config, function (err, bs) {
            request(bs.server)
                .get("/")
                .set("accept", "text/html")
                .expect(200)
                .end(function (err, res) {
                    assert.notInclude(res.text, "listing directory /");
                    done();
                });
        });
    });
});
<|endoftext|>


<commit_before>require('../../support');

var expect = require('chai').expect;
var loopback = require('loopback');

var RegistryModels = require('../../../lib/domain/registry-models');

describe.only('RegistryModels', function() {
  var registryModels;

  beforeEach(function() {
    registryModels = new RegistryModels;
  });

  describe('#appendModelV1', function() {
    var model = {collectionName: 'my-collection'};

    beforeEach(function() {
      registryModels.appendModelV1('my-collection', model);
    });

    it('should add model to V1 map', function() {
      expect(registryModels.v1Models.hasOwnProperty('my-collection')).to.be.true;
      expect(registryModels.v1Models['my-collection']).to.eql(model);
    });

    it('should not overwrite an existing V1 map item', function() {
      registryModels.appendModelV1('my-collection', {collectionName: 'new-collection'});
      expect(registryModels.v1Models['my-collection']).to.eql(model);
    });
  });

  describe('#appendModelV2', function() {
    var model = {collectionName: 'my-collection', tenantId: 'my-tenant'};

    beforeEach(function() {
      registryModels.appendModelV2('my-collection', 'my-tenant', model);
    });

    it('should add model to V2 map', function() {
      expect(registryModels.v2Models.hasOwnProperty('my-collection')).to.be.true;
      expect(registryModels.v2Models['my-collection'].hasOwnProperty('my-tenant')).to.be.true;
      expect(registryModels.v2Models['my-collection']['my-tenant']).to.eql(model);
    });

    it('should not overwrite an existing V2 map item', function() {
      registryModels.appendModelV1('my-collection', {collectionName: 'new-collection', tenantId: 'new-tenant'});
      expect(registryModels.v2Models['my-collection']['my-tenant']).to.eql(model);
    });
  });
});
<commit_msg>Remove .only<commit_after>require('../../support');

var expect = require('chai').expect;
var loopback = require('loopback');

var RegistryModels = require('../../../lib/domain/registry-models');

describe('RegistryModels', function() {
  var registryModels;

  beforeEach(function() {
    registryModels = new RegistryModels;
  });

  describe('#appendModelV1', function() {
    var model = {collectionName: 'my-collection'};

    beforeEach(function() {
      registryModels.appendModelV1('my-collection', model);
    });

    it('should add model to V1 map', function() {
      expect(registryModels.v1Models.hasOwnProperty('my-collection')).to.be.true;
      expect(registryModels.v1Models['my-collection']).to.eql(model);
    });

    it('should not overwrite an existing V1 map item', function() {
      registryModels.appendModelV1('my-collection', {collectionName: 'new-collection'});
      expect(registryModels.v1Models['my-collection']).to.eql(model);
    });
  });

  describe('#appendModelV2', function() {
    var model = {collectionName: 'my-collection', tenantId: 'my-tenant'};

    beforeEach(function() {
      registryModels.appendModelV2('my-collection', 'my-tenant', model);
    });

    it('should add model to V2 map', function() {
      expect(registryModels.v2Models.hasOwnProperty('my-collection')).to.be.true;
      expect(registryModels.v2Models['my-collection'].hasOwnProperty('my-tenant')).to.be.true;
      expect(registryModels.v2Models['my-collection']['my-tenant']).to.eql(model);
    });

    it('should not overwrite an existing V2 map item', function() {
      registryModels.appendModelV1('my-collection', {collectionName: 'new-collection', tenantId: 'new-tenant'});
      expect(registryModels.v2Models['my-collection']['my-tenant']).to.eql(model);
    });
  });
});
<|endoftext|>


<commit_before>import isPlainObject from "lodash/isPlainObject";

const defaultProps = defaultProps => ({ value }) => {
  if (isPlainObject(value)) {
    return { ...defaultProps, ...value };
  }
  return value;
};

export default defaultProps;
<commit_msg>dependency fix<commit_after>import isPlainObject from "lodash.isplainobject";

const defaultProps = defaultProps => ({ value }) => {
  if (isPlainObject(value)) {
    return { ...defaultProps, ...value };
  }
  return value;
};

export default defaultProps;
<|endoftext|>


<commit_before>/*
{
  "project_hash": {
    "issue_hash": {
      "active": {
        "logged": 100,
        "start": 1231283
      },
      "logs": [
        { "user": "user_hash", "start": 1231283, "stop": 1231383 }
      ]
    }
  }
}
 */

// start and logged are per-user
function Timer(start, logged, logs) {
  if (logged) this.logged = logged;
  else this.logged = 0;
  if (start) this.start = start;
  else this.start = 0;
  if (logs) this.logs = logs;
}

Timer.prototype.addLog = function addLog(log) {
  if (!log instanceof Log) {
    throw new Exception("Invalid log.");
  }

  this.logs.push(log);
};<commit_msg>Issue model<commit_after>/**
 * Represents a (GitHub) issue
 *
 * @class
 * @param {object} config The data in the issue, see Issue.set() for more information
 */
function Issue(config) {
  this.logs = [];

  this.set(config);
}

/**
 * Set active timer of the issue
 * @param {Timer} timer Active Timer object
 */
Issue.prototype.setTimer = function setTimer(timer) {
  if (!timer instanceof Timer) {
    throw new Error('Invalid type of argument \'timer\'. Expected: Timer');
  }

  this.timer = timer;
};

/**
 * Get active timer of the issue
 * @param {boolean} raw Return raw timer data (e.g. for JSON exports)
 * @return {Timer|object} Active Timer object (or data, if raw was specified)
 */
Issue.prototype.getTimer = function getTimer(raw) {
  if (raw) {
    return this.timer.get();
  } else {
    return this.timer;
  }
};

/**
 * Add log to the issue
 * @param {Log} log Log object
 */
Issue.prototype.addLog = function addLog(log) {
  if (!log instanceof Log) {
    throw new Error('Invalid type of argument \'log\'. Expected: Log');
  }

  this.logs.push(log);
};

/**
 * Set logs of the issue
 * @param {array} logs Array of Log objects
 */
Issue.prototype.setLogs = function setLogs(logs) {
  if (!logs instanceof Array) {
    throw new Error('Invalid type of argument \'logs\'. Expected: Array');
  }

  for (var i=0; i < logs.length; i++) {
    if (!logs[i] instanceof Log) {
      throw new Error('Invalid type of argument \'logs[' + i + ']\'. Expected: Log');
    }

    this.addLog(logs[i]);
  }
};

/**
 * Get logs of the issue
 * @param {boolean} raw Return raw log data (e.g. for JSON exports)
 * @param {array} logs Array of Log objects (or array of log data, if raw was specified)
 */
Issue.prototype.getLogs = function getLogs(raw) {
  if (raw) {
    var rawLogs = [];
    for (var i=0; i < this.logs.length; i++) {
      rawLogs.push(this.logs[i].get());
    }
    return rawLogs;
  } else {
    return this.logs;
  }
};

/**
 * Get active timer of the issue
 * @param {boolean} raw Return raw timer data (e.g. for JSON exports)
 * @return {Timer|object} Active Timer object (or data, if raw was specified)
 */
Issue.prototype.getTimer = function getTimer(raw) {
  if (raw) {
    return this.timer.get();
  } else {
    return this.timer;
  }
};

/**
 * Set multiple values of the issue
 *
 * Values:
 *  - timer: see setTimer()
 *  - logs: see setLogs()
 *
 * @param {object} config Configuration Object
 */
Issue.prototype.set = function set(config) {
  if (config) {
    if (config.timer) this.setTimer(config.timer);
    if (config.logs) this.setLogs(config.logs);
  }
};

/**
 * Get data from the issue
 * @return {object} issue data (e.g. for JSON exports)
 */
Issue.prototype.get = function get() {
  return {
    timer: this.getTimer(true),
    logs: this.getLogs(true)
  };
};<|endoftext|>


<commit_before>/**
 * @fileoverview About this file
 */

/**
 * @type {Object}
 * @const
 */
var SugarCrm = {};

/**
 * Represents SugarCRM field boolean value.
 * @enum {string}
 */
SugarCrm.Boolean = {
  '0': '0',
  '1': '1'
};

/**
 * Represents SugarCRM name value list pair.
 * @constructor
 */
SugarCrm.NameValue = function() {};

/**
 * @type {string}
 */
SugarCrm.NameValue.prototype.name;

/**
 * @type {string}
 */
SugarCrm.NameValue.prototype.value;

/**
 * Represents SugarCRM name value list entry.
 * @constructor
 */
SugarCrm.NameValueEntry = function() {};

/**
 * @type {string}
 */
SugarCrm.NameValueEntry.prototype.id;

/**
 * @type {string}
 */
SugarCrm.NameValueEntry.prototype.module_name;

/**
 * @type {Object.<SugarCrm.NameValue>}
 */
SugarCrm.NameValueEntry.prototype.name_value_list;

/**
 * Represents SugarCRM email field.
 * @constructor
 */
SugarCrm.EmailField = function() {};

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.bean_id;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.bean_module;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.date_created;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.date_modified;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.deleted;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address_caps;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address_id;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.id;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.invalid_email;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.opt_out;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.primary_address;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.reply_to_address;

/**
 * Represents SugarCRM entry.
 * @constructor
 */
SugarCrm.Record = function() {};

/**
 * @type {string}
 */
SugarCrm.Record.prototype.id;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.name;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.date_entered;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.date_modified;

/**
 * This field include in v10 REST result, but not in v4.
 * @type {string} module name.
 */
SugarCrm.Record.prototype._module;

/**
 * @type {string} either '1' or '0'
 */
SugarCrm.Record.prototype.deleted;

/**
 * Record in login respond.
 * @constructor
 * @extends {SugarCrm.Record}
 */
SugarCrm.LoginRecord = function() {};

/**
 * @type {string} "-99"
 */
SugarCrm.LoginRecord.prototype.user_currency_id;

/**
 * @type {string} "US Dollars"
 */
SugarCrm.LoginRecord.prototype.user_currency_name;

/**
 * @type {string} "."
 */
SugarCrm.LoginRecord.prototype.user_decimal_seperator;

/**
 * @type {string} "m/d/Y"
 */
SugarCrm.LoginRecord.prototype.user_default_dateformat;

/**
 * @type {?string}
 */
SugarCrm.LoginRecord.prototype.user_default_team_id;

/**
 * @type {string} "h:ia"
 */
SugarCrm.LoginRecord.prototype.user_default_timeformat;

/**
 * @type {string}
 */
SugarCrm.LoginRecord.prototype.user_id;

/**
 * @type {boolean}
 */
SugarCrm.LoginRecord.prototype.user_is_admin;

/**
 * Represents SugarCRM ModuleField.
 * @constructor
 */
SugarCrm.ModuleField = function() {};

/**
 * @type {boolean}
 */
SugarCrm.ModuleField.prototype.calculated;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.group;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.id_name;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.label;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.len;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.name;

/**
 * @type {Object.<SugarCrm.NameValue>|undefined}
 */
SugarCrm.ModuleField.prototype.options;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.related_module;

/**
 * @type {number}
 */
SugarCrm.ModuleField.prototype.required;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.type;

/**
 * Represents SugarCRM LinkField.
 * @constructor
 */
SugarCrm.LinkField = function() {};

/**
 * @type {string} this is always 'link' ?
 */
SugarCrm.LinkField.prototype.type;

/**
 * @type {string} Module name
 */
SugarCrm.LinkField.prototype.module;

/**
 * Represents meta data for ModuleInfo.
 * @constructor
 */
SugarCrm.ModuleMeta = function() {};

/**
 * Color hex for module.
 * @type {string}
 */
SugarCrm.ModuleMeta.prototype.color;

/**
 * List of email fields.
 * @type {Array.<string>}
 */
SugarCrm.ModuleMeta.prototype.email_fields;

/**
 * Represents SugarCRM Acl.
 * @constructor
 */
SugarCrm.Acl = function() {};

/**
 * @type {boolean}
 */
SugarCrm.Acl.prototype.access;

/**
 * Enum of 'edit', 'delete', 'list', 'view', 'import', 'export'
 * @type {string}
 */
SugarCrm.Acl.prototype.action;

/**
 * Represents SugarCRM AvailableModule.
 * @constructor
 */
SugarCrm.AvailableModule = function() {};

/**
 * @type {boolean}
 */
SugarCrm.AvailableModule.prototype.favorite_enabled;

/**
 * @type {string}
 */
SugarCrm.AvailableModule.prototype.module_key;

/**
 * @type {string}
 */
SugarCrm.AvailableModule.prototype.module_label;

/**
 * @type {Array.<SugarCrm.Acl>}
 */
SugarCrm.AvailableModule.prototype.acls;

/**
 * Represents SugarCRM ModuleInfo.
 * @constructor
 */
SugarCrm.ModuleInfo = function() {};

/**
 * @type {SugarCrm.ModuleMeta}
 */
SugarCrm.ModuleInfo.prototype._meta;

/**
 * @type {string}
 */
SugarCrm.ModuleInfo.prototype.module_name;

/**
 * @type {string}
 */
SugarCrm.ModuleInfo.prototype.table_name;

/**
 * @type {!Object.<SugarCrm.ModuleField>}
 */
SugarCrm.ModuleInfo.prototype.module_fields;

/**
 * @type {!Object.<SugarCrm.LinkField>}
 */
SugarCrm.ModuleInfo.prototype.link_fields;

/**
 * Represents query format in channel.
 * @constructor
 * @extends {CrmApp.ReqQuery}
 */
SugarCrm.Query = function() {};

/**
 * @type {Array.<SugarCrm.Record>} result of query.
 */
SugarCrm.Query.prototype.result;

/**
 * @interface
 */
SugarCrm.ServerInfo = function() {};

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.flavor;

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.version;

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.uptime;

/**
 * @constructor
 */
SugarCrm.About = function() {};

/**
 * @type {(string|undefined)}
 */
SugarCrm.About.prototype.baseUrl;

/**
 * @type {string}
 */
SugarCrm.About.prototype.domain;

/**
 * @type {(string|undefined)}
 */
SugarCrm.About.prototype.userName;

/**
 * @type {(boolean|undefined)}
 */
SugarCrm.About.prototype.hostPermission;

/**
 * @type {(boolean|undefined)}
 */
SugarCrm.About.prototype.isLogin;

/**
 * @constructor
 * @extends {SugarCrm.About}
 */
CrmApp.Credential = function() {};

/**
 * @type {string}
 */
CrmApp.Credential.prototype.password;

/**
 * @type {boolean|undefined}
 */
CrmApp.Credential.prototype.hashed;

/**
 * @interface
 */
SugarCrm.Details = function() {};

/**
 * @type {SugarCrm.About}
 */
SugarCrm.Details.prototype.about;

/**
 * @type {SugarCrm.ServerInfo}
 */
SugarCrm.Details.prototype.serverInfo;

/**
 * @type {SugarCrm.LoginRecord}
 */
SugarCrm.Details.prototype.loginInfo;

/**
 * @type {Array.<SugarCrm.AvailableModule>}
 */
SugarCrm.Details.prototype.availableModules;

/**
 * @type {Array.<SugarCrm.ModuleInfo>}
 */
SugarCrm.Details.prototype.modulesInfo;

/**
 * Query result for GData contact to SugarCRM records.
 * @interface
 */
SugarCrm.ContactSimilarityResult = function() {};

/**
 * @type {string}
 */
SugarCrm.ContactSimilarityResult.prototype.module;

/**
 * @type {string}
 */
SugarCrm.ContactSimilarityResult.prototype.index;

/**
 * @type {string}
 */
SugarCrm.ContactSimilarityResult.prototype.key;

/**
 * @type {Array<SugarCrm.Record>}
 */
SugarCrm.ContactSimilarityResult.prototype.result;
<commit_msg>add LDAP support.<commit_after>/**
 * @fileoverview About this file
 */

/**
 * @type {Object}
 * @const
 */
var SugarCrm = {};

/**
 * Represents SugarCRM field boolean value.
 * @enum {string}
 */
SugarCrm.Boolean = {
  '0': '0',
  '1': '1'
};

/**
 * Represents SugarCRM name value list pair.
 * @constructor
 */
SugarCrm.NameValue = function() {};

/**
 * @type {string}
 */
SugarCrm.NameValue.prototype.name;

/**
 * @type {string}
 */
SugarCrm.NameValue.prototype.value;

/**
 * Represents SugarCRM name value list entry.
 * @constructor
 */
SugarCrm.NameValueEntry = function() {};

/**
 * @type {string}
 */
SugarCrm.NameValueEntry.prototype.id;

/**
 * @type {string}
 */
SugarCrm.NameValueEntry.prototype.module_name;

/**
 * @type {Object.<SugarCrm.NameValue>}
 */
SugarCrm.NameValueEntry.prototype.name_value_list;

/**
 * Represents SugarCRM email field.
 * @constructor
 */
SugarCrm.EmailField = function() {};

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.bean_id;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.bean_module;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.date_created;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.date_modified;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.deleted;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address_caps;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address_id;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.id;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.invalid_email;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.opt_out;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.primary_address;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.reply_to_address;

/**
 * Represents SugarCRM entry.
 * @constructor
 */
SugarCrm.Record = function() {};

/**
 * @type {string}
 */
SugarCrm.Record.prototype.id;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.name;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.date_entered;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.date_modified;

/**
 * This field include in v10 REST result, but not in v4.
 * @type {string} module name.
 */
SugarCrm.Record.prototype._module;

/**
 * @type {string} either '1' or '0'
 */
SugarCrm.Record.prototype.deleted;

/**
 * Record in login respond.
 * @constructor
 * @extends {SugarCrm.Record}
 */
SugarCrm.LoginRecord = function() {};

/**
 * @type {string} "-99"
 */
SugarCrm.LoginRecord.prototype.user_currency_id;

/**
 * @type {string} "US Dollars"
 */
SugarCrm.LoginRecord.prototype.user_currency_name;

/**
 * @type {string} "."
 */
SugarCrm.LoginRecord.prototype.user_decimal_seperator;

/**
 * @type {string} "m/d/Y"
 */
SugarCrm.LoginRecord.prototype.user_default_dateformat;

/**
 * @type {?string}
 */
SugarCrm.LoginRecord.prototype.user_default_team_id;

/**
 * @type {string} "h:ia"
 */
SugarCrm.LoginRecord.prototype.user_default_timeformat;

/**
 * @type {string}
 */
SugarCrm.LoginRecord.prototype.user_id;

/**
 * @type {boolean}
 */
SugarCrm.LoginRecord.prototype.user_is_admin;

/**
 * Represents SugarCRM ModuleField.
 * @constructor
 */
SugarCrm.ModuleField = function() {};

/**
 * @type {boolean}
 */
SugarCrm.ModuleField.prototype.calculated;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.group;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.id_name;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.label;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.len;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.name;

/**
 * @type {Object.<SugarCrm.NameValue>|undefined}
 */
SugarCrm.ModuleField.prototype.options;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.related_module;

/**
 * @type {number}
 */
SugarCrm.ModuleField.prototype.required;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.type;

/**
 * Represents SugarCRM LinkField.
 * @constructor
 */
SugarCrm.LinkField = function() {};

/**
 * @type {string} this is always 'link' ?
 */
SugarCrm.LinkField.prototype.type;

/**
 * @type {string} Module name
 */
SugarCrm.LinkField.prototype.module;

/**
 * Represents meta data for ModuleInfo.
 * @constructor
 */
SugarCrm.ModuleMeta = function() {};

/**
 * Color hex for module.
 * @type {string}
 */
SugarCrm.ModuleMeta.prototype.color;

/**
 * List of email fields.
 * @type {Array.<string>}
 */
SugarCrm.ModuleMeta.prototype.email_fields;

/**
 * Represents SugarCRM Acl.
 * @constructor
 */
SugarCrm.Acl = function() {};

/**
 * @type {boolean}
 */
SugarCrm.Acl.prototype.access;

/**
 * Enum of 'edit', 'delete', 'list', 'view', 'import', 'export'
 * @type {string}
 */
SugarCrm.Acl.prototype.action;

/**
 * Represents SugarCRM AvailableModule.
 * @constructor
 */
SugarCrm.AvailableModule = function() {};

/**
 * @type {boolean}
 */
SugarCrm.AvailableModule.prototype.favorite_enabled;

/**
 * @type {string}
 */
SugarCrm.AvailableModule.prototype.module_key;

/**
 * @type {string}
 */
SugarCrm.AvailableModule.prototype.module_label;

/**
 * @type {Array.<SugarCrm.Acl>}
 */
SugarCrm.AvailableModule.prototype.acls;

/**
 * Represents SugarCRM ModuleInfo.
 * @constructor
 */
SugarCrm.ModuleInfo = function() {};

/**
 * @type {SugarCrm.ModuleMeta}
 */
SugarCrm.ModuleInfo.prototype._meta;

/**
 * @type {string}
 */
SugarCrm.ModuleInfo.prototype.module_name;

/**
 * @type {string}
 */
SugarCrm.ModuleInfo.prototype.table_name;

/**
 * @type {!Object.<SugarCrm.ModuleField>}
 */
SugarCrm.ModuleInfo.prototype.module_fields;

/**
 * @type {!Object.<SugarCrm.LinkField>}
 */
SugarCrm.ModuleInfo.prototype.link_fields;

/**
 * Represents query format in channel.
 * @constructor
 * @extends {CrmApp.ReqQuery}
 */
SugarCrm.Query = function() {};

/**
 * @type {Array.<SugarCrm.Record>} result of query.
 */
SugarCrm.Query.prototype.result;

/**
 * @interface
 */
SugarCrm.ServerInfo = function() {};

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.flavor;

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.version;

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.uptime;

/**
 * @constructor
 */
SugarCrm.About = function() {};

/**
 * @type {(string|undefined)}
 */
SugarCrm.About.prototype.baseUrl;

/**
 * @type {string}
 */
SugarCrm.About.prototype.domain;

/**
 * @type {(string|undefined)}
 */
SugarCrm.About.prototype.userName;

/**
 * @type {(boolean|undefined)}
 */
SugarCrm.About.prototype.hostPermission;

/**
 * @type {(string|undefined)} authentication provider.
 */
SugarCrm.About.prototype.provider;

/**
 * @type {(boolean|undefined)}
 */
SugarCrm.About.prototype.isLogin;

/**
 * @constructor
 * @extends {SugarCrm.About}
 */
CrmApp.Credential = function() {};

/**
 * @type {string}
 */
CrmApp.Credential.prototype.password;

/**
 * @type {string|undefined}
 */
CrmApp.Credential.prototype.provider;

/**
 * @type {boolean|undefined}
 */
CrmApp.Credential.prototype.hashed;

/**
 * @interface
 */
SugarCrm.Details = function() {};

/**
 * @type {SugarCrm.About}
 */
SugarCrm.Details.prototype.about;

/**
 * @type {SugarCrm.ServerInfo}
 */
SugarCrm.Details.prototype.serverInfo;

/**
 * @type {SugarCrm.LoginRecord}
 */
SugarCrm.Details.prototype.loginInfo;

/**
 * @type {Array.<SugarCrm.AvailableModule>}
 */
SugarCrm.Details.prototype.availableModules;

/**
 * @type {Array.<SugarCrm.ModuleInfo>}
 */
SugarCrm.Details.prototype.modulesInfo;

/**
 * Query result for GData contact to SugarCRM records.
 * @interface
 */
SugarCrm.ContactSimilarityResult = function() {};

/**
 * @type {string}
 */
SugarCrm.ContactSimilarityResult.prototype.module;

/**
 * @type {string}
 */
SugarCrm.ContactSimilarityResult.prototype.index;

/**
 * @type {string}
 */
SugarCrm.ContactSimilarityResult.prototype.key;

/**
 * @type {Array<SugarCrm.Record>}
 */
SugarCrm.ContactSimilarityResult.prototype.result;
<|endoftext|>


<commit_before>const _ = require('lodash');

// A subclass of `@apostrophecms/piece-type`, `@apostrophecms/image` establishes a library
// of uploaded images in formats suitable for use on the web.
//
// Together with [@apostrophecms/image-widget](../@apostrophecms/image-widget/index.html),
// this module provides a simple way to add downloadable PDFs and the like to
// a website, and to manage a library of them for reuse.
//
// Each `@apostrophecms/image` doc has an `attachment` schema field, implemented
// by the [@apostrophecms/attachment](../@apostrophecms/attachment/index.html) module.

module.exports = {
  extend: '@apostrophecms/piece-type',
  options: {
    name: '@apostrophecms/image',
    label: 'apostrophe:image',
    pluralLabel: 'apostrophe:images',
    alias: 'image',
    perPage: 31,
    sort: { createdAt: -1 },
    quickCreate: false,
    insertViaUpload: true,
    searchable: false,
    slugPrefix: 'image-',
    autopublish: true,
    editRole: 'editor',
    publishRole: 'editor',
    showPermissions: true,
    // Images should by default be considered "related documents" when localizing
    // another document that references them
    relatedDocument: true,
    relationshipEditor: 'AposImageRelationshipEditor',
    relationshipFields: {
      add: {
        top: {
          type: 'integer'
        },
        left: {
          type: 'integer'
        },
        width: {
          type: 'integer'
        },
        height: {
          type: 'integer'
        },
        x: {
          type: 'integer'
        },
        y: {
          type: 'integer'
        }
      }
    },
    relationshipPostprocessor: 'autocrop'
  },
  fields: {
    remove: [ 'visibility' ],
    add: {
      slug: {
        type: 'slug',
        label: 'apostrophe:slug',
        prefix: 'image',
        required: true,
        following: [ 'title', 'archived' ]
      },
      attachment: {
        type: 'attachment',
        label: 'apostrophe:imageFile',
        fileGroup: 'images',
        required: true
      },
      alt: {
        type: 'string',
        label: 'apostrophe:altText',
        help: 'apostrophe:altTextHelp'
      },
      credit: {
        type: 'string',
        label: 'apostrophe:credit'
      },
      creditUrl: {
        type: 'url',
        label: 'apostrophe:creditUrl'
      },
      _tags: {
        type: 'relationship',
        label: 'apostrophe:tags',
        withType: '@apostrophecms/image-tag',
        modifiers: [ 'no-search' ]
      }
    },
    group: {
      // The image editor has only one group.
      basics: {
        label: 'apostrophe:basics',
        fields: [
          'attachment',
          'title',
          'alt',
          '_tags',
          'credit',
          'creditUrl',
          'slug',
          'archived'
        ]
      }
    }
  },
  filters: {
    remove: [ 'visibility' ],
    add: {
      _tags: {
        label: 'apostrophe:tags'
      }
    }
  },
  extendRestApiRoutes: (self) => ({
    async getAll (_super, req) {
      const pieces = await _super(req);

      self.apos.attachment.all(pieces, {
        annotate: true
      });

      return pieces;
    }
  }),
  apiRoutes: (self) => ({
    post: {
      async autocrop(req) {
        if (!self.apos.permission.can(req, 'upload-attachment')) {
          throw self.apos.error('forbidden');
        }
        const widgetOptions = sanitizeOptions(req.body.widgetOptions);
        if (!widgetOptions.aspectRatio) {
          return {
            // This is OK because there will be further sanitization
            // when we actually save the relationship. At this stage
            // we only need to sanitize if we're going to autocrop
            relationship: req.body.relationship
          };
        }
        const relationship = await sanitizeRelationship(req.body.relationship);
        for (const image of relationship) {
          if (!closeEnough(image)) {
            await autocrop(image, widgetOptions);
          }
        }
        return {
          relationship
        };

        async function sanitizeRelationship(input) {
          const output = [];
          if (!Array.isArray(input)) {
            return output;
          }
          for (const inputImage of input) {
            const outputImage = await sanitizeImage(inputImage);
            if (!outputImage) {
              continue;
            }
            outputImage._fields = sanitizeFields(inputImage._fields);
            output.push(outputImage);
          }
          return output;
        }
        function sanitizeOptions(input) {
          if (input == null) {
            return {};
          }
          if ((typeof input) !== 'object') {
            return {};
          }
          if (!input.aspectRatio) {
            return {};
          }
          if (!Array.isArray(input.aspectRatio)) {
            return {};
          }
          const w = self.apos.launder.float(input.aspectRatio[0], 0);
          const h = self.apos.launder.float(input.aspectRatio[1], 0);
          if ((w <= 0) || (h <= 0)) {
            return {};
          }
          return {
            aspectRatio: [ w, h ]
          };
        }
        function sanitizeFields(input) {
          const output = {};
          if ((input == null) || ((typeof input) !== 'object')) {
            return output;
          }
          const props = [ 'top', 'left', 'width', 'height', 'x', 'y' ];
          for (const prop of props) {
            if ((typeof input[prop]) === 'number') {
              output[prop] = self.apos.launder.integer(input[prop]);
              if (output[prop] < 0) {
                return {};
              }
            }
          }
          const mandatory = [ 'top', 'left', 'width', 'height' ];
          for (const prop of mandatory) {
            if (!_.has(output, prop)) {
              return {};
            }
          }
          if (output.width === 0) {
            return {};
          }
          if (output.height === 0) {
            return {};
          }
          return output;
        }
        function sanitizeImage(input) {
          if (!input) {
            return null;
          }
          return self.find(req, {
            _id: self.apos.launder.id(input._id)
          }).toObject();
        }
        function closeEnough(image) {
          if (!image._fields) {
            return false;
          }
          const ratio = image.attachment.width / image.attachment.height;
          const configuredRatio = widgetOptions.aspectRatio[0] / widgetOptions.aspectRatio[1];
          return withinOnePercent(ratio, configuredRatio);
        }
        async function autocrop(image, widgetOptions) {
          const nativeRatio = image.attachment.width / image.attachment.height;
          const configuredRatio = widgetOptions.aspectRatio[0] / widgetOptions.aspectRatio[1];
          let crop;
          if (configuredRatio >= nativeRatio) {
            const height = image.attachment.width / configuredRatio;
            crop = {
              top: Math.floor((image.attachment.height - height) / 2),
              left: 0,
              width: image.attachment.width,
              height: Math.floor(height)
            };
          } else {
            const width = image.attachment.height * configuredRatio;
            crop = {
              top: 0,
              left: Math.floor((image.attachment.width - width) / 2),
              width: Math.floor(width),
              height: image.attachment.height
            };
          }
          await self.apos.attachment.crop(req, image.attachment._id, crop);
          image._fields = crop;
          // For ease of testing send back the cropped image URLs now
          image._crop = crop;
          await self.all(image, {
            crop,
            annotate: true
          });
        }
        // Compare two ratios and decide if they are within 1% of the
        // largest of the two
        function withinOnePercent(a, b) {
          const max = Math.max(a, b);
          a = a * 100 / max;
          b = b * 100 / max;
          return Math.abs(a - b) < 1;
        }
      }
    }
  }),
  methods(self) {
    return {
      // This method is available as a template helper: apos.image.first
      //
      // Find the first image attachment referenced within an object that may have attachments
      // as properties or sub-properties.
      //
      // For best performance be reasonably specific; don't pass an entire page or piece
      // object if you can pass page.thumbnail to avoid an exhaustive search, especially
      // if the page has many relationships.
      //
      // For ease of use, a null or undefined `within` argument is accepted.
      //
      // Note that this method doesn't actually care if the attachment is part of
      // an `@apostrophecms/image` piece or not. It simply checks whether the `group`
      // property is set to `images`.
      //
      // Examples:
      //
      // 1. First image in the body area please
      //
      // apos.image.first(page.body)
      //
      // 2. Must be a GIF
      //
      // apos.image.first(page.body, { extension: 'gif' })
      //
      // (Note Apostrophe always uses .jpg for JPEGs.)
      //
      // OPTIONS:
      //
      // You may specify `extension` or `extensions` (an array of extensions)
      // to filter the results.
      first(within, options) {
        options = options ? _.clone(options) : {};
        options.group = 'images';
        const result = self.apos.attachment.first(within, options);
        return result;
      },
      // This method is available as a template helper: apos.image.all
      //
      // Find all image attachments referenced within an object that may have attachments
      // as properties or sub-properties.
      //
      // For best performance be reasonably specific; don't pass an entire page or piece
      // object if you can pass page.thumbnail to avoid an exhaustive search, especially
      // if the page has many relationships.
      //
      // When available, the `_description`, `_credit` and `_creditUrl` are
      // also returned as part of the object.
      //
      // For ease of use, a null or undefined `within` argument is accepted.
      //
      // Note that this method doesn't actually care if the attachment is part of
      // an `@apostrophecms/image` piece or not. It simply checks whether the `group`
      // property is set to `images`.
      //
      // Examples:
      //
      // 1. All images in the body area please
      //
      // apos.image.all(page.body)
      //
      // 2. Must be GIFs
      //
      // apos.image.all(page.body, { extension: 'gif' })
      //
      // (Note Apostrophe always uses .jpg for JPEGs.)
      //
      // OPTIONS:
      //
      // You may specify `extension` or `extensions` (an array of extensions)
      // to filter the results.
      all(within, options) {
        options = options ? _.clone(options) : {};
        options.group = 'images';
        return self.apos.attachment.all(within, options);
      },
      // This method is available as a template helper: apos.image.srcset
      //
      // Given an image attachment, return a string that can be used as the value
      // of a `srcset` HTML attribute.
      srcset(attachment, cropFields) {
        if (!self.apos.attachment.isSized(attachment)) {
          return '';
        }
        // Since images are never scaled up once uploaded, we only need to
        // include a single image size that's larger than the original image
        // (if such an image size exists) to cover as many bases as possible
        let includedOriginalWidth = false;
        const sources = self.apos.attachment.imageSizes.filter(function (imageSize) {
          if (imageSize.width < attachment.width) {
            return true;
          } else if (!includedOriginalWidth) {
            includedOriginalWidth = true;
            return true;
          } else {
            return false;
          }
        }).map(function (imageSize) {
          const src = self.apos.attachment.url(attachment, {
            size: imageSize.name,
            crop: cropFields
          });
          const width = Math.min(imageSize.width, attachment.width);
          return src + ' ' + width + 'w';
        });
        return sources.join(', ');
      },
      isCroppable(image) {
        return image && self.apos.attachment.isCroppable(image.attachment);
      },
      // Make the minimum size, if any, accessible to the templates
      afterList(req, results) {
        if (req.body.minSize) {
          results.minSize = [
            self.apos.launder.integer(req.body.minSize[0]),
            self.apos.launder.integer(req.body.minSize[1])
          ];
        }
      },
      addManagerModal() {
        self.apos.modal.add(
          `${self.__meta.name}:manager`,
          self.getComponentName('managerModal', 'AposMediaManager'),
          { moduleName: self.__meta.name }
        );
      }
    };
  },
  extendMethods(self) {
    return {
      getBrowserData(_super, req) {
        const data = _super(req);
        data.components.managerModal = 'AposMediaManager';
        return data;
      }
    };
  },
  helpers: [
    'first',
    'all',
    'srcset',
    'isCroppable'
  ],
  queries(self, query) {
    return {
      builders: {
        minSize: {
          finalize() {
            const minSize = query.get('minSize');
            if (!minSize) {
              return;
            }
            const $nin = Object.keys(self.apos.attachment.sized).filter(key => self.apos.attachment.sized[key]);
            const criteria = {
              $or: [
                {
                  'attachment.extension': { $nin: $nin }
                },
                {
                  'attachment.width': { $gte: minSize[0] },
                  'attachment.height': { $gte: minSize[1] }
                }
              ]
            };
            query.and(criteria);
          },
          launder(a) {
            if (!Array.isArray(a)) {
              return undefined;
            }
            if (a.length !== 2) {
              return undefined;
            }
            return [ self.apos.launder.integer(a[0]), self.apos.launder.integer(a[1]) ];
          }
        }
      }
    };
  }
};
<commit_msg>* Handle the case where the attachment was replaced with one that is not compatible with the crop (eventually we will want to work on more sophisticated invalidation of crops via backlinks, this isn't really enough but we're past what we had in 2.x) * The aspect ratio to compare to is that of the previous crop, unless there isn't one<commit_after>const _ = require('lodash');

// A subclass of `@apostrophecms/piece-type`, `@apostrophecms/image` establishes a library
// of uploaded images in formats suitable for use on the web.
//
// Together with [@apostrophecms/image-widget](../@apostrophecms/image-widget/index.html),
// this module provides a simple way to add downloadable PDFs and the like to
// a website, and to manage a library of them for reuse.
//
// Each `@apostrophecms/image` doc has an `attachment` schema field, implemented
// by the [@apostrophecms/attachment](../@apostrophecms/attachment/index.html) module.

module.exports = {
  extend: '@apostrophecms/piece-type',
  options: {
    name: '@apostrophecms/image',
    label: 'apostrophe:image',
    pluralLabel: 'apostrophe:images',
    alias: 'image',
    perPage: 31,
    sort: { createdAt: -1 },
    quickCreate: false,
    insertViaUpload: true,
    searchable: false,
    slugPrefix: 'image-',
    autopublish: true,
    editRole: 'editor',
    publishRole: 'editor',
    showPermissions: true,
    // Images should by default be considered "related documents" when localizing
    // another document that references them
    relatedDocument: true,
    relationshipEditor: 'AposImageRelationshipEditor',
    relationshipFields: {
      add: {
        top: {
          type: 'integer'
        },
        left: {
          type: 'integer'
        },
        width: {
          type: 'integer'
        },
        height: {
          type: 'integer'
        },
        x: {
          type: 'integer'
        },
        y: {
          type: 'integer'
        }
      }
    },
    relationshipPostprocessor: 'autocrop'
  },
  fields: {
    remove: [ 'visibility' ],
    add: {
      slug: {
        type: 'slug',
        label: 'apostrophe:slug',
        prefix: 'image',
        required: true,
        following: [ 'title', 'archived' ]
      },
      attachment: {
        type: 'attachment',
        label: 'apostrophe:imageFile',
        fileGroup: 'images',
        required: true
      },
      alt: {
        type: 'string',
        label: 'apostrophe:altText',
        help: 'apostrophe:altTextHelp'
      },
      credit: {
        type: 'string',
        label: 'apostrophe:credit'
      },
      creditUrl: {
        type: 'url',
        label: 'apostrophe:creditUrl'
      },
      _tags: {
        type: 'relationship',
        label: 'apostrophe:tags',
        withType: '@apostrophecms/image-tag',
        modifiers: [ 'no-search' ]
      }
    },
    group: {
      // The image editor has only one group.
      basics: {
        label: 'apostrophe:basics',
        fields: [
          'attachment',
          'title',
          'alt',
          '_tags',
          'credit',
          'creditUrl',
          'slug',
          'archived'
        ]
      }
    }
  },
  filters: {
    remove: [ 'visibility' ],
    add: {
      _tags: {
        label: 'apostrophe:tags'
      }
    }
  },
  extendRestApiRoutes: (self) => ({
    async getAll (_super, req) {
      const pieces = await _super(req);

      self.apos.attachment.all(pieces, {
        annotate: true
      });

      return pieces;
    }
  }),
  apiRoutes: (self) => ({
    post: {
      async autocrop(req) {
        if (!self.apos.permission.can(req, 'upload-attachment')) {
          throw self.apos.error('forbidden');
        }
        const widgetOptions = sanitizeOptions(req.body.widgetOptions);
        if (!widgetOptions.aspectRatio) {
          return {
            // This is OK because there will be further sanitization
            // when we actually save the relationship. At this stage
            // we only need to sanitize if we're going to autocrop
            relationship: req.body.relationship
          };
        }
        const relationship = await sanitizeRelationship(req.body.relationship);
        for (const image of relationship) {
          if (!closeEnough(image)) {
            await autocrop(image, widgetOptions);
          }
        }
        return {
          relationship
        };

        async function sanitizeRelationship(input) {
          const output = [];
          if (!Array.isArray(input)) {
            return output;
          }
          for (const inputImage of input) {
            const outputImage = await sanitizeImage(inputImage);
            if (!outputImage) {
              continue;
            }
            outputImage._fields = sanitizeFields(inputImage);
            output.push(outputImage);
          }
          return output;
        }
        function sanitizeOptions(input) {
          if (input == null) {
            return {};
          }
          if ((typeof input) !== 'object') {
            return {};
          }
          if (!input.aspectRatio) {
            return {};
          }
          if (!Array.isArray(input.aspectRatio)) {
            return {};
          }
          const w = self.apos.launder.float(input.aspectRatio[0], 0);
          const h = self.apos.launder.float(input.aspectRatio[1], 0);
          if ((w <= 0) || (h <= 0)) {
            return {};
          }
          return {
            aspectRatio: [ w, h ]
          };
        }
        function sanitizeFields(inputImage) {
          const input = inputImage._fields;
          const output = {};
          if ((input == null) || ((typeof input) !== 'object')) {
            return output;
          }
          const props = [ 'top', 'left', 'width', 'height', 'x', 'y' ];
          for (const prop of props) {
            if ((typeof input[prop]) === 'number') {
              output[prop] = self.apos.launder.integer(input[prop]);
              if (output[prop] < 0) {
                return {};
              }
            }
          }
          const mandatory = [ 'top', 'left', 'width', 'height' ];
          for (const prop of mandatory) {
            if (!_.has(output, prop)) {
              return {};
            }
          }
          if (output.width === 0) {
            return {};
          }
          if (output.height === 0) {
            return {};
          }
          if (output.left + output.width > inputImage.attachment.width) {
            // An older crop that does not work with a new attachment file
            return {};
          }
          if (output.top + output.height > inputImage.attachment.height) {
            // An older crop that does not work with a new attachment file
            return {};
          }
          return output;
        }
        function sanitizeImage(input) {
          if (!input) {
            return null;
          }
          return self.find(req, {
            _id: self.apos.launder.id(input._id)
          }).toObject();
        }
        function closeEnough(image) {
          const testRatio = image._fields ? (image._fields.width / image._fields.height) :
            (image.attachment.width / image.attachment.height);
          const configuredRatio = widgetOptions.aspectRatio[0] / widgetOptions.aspectRatio[1];
          return withinOnePercent(testRatio, configuredRatio);
        }
        async function autocrop(image, widgetOptions) {
          const nativeRatio = image.attachment.width / image.attachment.height;
          const configuredRatio = widgetOptions.aspectRatio[0] / widgetOptions.aspectRatio[1];
          let crop;
          if (configuredRatio >= nativeRatio) {
            const height = image.attachment.width / configuredRatio;
            crop = {
              top: Math.floor((image.attachment.height - height) / 2),
              left: 0,
              width: image.attachment.width,
              height: Math.floor(height)
            };
          } else {
            const width = image.attachment.height * configuredRatio;
            crop = {
              top: 0,
              left: Math.floor((image.attachment.width - width) / 2),
              width: Math.floor(width),
              height: image.attachment.height
            };
          }
          await self.apos.attachment.crop(req, image.attachment._id, crop);
          image._fields = crop;
          // For ease of testing send back the cropped image URLs now
          image._crop = crop;
          await self.all(image, {
            crop,
            annotate: true
          });
        }
        // Compare two ratios and decide if they are within 1% of the
        // largest of the two
        function withinOnePercent(a, b) {
          const max = Math.max(a, b);
          a = a * 100 / max;
          b = b * 100 / max;
          return Math.abs(a - b) < 1;
        }
      }
    }
  }),
  methods(self) {
    return {
      // This method is available as a template helper: apos.image.first
      //
      // Find the first image attachment referenced within an object that may have attachments
      // as properties or sub-properties.
      //
      // For best performance be reasonably specific; don't pass an entire page or piece
      // object if you can pass page.thumbnail to avoid an exhaustive search, especially
      // if the page has many relationships.
      //
      // For ease of use, a null or undefined `within` argument is accepted.
      //
      // Note that this method doesn't actually care if the attachment is part of
      // an `@apostrophecms/image` piece or not. It simply checks whether the `group`
      // property is set to `images`.
      //
      // Examples:
      //
      // 1. First image in the body area please
      //
      // apos.image.first(page.body)
      //
      // 2. Must be a GIF
      //
      // apos.image.first(page.body, { extension: 'gif' })
      //
      // (Note Apostrophe always uses .jpg for JPEGs.)
      //
      // OPTIONS:
      //
      // You may specify `extension` or `extensions` (an array of extensions)
      // to filter the results.
      first(within, options) {
        options = options ? _.clone(options) : {};
        options.group = 'images';
        const result = self.apos.attachment.first(within, options);
        return result;
      },
      // This method is available as a template helper: apos.image.all
      //
      // Find all image attachments referenced within an object that may have attachments
      // as properties or sub-properties.
      //
      // For best performance be reasonably specific; don't pass an entire page or piece
      // object if you can pass page.thumbnail to avoid an exhaustive search, especially
      // if the page has many relationships.
      //
      // When available, the `_description`, `_credit` and `_creditUrl` are
      // also returned as part of the object.
      //
      // For ease of use, a null or undefined `within` argument is accepted.
      //
      // Note that this method doesn't actually care if the attachment is part of
      // an `@apostrophecms/image` piece or not. It simply checks whether the `group`
      // property is set to `images`.
      //
      // Examples:
      //
      // 1. All images in the body area please
      //
      // apos.image.all(page.body)
      //
      // 2. Must be GIFs
      //
      // apos.image.all(page.body, { extension: 'gif' })
      //
      // (Note Apostrophe always uses .jpg for JPEGs.)
      //
      // OPTIONS:
      //
      // You may specify `extension` or `extensions` (an array of extensions)
      // to filter the results.
      all(within, options) {
        options = options ? _.clone(options) : {};
        options.group = 'images';
        return self.apos.attachment.all(within, options);
      },
      // This method is available as a template helper: apos.image.srcset
      //
      // Given an image attachment, return a string that can be used as the value
      // of a `srcset` HTML attribute.
      srcset(attachment, cropFields) {
        if (!self.apos.attachment.isSized(attachment)) {
          return '';
        }
        // Since images are never scaled up once uploaded, we only need to
        // include a single image size that's larger than the original image
        // (if such an image size exists) to cover as many bases as possible
        let includedOriginalWidth = false;
        const sources = self.apos.attachment.imageSizes.filter(function (imageSize) {
          if (imageSize.width < attachment.width) {
            return true;
          } else if (!includedOriginalWidth) {
            includedOriginalWidth = true;
            return true;
          } else {
            return false;
          }
        }).map(function (imageSize) {
          const src = self.apos.attachment.url(attachment, {
            size: imageSize.name,
            crop: cropFields
          });
          const width = Math.min(imageSize.width, attachment.width);
          return src + ' ' + width + 'w';
        });
        return sources.join(', ');
      },
      isCroppable(image) {
        return image && self.apos.attachment.isCroppable(image.attachment);
      },
      // Make the minimum size, if any, accessible to the templates
      afterList(req, results) {
        if (req.body.minSize) {
          results.minSize = [
            self.apos.launder.integer(req.body.minSize[0]),
            self.apos.launder.integer(req.body.minSize[1])
          ];
        }
      },
      addManagerModal() {
        self.apos.modal.add(
          `${self.__meta.name}:manager`,
          self.getComponentName('managerModal', 'AposMediaManager'),
          { moduleName: self.__meta.name }
        );
      }
    };
  },
  extendMethods(self) {
    return {
      getBrowserData(_super, req) {
        const data = _super(req);
        data.components.managerModal = 'AposMediaManager';
        return data;
      }
    };
  },
  helpers: [
    'first',
    'all',
    'srcset',
    'isCroppable'
  ],
  queries(self, query) {
    return {
      builders: {
        minSize: {
          finalize() {
            const minSize = query.get('minSize');
            if (!minSize) {
              return;
            }
            const $nin = Object.keys(self.apos.attachment.sized).filter(key => self.apos.attachment.sized[key]);
            const criteria = {
              $or: [
                {
                  'attachment.extension': { $nin: $nin }
                },
                {
                  'attachment.width': { $gte: minSize[0] },
                  'attachment.height': { $gte: minSize[1] }
                }
              ]
            };
            query.and(criteria);
          },
          launder(a) {
            if (!Array.isArray(a)) {
              return undefined;
            }
            if (a.length !== 2) {
              return undefined;
            }
            return [ self.apos.launder.integer(a[0]), self.apos.launder.integer(a[1]) ];
          }
        }
      }
    };
  }
};
<|endoftext|>


<commit_before>/*globals THREE, requestAnimationFrame*/
(function( window, document, undefined ) {
  'use strict';

  var TAU = 2 * Math.PI;

  var container;

  var scene, camera, renderer;

  // Hyperbolic trigonometric functions.
  // Cached Math.exp(x) is significantly less accurate.
  var cosh = Math.cosh || function cosh( x ) {
    return ( Math.exp( x ) + Math.exp( -x ) ) / 2;
  };

  var sinh = Math.sinh || function sinh( x ){
    return ( Math.exp( x ) - Math.exp( -x ) ) / 2;
  };

  // Trigonometric functions with complex arguments.
  function sini( real, imag ) {
    return {
      real: Math.sin( real ) * cosh( imag ),
      imag: Math.cos( real ) * sinh( imag )
    };
  }

  function cosi( real, imag ) {
    return {
      real:  Math.cos( real ) * cosh( imag ),
      imag: -Math.sin( real ) * sinh( imag )
    };
  }

  /**
   * The phase factor function s(k, n) is defined as:
   *
   *   s(k, n) = exp(2PIik / n)
   *
   * We use Euler's formula to calculate the complex exponential function:
   *
   *   e^ix = cos(x) + i * sin(x)
   *
   * This phase factor represents the nth root of unity for integers
   * 0 <= k <= n - 1.
   */
  function phaseFactor( k, n ) {
    var x = ( TAU * k ) / n;

    return {
      real: Math.cos( x ),
      imag: Math.sin( x )
    };
  }

  /**
   * Multiply two complex numbers together (by components).
   *
   *   (a + bi)(c + di) = (ac - bd) + (ad + bc)i
   *
   * This is a 2D rotation in the complex plane:
   *
   *   x * cos - y * sin
   *   x * sin + y * cos
   */
  function muli( r0, i0, r1, i1 ) {
    return {
      real: r0 * r1 - i0 * i1,
      imag: r0 * i1 + i0 * r1
    };
  }

  /**
   * Calculate values where:
   *
   *   z0^n + z1^n = 1
   *
   * And:
   *
   *   z0k = exp(2PIik / n) * cosh(a, b)^(2 / n)
   *   z1k = exp(2PIik / n) * sinh(a, b)^(2 / n)
   */
  function z0k( r, i, n, k ) {
    var phase = phaseFactor( k, n );
    var amplitude = Math.pow( cosh( r, i ), 2 / n );

    phase.real *= amplitude;
    phase.imag *= amplitude;

    return phase;
  }

  function z1k( r, i, n, k ) {
    var phase = phaseFactor( k, n );
    var amplitude = Math.pow( cosh( r, i ), 2 / n );

    phase.real *= amplitude;
    phase.imag *= amplitude;

    return phase;
  }

  function init() {
    container = document.createElement( 'div' );
    document.body.appendChild( container );

    renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    container.appendChild( renderer.domElement );

    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
  }

  function animate() {
    renderer.render( scene, camera );
    requestAnimationFrame( animate );
  }

  init();
  animate();

}) ( window, document );
<commit_msg>manifolds: Add Calabi-Yau data generation.<commit_after>/*globals THREE, requestAnimationFrame*/
(function( window, document, undefined ) {
  'use strict';

  var TAU = 2 * Math.PI;

  var container;

  var scene, camera, renderer;

  // Hyperbolic trigonometric functions.
  // Cached Math.exp(x) is significantly less accurate.
  var cosh = Math.cosh || function cosh( x ) {
    return ( Math.exp( x ) + Math.exp( -x ) ) / 2;
  };

  var sinh = Math.sinh || function sinh( x ){
    return ( Math.exp( x ) - Math.exp( -x ) ) / 2;
  };

  // Trigonometric functions with complex arguments.
  function sini( real, imag ) {
    return {
      real: Math.sin( real ) * cosh( imag ),
      imag: Math.cos( real ) * sinh( imag )
    };
  }

  function cosi( real, imag ) {
    return {
      real:  Math.cos( real ) * cosh( imag ),
      imag: -Math.sin( real ) * sinh( imag )
    };
  }

  /**
   * The phase factor function s(k, n) is defined as:
   *
   *   s(k, n) = exp(2PIik / n)
   *
   * We use Euler's formula to calculate the complex exponential function:
   *
   *   e^ix = cos(x) + i * sin(x)
   *
   * This phase factor represents the nth root of unity for integers
   * 0 <= k <= n - 1.
   */
  function phaseFactor( k, n ) {
    var x = ( TAU * k ) / n;

    return {
      real: Math.cos( x ),
      imag: Math.sin( x )
    };
  }

  /**
   * Multiply two complex numbers together (by components).
   *
   *   (a + bi)(c + di) = (ac - bd) + (ad + bc)i
   *
   * This is a 2D rotation in the complex plane:
   *
   *   x * cos - y * sin
   *   x * sin + y * cos
   */
  function muli( r0, i0, r1, i1 ) {
    return {
      real: r0 * r1 - i0 * i1,
      imag: r0 * i1 + i0 * r1
    };
  }

  /**
   * Calculate values where:
   *
   *   z0^n + z1^n = 1
   *
   * And:
   *
   *   z0k(a, b, n, k) = exp(2PIik / n) * cosh(a, b)^(2 / n)
   *   z1k(a, b, n, k) = exp(2PIik / n) * sinh(a, b)^(2 / n)
   */
  function z0k( r, i, n, k ) {
    var phase = phaseFactor( k, n );
    var amplitude = Math.pow( cosh( r, i ), 2 / n );

    phase.real *= amplitude;
    phase.imag *= amplitude;

    return phase;
  }

  function z1k( r, i, n, k ) {
    var phase = phaseFactor( k, n );
    var amplitude = Math.pow( sinh( r, i ), 2 / n );

    phase.real *= amplitude;
    phase.imag *= amplitude;

    return phase;
  }

  function calabi( n, alpha, count, rmin, rmax ) {
    var cos = Math.cos( alpha ),
        sin = Math.sin( alpha );

    var dr = ( rmax - rmin ) / ( count - 1 ),
        di = ( 0.5 * Math.PI ) / ( count - 1 );

    var data = new Float32Array( 3 * n * n * count * count );
    var k0, k1;
    var r, i;
    var ir, ii;
    var z0, z1;
    var index = 0;
    for ( k0 = 0; k0 < n; k0++ ) {
      for ( k1 = 0; k1 < n; k1++ ) {
        for ( ir = 0; ir < count; ir++ ) {
          r = rmin + ir * dr;

          for ( ii = 0; ii < count; ii++ ) {
            i = ii * di;

            z0 = z0k( r, i, n, k0 );
            z1 = z1k( r, i, n, k1 );

            data[ index++ ] = z0.real;
            data[ index++ ] = z1.real;
            data[ index++ ] = cos * z0.imag + sin * z1.imag;
          }
        }
      }
    }

    return data;
  }

  function init() {
    container = document.createElement( 'div' );
    document.body.appendChild( container );

    renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    container.appendChild( renderer.domElement );

    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
  }

  function animate() {
    renderer.render( scene, camera );
    requestAnimationFrame( animate );
  }

  init();
  animate();

}) ( window, document );
<|endoftext|>


<commit_before>/* global APP, config, $, interfaceConfig */

import UIUtil from '../util/UIUtil';
import Toolbar from './Toolbar';
import SideContainerToggler from "../side_pannels/SideContainerToggler";
import FilmStrip from '../videolayout/FilmStrip.js';

let toolbarTimeoutObject;
let toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT;
/**
 * If true the toolbar will be always displayed
 */
let alwaysVisibleToolbar = false;

function showDesktopSharingButton() {
    if (APP.conference.isDesktopSharingEnabled &&
        UIUtil.isButtonEnabled('desktop')) {
        $('#toolbar_button_desktopsharing').css({display: "inline-block"});
    } else {
        $('#toolbar_button_desktopsharing').css({display: "none"});
    }
}

/**
 * Hides the toolbar.
 *
 * @param force {true} to force the hiding of the toolbar without caring about
 * the extended toolbar side panels.
 */
function hideToolbar(force) {
    if (alwaysVisibleToolbar) {
        return;
    }

    clearTimeout(toolbarTimeoutObject);
    toolbarTimeoutObject = null;

    if (Toolbar.isHovered() || APP.UI.isRingOverlayVisible()) {
        toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
    } else if (!SideContainerToggler.isVisible() || force) {
        Toolbar.hide();
        $('#subject').animate({top: "-=40"}, 300);
    }
}

const ToolbarToggler = {
    /**
     * Initializes the ToolbarToggler
     */
    init() {
        alwaysVisibleToolbar = (config.alwaysVisibleToolbar === true);

        this._registerWindowClickListeners();
    },

    /**
     * Registers click listeners handling the show and hode of toolbars when
     * user clicks outside of toolbar area.
     */
    _registerWindowClickListeners() {
        $(window).click(function() {
            (Toolbar.isEnabled() && Toolbar.isVisible())
                ? hideToolbar(true)
                : this.showToolbar();
        }.bind(this));

        Toolbar.registerClickListeners(function(event){
            event.stopPropagation();
        });
    },

    /**
     * Sets the value of alwaysVisibleToolbar variable.
     * @param value {boolean} the new value of alwaysVisibleToolbar variable
     */
    setAlwaysVisibleToolbar(value) {
        alwaysVisibleToolbar = value;
    },

    /**
     * Resets the value of alwaysVisibleToolbar variable to the default one.
     */
    resetAlwaysVisibleToolbar() {
        alwaysVisibleToolbar = (config.alwaysVisibleToolbar === true);
    },

    /**
     * Shows the main toolbar.
     */
    showToolbar () {
        if (interfaceConfig.filmStripOnly) {
            return;
        }

        var updateTimeout = false;
        if (Toolbar.isEnabled() && !Toolbar.isVisible()) {
            Toolbar.show();
            $('#subject').animate({top: "+=40"}, 300);
            updateTimeout = true;
        }

        if (updateTimeout) {
            if (toolbarTimeoutObject) {
                clearTimeout(toolbarTimeoutObject);
                toolbarTimeoutObject = null;
            }
            toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
            toolbarTimeout = interfaceConfig.TOOLBAR_TIMEOUT;
        }

        // Show/hide desktop sharing button
        showDesktopSharingButton();
    },

    /**
     * Docks/undocks the toolbar.
     *
     * @param isDock indicates what operation to perform
     */
    dockToolbar (isDock) {
        if (interfaceConfig.filmStripOnly || !Toolbar.isEnabled()) {
            return;
        }

        if (isDock) {
            // First make sure the toolbar is shown.
            if (!Toolbar.isVisible()) {
                this.showToolbar();
            }

            // Then clear the time out, to dock the toolbar.
            clearTimeout(toolbarTimeoutObject);
            toolbarTimeoutObject = null;
        } else {
            if (Toolbar.isVisible()) {
                toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
            } else {
                this.showToolbar();
            }
        }
    }
};

module.exports = ToolbarToggler;
<commit_msg>Disables click toggler.<commit_after>/* global APP, config, $, interfaceConfig */

import UIUtil from '../util/UIUtil';
import Toolbar from './Toolbar';
import SideContainerToggler from "../side_pannels/SideContainerToggler";
import FilmStrip from '../videolayout/FilmStrip.js';

let toolbarTimeoutObject;
let toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT;
/**
 * If true the toolbar will be always displayed
 */
let alwaysVisibleToolbar = false;

function showDesktopSharingButton() {
    if (APP.conference.isDesktopSharingEnabled &&
        UIUtil.isButtonEnabled('desktop')) {
        $('#toolbar_button_desktopsharing').css({display: "inline-block"});
    } else {
        $('#toolbar_button_desktopsharing').css({display: "none"});
    }
}

/**
 * Hides the toolbar.
 *
 * @param force {true} to force the hiding of the toolbar without caring about
 * the extended toolbar side panels.
 */
function hideToolbar(force) {
    if (alwaysVisibleToolbar) {
        return;
    }

    clearTimeout(toolbarTimeoutObject);
    toolbarTimeoutObject = null;

    if (Toolbar.isHovered() || APP.UI.isRingOverlayVisible()) {
        toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
    } else if (!SideContainerToggler.isVisible() || force) {
        Toolbar.hide();
        $('#subject').animate({top: "-=40"}, 300);
    }
}

const ToolbarToggler = {
    /**
     * Initializes the ToolbarToggler
     */
    init() {
        alwaysVisibleToolbar = (config.alwaysVisibleToolbar === true);

        // disabled
        //this._registerWindowClickListeners();
    },

    /**
     * Registers click listeners handling the show and hode of toolbars when
     * user clicks outside of toolbar area.
     */
    _registerWindowClickListeners() {
        $(window).click(function() {
            (Toolbar.isEnabled() && Toolbar.isVisible())
                ? hideToolbar(true)
                : this.showToolbar();
        }.bind(this));

        Toolbar.registerClickListeners(function(event){
            event.stopPropagation();
        });
    },

    /**
     * Sets the value of alwaysVisibleToolbar variable.
     * @param value {boolean} the new value of alwaysVisibleToolbar variable
     */
    setAlwaysVisibleToolbar(value) {
        alwaysVisibleToolbar = value;
    },

    /**
     * Resets the value of alwaysVisibleToolbar variable to the default one.
     */
    resetAlwaysVisibleToolbar() {
        alwaysVisibleToolbar = (config.alwaysVisibleToolbar === true);
    },

    /**
     * Shows the main toolbar.
     */
    showToolbar () {
        if (interfaceConfig.filmStripOnly) {
            return;
        }

        var updateTimeout = false;
        if (Toolbar.isEnabled() && !Toolbar.isVisible()) {
            Toolbar.show();
            $('#subject').animate({top: "+=40"}, 300);
            updateTimeout = true;
        }

        if (updateTimeout) {
            if (toolbarTimeoutObject) {
                clearTimeout(toolbarTimeoutObject);
                toolbarTimeoutObject = null;
            }
            toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
            toolbarTimeout = interfaceConfig.TOOLBAR_TIMEOUT;
        }

        // Show/hide desktop sharing button
        showDesktopSharingButton();
    },

    /**
     * Docks/undocks the toolbar.
     *
     * @param isDock indicates what operation to perform
     */
    dockToolbar (isDock) {
        if (interfaceConfig.filmStripOnly || !Toolbar.isEnabled()) {
            return;
        }

        if (isDock) {
            // First make sure the toolbar is shown.
            if (!Toolbar.isVisible()) {
                this.showToolbar();
            }

            // Then clear the time out, to dock the toolbar.
            clearTimeout(toolbarTimeoutObject);
            toolbarTimeoutObject = null;
        } else {
            if (Toolbar.isVisible()) {
                toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
            } else {
                this.showToolbar();
            }
        }
    }
};

module.exports = ToolbarToggler;
<|endoftext|>


<commit_before>import Promise from 'bluebird';
import fs from 'fs';
import path from 'path';
import url from 'url';
import configHelper from '../configHelper.js'

const add = (req, res) => {

  let body = req.body;
  console.log(JSON.parse(body["rules"]));

  saveTask(body.folderName, body.folderPath, body.taskName,
          body.taskDescription, body.matchAll, body.interval, JSON.parse(body.rules))
  .then(() => {
    return res.sendStatus(200);
  })
  .catch(err => {
    throw new Error(err);
  });

};

const get = (req, res) => {
  let urlParts = url.parse(req.url, true);
  let query = urlParts.query;
  if(!query || !query.folderName || !query.folderPath) {
    res.statusCode(400);
  } else {
    configHelper
    .getTasks(query.folderName, query.folderPath)
    .then(tasks =>
      tasks
      .map(task => ({"name": task.name, "description": task.description})))
    .then(tasks => res.send(JSON.stringify(tasks)));
  }
}

const saveTask = (folderName, folderPath, taskName, taskDescription, matchAll, interval, rules, cb) => {

  let task = {
    "name": taskName,
    "description": taskDescription,
    "matchAll": matchAll,
    "interval": parseInt(interval, 10),
    "rules": rules
  }

  configHelper.saveTask(folderName, folderPath, task);

}

module.exports = {
  add,
  get
};<commit_msg>change get api endpoint to serve more needs<commit_after>import Promise from 'bluebird';
import fs from 'fs';
import path from 'path';
import url from 'url';
import configHelper from '../configHelper.js'

const add = (req, res) => {

  let body = req.body;
  console.log(JSON.parse(body["rules"]));

  saveTask(body.folderName, body.folderPath, body.taskName,
          body.taskDescription, body.matchAll, body.interval, JSON.parse(body.rules))
  .then(() => {
    return res.sendStatus(200);
  })
  .catch(err => {
    throw new Error(err);
  });

};

const get = (req, res) => {
  let urlParts = url.parse(req.url, true);
  let query = urlParts.query;
  if(!query || !query.folderName || !query.folderPath) {
    res.statusCode(400);
  } else {
    configHelper
    .getTasks(query.folderName, query.folderPath, query.taskId)
    .then(tasks => res.send(JSON.stringify(tasks)));
  }
}

const saveTask = (folderName, folderPath, taskName, taskDescription, matchAll, interval, rules, cb) => {

  let task = {
    "name": taskName,
    "description": taskDescription,
    "matchAll": matchAll,
    "interval": parseInt(interval, 10),
    "rules": rules
  }

  configHelper.saveTask(folderName, folderPath, task);

}

module.exports = {
  add,
  get
};<|endoftext|>


<commit_before>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Dominik
// Date:      29.10.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

m_require('logger.js');

/**
 * @class
 *
 * The observable knows all observers, mainly views, and pushes updates if necessary.
 *
 */
M.Observable = M.Object.extend({

    /**
     * List that contains pairs of an observer with an observable. An observer is tightened to one
     * observable, but one observable can have multiple observers.
     *
     */
    bindingList: [],

    /**
     * Attach an observer to an observable.
     *
     * @param {String} observer The observer.
     * @param {String} observable The observable.
     */
    attach: function(observer, observable) {
        this.bindingList.push({
            observer: observer,
            observable: observable
        });
    },

    /**
     * Detach an observer from an observable.
     *
     * @param {String} observer The observer.
     * @param {String} observable The observable.
     */
    detach: function(observer, observable) {
        /* grep is a jQuery function that finds
         * elements in an array that satisfy a certain criteria.
         * It works on a copy so we have to assign the "cleaned"
         * array to our bindingList.
         */
        this.bindlingList = $.grep(this.bindlingList, function(value, index) {
                return value.observer !== observer;
        });
    }

});<commit_msg>Removed second parameter from detach-function<commit_after>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Dominik
// Date:      29.10.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

m_require('logger.js');

/**
 * @class
 *
 * The observable knows all observers, mainly views, and pushes updates if necessary.
 *
 */
M.Observable = M.Object.extend({

    /**
     * List that contains pairs of an observer with an observable. An observer is tightened to one
     * observable, but one observable can have multiple observers.
     *
     */
    bindingList: [],

    /**
     * Attach an observer to an observable.
     *
     * @param {String} observer The observer.
     * @param {String} observable The observable.
     */
    attach: function(observer, observable) {
        this.bindingList.push({
            observer: observer,
            observable: observable
        });
    },

    /**
     * Detach an observer from an observable.
     *
     * @param {String} observer The observer.
     */
    detach: function(observer) {
        /* grep is a jQuery function that finds
         * elements in an array that satisfy a certain criteria.
         * It works on a copy so we have to assign the "cleaned"
         * array to our bindingList.
         */
        this.bindlingList = $.grep(this.bindlingList, function(value, index) {
                return value.observer !== observer;
        });
    }

});<|endoftext|>


<commit_before>/* Magic Mirror
 * Module: MMM-Hello-Mirror
 *
 * By Mathias Kaniut
 * MIT Licensed
 */

Module.register("MMM-Hello-Mirror", {

	// Default module config.
    defaults: {
        language: "de",
        voice: "Deutsch Female",
        wakeUp: "Hallo (magischer) Spiegel",
        animationSpeed: 2000,
        debug: true,
        broadcastEvents: true
    },

	// Load required additional scripts
	getScripts: function() {
		return [
			'//cdnjs.cloudflare.com/ajax/libs/annyang/2.6.0/annyang.min.js',     // annyang! SpeechRecognition
			'http://code.responsivevoice.org/responsivevoice.js',                // ResponsiveVoice
			'moment.js'                                                          // Parse, validate, manipulate, and display dates in JavaScript
		];
	},

	// Define additional styles
	getStyles: function() {
		return [
			"font-awesome.css",
			this.file('css/MMM-Hello-Mirror.css')
		];
	},

	// Request translation files
	getTranslations: function() {
        return {
            en: "translations/en.json",
            de: "translations/de.json"
		};
	},

    textMessage: "",

	// Called when all modules are loaded an the system is ready to boot up
	start: function() {
		if (responsiveVoice) {
			responsiveVoice.setDefaultVoice(this.config.voice);
		}

		if (annyang) {
			// Set language for date object
			moment.locale(this.config.language);

			// Set the debug mode
			annyang.debug(this.config.debug);

			// Set the language of annyang
			annyang.setLanguage(this.config.language);

			// Define the commands
			var commands = {
				'Hallo (magischer) Spiegel *command': function(command) {
					Log.info('Voice command recognized in module ' + this.name + ': ' + command);
					if (this.config.broadcastEvents) {
						this.sendNotification("VOICE_COMMAND", command);
					}
					if (responsiveVoice) {
						responsiveVoice.speak( "Ich konnte dich verstehen" );
					}
                }
			};

			// Add the commands to annyang
  			annyang.addCommands(commands);

			// Add callback functions for errors
			annyang.addCallback('error', function() {
				Log.error('ERROR in module ' + this.name + ': ' + 'Speech Recognition fails because an undefined error occured');
			});
			annyang.addCallback('errorNetwork', function() {
		    		Log.error('ERROR in module ' + this.name + ': ' + 'Speech Recognition fails because of a network error');
			});
			annyang.addCallback('errorPermissionBlocked', function() {
		    		Log.error('ERROR in module ' + this.name + ': ' + 'Browser blocks the permission request to use Speech Recognition');
			});
			annyang.addCallback('errorPermissionDenied', function() {
		    		Log.error('ERROR in module ' + this.name + ': ' + 'The user blocks the permission request to use Speech Recognition');
			});
			annyang.addCallback('resultNoMatch', function(phrases) {
				Log.error('ERROR in module ' + this.name + ': ' + 'No match for voice command ' + phrases);
			});
			annyang.addCallback('soundstart', function() {
				this.textMessage = this.translate("HEAR_YOU");
  				this.updateDom(this.config.animationSpeed);
			});
			annyang.addCallback('result', function() {
				this.textMessage = "";
  				this.updateDom(this.config.animationSpeed);
			});

			// Start listening
			annyang.start();

			Log.log(this.name + ' is started!');
		} else {
			Log.error('ERROR in module ' + this.name + ': ' + 'Google Speech Recognizer is down :(');
		}
	},

    // Override dom generator.
    getDom: function() {
        var wrapper = document.createElement("div");
        wrapper.className = "small light";
        wrapper.innerHTML = this.textMessage;
        return wrapper;
    },
});
<commit_msg>Replace this with self<commit_after>/* Magic Mirror
 * Module: MMM-Hello-Mirror
 *
 * By Mathias Kaniut
 * MIT Licensed
 */

Module.register("MMM-Hello-Mirror", {

	// Default module config.
    defaults: {
        language: "de",
        voice: "Deutsch Female",
        wakeUp: "Hallo (magischer) Spiegel",
        animationSpeed: 2000,
        debug: true,
        broadcastEvents: true
    },

	// Load required additional scripts
	getScripts: function() {
		return [
			'//cdnjs.cloudflare.com/ajax/libs/annyang/2.6.0/annyang.min.js',     // annyang! SpeechRecognition
			'http://code.responsivevoice.org/responsivevoice.js',                // ResponsiveVoice
			'moment.js'                                                          // Parse, validate, manipulate, and display dates in JavaScript
		];
	},

	// Define additional styles
	getStyles: function() {
		return [
			"font-awesome.css",
			this.file('css/MMM-Hello-Mirror.css')
		];
	},

	// Request translation files
	getTranslations: function() {
        return {
            en: "translations/en.json",
            de: "translations/de.json"
		};
	},

    textMessage: "",

	// Called when all modules are loaded an the system is ready to boot up
	start: function() {
		if (responsiveVoice) {
			responsiveVoice.setDefaultVoice(this.config.voice);
		}

		if (annyang) {
            Log.info("Starting module: " + this.name);

            var self = this;

			// Set language for date object
			moment.locale(this.config.language);

			// Set the debug mode
			annyang.debug(this.config.debug);

			// Set the language of annyang
			annyang.setLanguage(this.config.language);

			// Define the commands
			var commands = {
				'Hallo (magischer) Spiegel *command': function(command) {
					Log.info('Voice command recognized in module ' + this.name + ': ' + command);
					if (this.config.broadcastEvents) {
						this.sendNotification("VOICE_COMMAND", command);
					}
					if (responsiveVoice) {
						responsiveVoice.speak( "Ich konnte dich verstehen" );
					}
                }
			};

			// Add the commands to annyang
  			annyang.addCommands(commands);

			// Add callback functions for errors
			annyang.addCallback('error', function() {
				Log.error('ERROR in module ' + this.name + ': ' + 'Speech Recognition fails because an undefined error occured');
			});
			annyang.addCallback('errorNetwork', function() {
		    		Log.error('ERROR in module ' + this.name + ': ' + 'Speech Recognition fails because of a network error');
			});
			annyang.addCallback('errorPermissionBlocked', function() {
		    		Log.error('ERROR in module ' + this.name + ': ' + 'Browser blocks the permission request to use Speech Recognition');
			});
			annyang.addCallback('errorPermissionDenied', function() {
		    		Log.error('ERROR in module ' + this.name + ': ' + 'The user blocks the permission request to use Speech Recognition');
			});
			annyang.addCallback('resultNoMatch', function(phrases) {
				Log.error('ERROR in module ' + this.name + ': ' + 'No match for voice command ' + phrases);
			});
			annyang.addCallback('soundstart', function() {
				this.textMessage = self.translate("HEAR_YOU");
  				this.updateDom(this.config.animationSpeed);
			});
			annyang.addCallback('result', function() {
				this.textMessage = "";
  				this.updateDom(this.config.animationSpeed);
			});

			// Start listening
			annyang.start();
		} else {
			Log.error('ERROR in module ' + this.name + ': ' + 'Google Speech Recognizer is down :(');
		}
	},

    // Override dom generator.
    getDom: function() {
        var wrapper = document.createElement("div");
        wrapper.className = "small light";
        wrapper.innerHTML = this.textMessage;
        return wrapper;
    },
});
<|endoftext|>