<commit_before>const querystring = require('querystring');
const formatError = require('../../lib/format-error');
const get = require('lodash/get');
const set = require('lodash/set');
const uuid = require('uuid');
const config = require('../../../config');

module.exports = (
  userService,
  emailService,
  renderTemplate,
  clientService,
  userFormData,
  oidcProvider,
  imageService
) => {
  const errorMessages = {
    email: {
      'any.required': 'Email address is required',
      'any.empty': 'Email address is required',
      'string.email': 'Must be a valid email address',
    },
    password: {
      'any.empty': 'Password is required',
      'string.min': 'Password must be at least 8 characters',
    },
    pass2: {
      'any.allowOnly': 'Passwords must match'
    },
    redirect_uri: {
      'any.required': 'Redirect URI is required',
    },
    client_id: {
      'any.required': 'Client ID is required'
    },
    response_type: {
      'any.required': 'Response type is required',
    },
    scope: {
      'any.required': 'Scope is required',
    },
    token: {
      'any.required': 'Token is required',
    },
    profile: {
      'string.uri': 'Must be a valid URL',
    },
    picture: {
      'string.uri': 'Must be a valid URL',
    },
    website: {
      'string.uri': 'Must be a valid URL',
    },
    birthdate: {
      'string.isoDate': 'Must be valid date in YYYY-MM-DD format'
    }
  };

  const handleRegistrationPost = function(request, reply) {
    userService.create(request.payload.email, request.payload.password)
      .then(user => {
        reply.redirect(`/op/auth?${querystring.stringify(request.query)}`);
      })
      .catch(error => {
        // assume email collision and show validation message
        reply.view('user-registration', {
          title: 'Sign Up',
          formAction: `/user/register?${querystring.stringify(request.query)}`,
          returnTo: `${request.query.redirect_uri}?status=cancelled`,
          error: true,
          validationErrorMessages: {email: ['That email address is already in use']},
          email: request.payload.email || ''
        });
      });
  };

  const getValidationMessages = function(error) {
    var validationErrorMessages = {};

    if (error) {
      error = formatError(error);
      error.output.payload.validationErrors.forEach(errorObj => {
        validationErrorMessages[errorObj.key] = validationErrorMessages[errorObj.key] || [];

        if (errorMessages[errorObj.key] && errorMessages[errorObj.key][errorObj.type]) {
          validationErrorMessages[errorObj.key].push(errorMessages[errorObj.key][errorObj.type]);
        } else if (errorObj.message) {
          validationErrorMessages[errorObj.key].push(errorObj.message);
        }
      });
    }

    return validationErrorMessages;
  };

  // e.g. convert { foo.bar: 'baz' } to { foo: { bar: 'baz' }}
  const expandDotPaths = function(object) {
    Object.keys(object).forEach(key => {
      if (key.indexOf('.') > -1) {
        const value = object[key];
        delete(object[key]);
        set(object, key, value);
      }
    });
    return object;
  };

  const getPasswordResetHandler = (method, title) => {
    if (method === 'GET') {
      return (request, reply, source, error) => {
        reply.view('reset-password', {
          title: title,
          returnTo: `${request.query.redirect_uri}?status=cancelled`,
          error: !!error,
          validationErrorMessages: getValidationMessages(error),
        });
      };
    } else if (method === 'POST') {
      return (request, reply) => {
        userService.findByPasswordToken(request.query.token)
        .then(user => {
          if (user) {
            return userService.encryptPassword(request.payload.password)
              .then(password => {
                const profile = user.get('profile');
                profile.email_verified = true;
                return userService.update(user.get('id'), { password, profile });
              })
              .then(() => userService.destroyPasswordToken(request.query.token))
              .then(() => reply.view(`reset-password-success`));
          } else {
            return reply.view('reset-password', {
              title: title,
              returnTo: `${request.query.redirect_uri}?status=cancelled`,
              error: true,
              validationErrorMessages: { token: ['Token is invalid or expired'] },
            });
          }
        });
      };
    }
  };

  const self = {
    registerFormHandler: function(request, reply, source, error) {
      request.payload = request.payload || {};

      if (!error && request.method === 'post') {
        handleRegistrationPost(request, reply);
      } else {
        reply.view('user-registration', {
          title: 'Sign Up',
          formAction: `/user/register?${querystring.stringify(request.query)}`,
          returnTo: `${request.query.redirect_uri}?status=cancelled`,
          error: !!error,
          validationErrorMessages: getValidationMessages(error),
          email: request.payload.email || ''
        });
      }
    },

    profileFormHandler: function(request, reply, source, error) {
      const accountId = request.auth.credentials.accountId;
      userService.findById(accountId).then(user => {
        if (!user) {
          return reply.redirect(`${request.query.redirect_uri}?error=user_not_found&error_description=user not found`);
        }

        let validationErrorMessages = {};
        if (!error && request.method === 'post') {
          const profile = user.get('profile');
          const payload = expandDotPaths(request.payload);

          const oldPicture = profile.picture;
          const pictureMIME = request.payload.picture.hapi.headers['content-type'];

          return new Promise((resolve, reject) => {
            if (pictureMIME === 'image/jpeg' || pictureMIME === 'image/png') {
              const filename = uuid();
              const bucket = filename.substring(0, 2);
              imageService.uploadImageStream(request.payload.picture, `pictures/${bucket}/${filename}`)
                .then(filename => {
                  resolve(Object.assign(profile, payload, { picture: filename }));
                })
                .catch(err => {
                  reject(err);
                });
            } else {
              delete request.payload.picture;
              resolve(Object.assign(profile, payload));
            }
          })
            .then(profile => userService.update(user.get('id'), { profile }))
            .then(() => {
              if (oldPicture) {
                imageService.deleteImage(oldPicture.replace(/^.*\/\/[^\/]+\//, ''));
              }
            })
            .then(() => reply.redirect(request.query.redirect_uri));
        } else if (error) {
          validationErrorMessages = getValidationMessages(error);
          if (validationErrorMessages.picture || validationErrorMessages['hapi.headers.content-type']) {
            validationErrorMessages.picture = ['Must be JPEG or PNG image less than 1MB'];
          }
        }

        const profile = user.get('profile');
        const getValue = (field) => {
          return (request.payload && request.payload[field]) || get(profile, field, '');
        };
        reply.view('user-profile', {
          returnTo: request.query.redirect_uri,
          title: 'User Profile',
          fields: [
            {
              name: 'name',
              label: 'Name',
              type: 'text',
              value: getValue('name'),
              error: validationErrorMessages.name,
            },
            {
              name: 'given_name',
              label: 'Given Name',
              type: 'text',
              value: getValue('given_name'),
              error: validationErrorMessages.given_name,
            },
            {
              name: 'family_name',
              label: 'Family Name',
              type: 'text',
              value: getValue('family_name'),
              error: validationErrorMessages.family_name,
            },
            {
              name: 'middle_name',
              label: 'Middle Name',
              type: 'text',
              value: getValue('middle_name'),
              error: validationErrorMessages.middle_name,
            },
            {
              name: 'nickname',
              label: 'Nickname',
              type: 'text',
              value: getValue('nickname'),
              error: validationErrorMessages.nickname,
            },
            {
              name: 'preferred_username',
              label: 'Preferred Username',
              type: 'text',
              value: getValue('preferred_username'),
              error: validationErrorMessages.preferred_username,
            },
            {
              name: 'profile',
              label: 'Profile',
              type: 'text',
              value: getValue('profile'),
              error: validationErrorMessages.profile,
            },
            {
              name: 'picture',
              label: 'Picture',
              isFile: true,
              accept: 'image/jpeg, image/png',
              value: getValue('picture'),
              error: validationErrorMessages.picture,
            },
            {
              name: 'website',
              label: 'Website',
              type: 'text',
              value: getValue('website'),
              error: validationErrorMessages.website,
            },
            {
              name: 'email',
              label: 'Email',
              type: 'text',
              value: getValue('email'),
              error: validationErrorMessages.email,
            },
            {
              name: 'gender',
              label: 'Gender',
              type: 'text',
              value: getValue('gender'),
              error: validationErrorMessages.gender,
            },
            {
              name: 'birthdate',
              label: 'Birthdate',
              type: 'text',
              value: getValue('birthdate'),
              error: validationErrorMessages.birthdate,
            },
            {
              name: 'zoneinfo',
              label: 'Timezone',
              isDropdown: true,
              options: userFormData.timezones.map(name => ({
                label: name,
                value: name,
                selected: getValue('zoneinfo') === name
              })),
              value: getValue('zoneinfo'),
              error: validationErrorMessages.zoneinfo,
            },
            {
              name: 'locale',
              label: 'Locale',
              isDropdown: true,
              options: Object.keys(userFormData.locales).map((value) => ({
                label: userFormData.locales[value],
                value,
                selected: getValue('locale') === value,
              })),
              value: getValue('locale'),
              error: validationErrorMessages.locale,
            },
            {
              name: 'phone_number',
              label: 'Phone Number',
              type: 'text',
              value: getValue('phone_number'),
              error: validationErrorMessages.phone_number,
            },
            {
              name: 'address.street_address',
              label: 'Street Address',
              type: 'text',
              value: getValue('address.street_address'),
              error: validationErrorMessages['address.street_address'],
            },
            {
              name: 'address.locality',
              label: 'Locality',
              type: 'text',
              value: getValue('address.locality'),
              error: validationErrorMessages['address.locality'],
            },
            {
              name: 'address.region',
              label: 'Region',
              type: 'text',
              value: getValue('address.region'),
              error: validationErrorMessages['address.region'],
            },
            {
              name: 'address.postal_code',
              label: 'Postal Code',
              type: 'text',
              value: getValue('address.postal_code'),
              error: validationErrorMessages['address.postal_code'],
            },
            {
              name: 'address.country',
              label: 'Country',
              type: 'text',
              value: getValue('address.country'),
              error: validationErrorMessages['address.country'],
            },
          ]
        });
      });
    },

    getForgotPasswordForm: function(request, reply, source, error) {
      reply.view('forgot-password', {
        title: 'Forgot Password',
        formAction: `/user/forgot-password?${querystring.stringify(request.query)}`,
        returnTo: `${request.query.redirect_uri}?status=cancelled`,
        error: !!error,
        validationErrorMessages: getValidationMessages(error),
      });
    },

    postForgotPasswordForm: function(request, reply) {
      return userService.findByEmailForOidc(request.payload.email)
        .then(user => user ? userService.createPasswordResetToken(user.accountId): null)
        .then(token => {
          if (token) {
            const base = config('/baseUrl');
            const prevQuery = querystring.stringify(request.query);

            return renderTemplate('email/forgot-password', {
              url: `${base}/user/reset-password?${prevQuery}&token=${token.get('token')}`,
            });
          }
        })
        .then(emailBody => {
          if (emailBody) {
            emailService.send({
              to: request.payload.email,
              subject: 'Reset your password',
              html: emailBody,
            });
          }
        })
        .then(() => {
          reply.view('forgot-password-success');
        });
    },

    getResetPasswordForm: getPasswordResetHandler('GET', 'Reset Password'),

    postResetPasswordForm: getPasswordResetHandler('POST', 'Reset Password'),

    getAcceptInviteForm: getPasswordResetHandler('GET', 'Set Password'),

    postAcceptInviteForm: getPasswordResetHandler('POST', 'Set Password'),
  };

  return self;
};

module.exports['@singleton'] = true;
module.exports['@require'] = [
  'user/user-service',
  'email/email-service',
  'render-template',
  'client/client-service',
  'user/user-form-data',
  'oidc-provider',
  'image/image-service',
];
<commit_msg>Remove email from profile form<commit_after>const querystring = require('querystring');
const formatError = require('../../lib/format-error');
const get = require('lodash/get');
const set = require('lodash/set');
const uuid = require('uuid');
const config = require('../../../config');

module.exports = (
  userService,
  emailService,
  renderTemplate,
  clientService,
  userFormData,
  oidcProvider,
  imageService
) => {
  const errorMessages = {
    email: {
      'any.required': 'Email address is required',
      'any.empty': 'Email address is required',
      'string.email': 'Must be a valid email address',
    },
    password: {
      'any.empty': 'Password is required',
      'string.min': 'Password must be at least 8 characters',
    },
    pass2: {
      'any.allowOnly': 'Passwords must match'
    },
    redirect_uri: {
      'any.required': 'Redirect URI is required',
    },
    client_id: {
      'any.required': 'Client ID is required'
    },
    response_type: {
      'any.required': 'Response type is required',
    },
    scope: {
      'any.required': 'Scope is required',
    },
    token: {
      'any.required': 'Token is required',
    },
    profile: {
      'string.uri': 'Must be a valid URL',
    },
    picture: {
      'string.uri': 'Must be a valid URL',
    },
    website: {
      'string.uri': 'Must be a valid URL',
    },
    birthdate: {
      'string.isoDate': 'Must be valid date in YYYY-MM-DD format'
    }
  };

  const handleRegistrationPost = function(request, reply) {
    userService.create(request.payload.email, request.payload.password)
      .then(user => {
        reply.redirect(`/op/auth?${querystring.stringify(request.query)}`);
      })
      .catch(error => {
        // assume email collision and show validation message
        reply.view('user-registration', {
          title: 'Sign Up',
          formAction: `/user/register?${querystring.stringify(request.query)}`,
          returnTo: `${request.query.redirect_uri}?status=cancelled`,
          error: true,
          validationErrorMessages: {email: ['That email address is already in use']},
          email: request.payload.email || ''
        });
      });
  };

  const getValidationMessages = function(error) {
    var validationErrorMessages = {};

    if (error) {
      error = formatError(error);
      error.output.payload.validationErrors.forEach(errorObj => {
        validationErrorMessages[errorObj.key] = validationErrorMessages[errorObj.key] || [];

        if (errorMessages[errorObj.key] && errorMessages[errorObj.key][errorObj.type]) {
          validationErrorMessages[errorObj.key].push(errorMessages[errorObj.key][errorObj.type]);
        } else if (errorObj.message) {
          validationErrorMessages[errorObj.key].push(errorObj.message);
        }
      });
    }

    return validationErrorMessages;
  };

  // e.g. convert { foo.bar: 'baz' } to { foo: { bar: 'baz' }}
  const expandDotPaths = function(object) {
    Object.keys(object).forEach(key => {
      if (key.indexOf('.') > -1) {
        const value = object[key];
        delete(object[key]);
        set(object, key, value);
      }
    });
    return object;
  };

  const getPasswordResetHandler = (method, title) => {
    if (method === 'GET') {
      return (request, reply, source, error) => {
        reply.view('reset-password', {
          title: title,
          returnTo: `${request.query.redirect_uri}?status=cancelled`,
          error: !!error,
          validationErrorMessages: getValidationMessages(error),
        });
      };
    } else if (method === 'POST') {
      return (request, reply) => {
        userService.findByPasswordToken(request.query.token)
        .then(user => {
          if (user) {
            return userService.encryptPassword(request.payload.password)
              .then(password => {
                const profile = user.get('profile');
                profile.email_verified = true;
                return userService.update(user.get('id'), { password, profile });
              })
              .then(() => userService.destroyPasswordToken(request.query.token))
              .then(() => reply.view(`reset-password-success`));
          } else {
            return reply.view('reset-password', {
              title: title,
              returnTo: `${request.query.redirect_uri}?status=cancelled`,
              error: true,
              validationErrorMessages: { token: ['Token is invalid or expired'] },
            });
          }
        });
      };
    }
  };

  const self = {
    registerFormHandler: function(request, reply, source, error) {
      request.payload = request.payload || {};

      if (!error && request.method === 'post') {
        handleRegistrationPost(request, reply);
      } else {
        reply.view('user-registration', {
          title: 'Sign Up',
          formAction: `/user/register?${querystring.stringify(request.query)}`,
          returnTo: `${request.query.redirect_uri}?status=cancelled`,
          error: !!error,
          validationErrorMessages: getValidationMessages(error),
          email: request.payload.email || ''
        });
      }
    },

    profileFormHandler: function(request, reply, source, error) {
      const accountId = request.auth.credentials.accountId;
      userService.findById(accountId).then(user => {
        if (!user) {
          return reply.redirect(`${request.query.redirect_uri}?error=user_not_found&error_description=user not found`);
        }

        let validationErrorMessages = {};
        if (!error && request.method === 'post') {
          const profile = user.get('profile');
          const payload = expandDotPaths(request.payload);

          const oldPicture = profile.picture;
          const pictureMIME = request.payload.picture.hapi.headers['content-type'];

          return new Promise((resolve, reject) => {
            if (pictureMIME === 'image/jpeg' || pictureMIME === 'image/png') {
              const filename = uuid();
              const bucket = filename.substring(0, 2);
              imageService.uploadImageStream(request.payload.picture, `pictures/${bucket}/${filename}`)
                .then(filename => {
                  resolve(Object.assign(profile, payload, { picture: filename }));
                })
                .catch(err => {
                  reject(err);
                });
            } else {
              delete request.payload.picture;
              resolve(Object.assign(profile, payload));
            }
          })
            .then(profile => userService.update(user.get('id'), { profile }))
            .then(() => {
              if (oldPicture) {
                imageService.deleteImage(oldPicture.replace(/^.*\/\/[^\/]+\//, ''));
              }
            })
            .then(() => reply.redirect(request.query.redirect_uri));
        } else if (error) {
          validationErrorMessages = getValidationMessages(error);
          if (validationErrorMessages.picture || validationErrorMessages['hapi.headers.content-type']) {
            validationErrorMessages.picture = ['Must be JPEG or PNG image less than 1MB'];
          }
        }

        const profile = user.get('profile');
        const getValue = (field) => {
          return (request.payload && request.payload[field]) || get(profile, field, '');
        };
        reply.view('user-profile', {
          returnTo: request.query.redirect_uri,
          title: 'User Profile',
          fields: [
            {
              name: 'name',
              label: 'Name',
              type: 'text',
              value: getValue('name'),
              error: validationErrorMessages.name,
            },
            {
              name: 'given_name',
              label: 'Given Name',
              type: 'text',
              value: getValue('given_name'),
              error: validationErrorMessages.given_name,
            },
            {
              name: 'family_name',
              label: 'Family Name',
              type: 'text',
              value: getValue('family_name'),
              error: validationErrorMessages.family_name,
            },
            {
              name: 'middle_name',
              label: 'Middle Name',
              type: 'text',
              value: getValue('middle_name'),
              error: validationErrorMessages.middle_name,
            },
            {
              name: 'nickname',
              label: 'Nickname',
              type: 'text',
              value: getValue('nickname'),
              error: validationErrorMessages.nickname,
            },
            {
              name: 'preferred_username',
              label: 'Preferred Username',
              type: 'text',
              value: getValue('preferred_username'),
              error: validationErrorMessages.preferred_username,
            },
            {
              name: 'profile',
              label: 'Profile',
              type: 'text',
              value: getValue('profile'),
              error: validationErrorMessages.profile,
            },
            {
              name: 'picture',
              label: 'Picture',
              isFile: true,
              accept: 'image/jpeg, image/png',
              value: getValue('picture'),
              error: validationErrorMessages.picture,
            },
            {
              name: 'website',
              label: 'Website',
              type: 'text',
              value: getValue('website'),
              error: validationErrorMessages.website,
            },
            {
              name: 'gender',
              label: 'Gender',
              type: 'text',
              value: getValue('gender'),
              error: validationErrorMessages.gender,
            },
            {
              name: 'birthdate',
              label: 'Birthdate',
              type: 'text',
              value: getValue('birthdate'),
              error: validationErrorMessages.birthdate,
            },
            {
              name: 'zoneinfo',
              label: 'Timezone',
              isDropdown: true,
              options: userFormData.timezones.map(name => ({
                label: name,
                value: name,
                selected: getValue('zoneinfo') === name
              })),
              value: getValue('zoneinfo'),
              error: validationErrorMessages.zoneinfo,
            },
            {
              name: 'locale',
              label: 'Locale',
              isDropdown: true,
              options: Object.keys(userFormData.locales).map((value) => ({
                label: userFormData.locales[value],
                value,
                selected: getValue('locale') === value,
              })),
              value: getValue('locale'),
              error: validationErrorMessages.locale,
            },
            {
              name: 'phone_number',
              label: 'Phone Number',
              type: 'text',
              value: getValue('phone_number'),
              error: validationErrorMessages.phone_number,
            },
            {
              name: 'address.street_address',
              label: 'Street Address',
              type: 'text',
              value: getValue('address.street_address'),
              error: validationErrorMessages['address.street_address'],
            },
            {
              name: 'address.locality',
              label: 'Locality',
              type: 'text',
              value: getValue('address.locality'),
              error: validationErrorMessages['address.locality'],
            },
            {
              name: 'address.region',
              label: 'Region',
              type: 'text',
              value: getValue('address.region'),
              error: validationErrorMessages['address.region'],
            },
            {
              name: 'address.postal_code',
              label: 'Postal Code',
              type: 'text',
              value: getValue('address.postal_code'),
              error: validationErrorMessages['address.postal_code'],
            },
            {
              name: 'address.country',
              label: 'Country',
              type: 'text',
              value: getValue('address.country'),
              error: validationErrorMessages['address.country'],
            },
          ]
        });
      });
    },

    getForgotPasswordForm: function(request, reply, source, error) {
      reply.view('forgot-password', {
        title: 'Forgot Password',
        formAction: `/user/forgot-password?${querystring.stringify(request.query)}`,
        returnTo: `${request.query.redirect_uri}?status=cancelled`,
        error: !!error,
        validationErrorMessages: getValidationMessages(error),
      });
    },

    postForgotPasswordForm: function(request, reply) {
      return userService.findByEmailForOidc(request.payload.email)
        .then(user => user ? userService.createPasswordResetToken(user.accountId): null)
        .then(token => {
          if (token) {
            const base = config('/baseUrl');
            const prevQuery = querystring.stringify(request.query);

            return renderTemplate('email/forgot-password', {
              url: `${base}/user/reset-password?${prevQuery}&token=${token.get('token')}`,
            });
          }
        })
        .then(emailBody => {
          if (emailBody) {
            emailService.send({
              to: request.payload.email,
              subject: 'Reset your password',
              html: emailBody,
            });
          }
        })
        .then(() => {
          reply.view('forgot-password-success');
        });
    },

    getResetPasswordForm: getPasswordResetHandler('GET', 'Reset Password'),

    postResetPasswordForm: getPasswordResetHandler('POST', 'Reset Password'),

    getAcceptInviteForm: getPasswordResetHandler('GET', 'Set Password'),

    postAcceptInviteForm: getPasswordResetHandler('POST', 'Set Password'),
  };

  return self;
};

module.exports['@singleton'] = true;
module.exports['@require'] = [
  'user/user-service',
  'email/email-service',
  'render-template',
  'client/client-service',
  'user/user-form-data',
  'oidc-provider',
  'image/image-service',
];
<|endoftext|>


<commit_before>import Template from "./template";
import paper from "paper";
import ComponentPort from "../core/componentPort";

export default class Pump3D extends Template {
    constructor() {
        super();
    }

    __setupDefinitions() {
        this.__unique = {
            position: "Point"
        };

        this.__heritable = {
            valveRadius: "Float",
            height: "Float",
            gap: "Float",
            rotation: "Float",
            spacing: "Float",
            flowChannelWidth: "Float"
        };

        this.__defaults = {
            valveRadius: 1.2 * 1000,
            height: 250,
            gap: 0.6 * 1000,
            width: 2.4 * 1000,
            length: 2.4 * 1000,
            rotation: 90,
            spacing: 5000,
            flowChannelWidth: 300
        };

        this.__units = {
            valveRadius: "μm",
            height: "μm",
            gap: "μm",
            width: "μm",
            length: "μm",
            rotation: "°",
            spacing: "μm",
            flowChannelWidth: "μm"
        };

        this.__minimum = {
            valveRadius: 0.1 * 100,
            height: 0.1 * 100,
            gap: 0.5 * 10,
            rotation: 0,
            spacing: 10,
            flowChannelWidth: 1
        };

        this.__maximum = {
            valveRadius: 0.2 * 10000,
            height: 1.2 * 1000,
            gap: 0.1 * 10000,
            rotation: 360,
            spacing: 10000,
            flowChannelWidth: 10000
        };

        this.__featureParams = {
            position: "position",
            rotation: "rotation",
            valveRadius: "valveRadius",
            flowChannelWidth: "flowChannelWidth",
            spacing: "spacing",
            gap: "gap"
        };

        this.__targetParams = {
            rotation: "rotation",
            valveRadius: "valveRadius",
            flowChannelWidth: "flowChannelWidth",
            spacing: "spacing",
            gap: "gap"
        };

        this.__placementTool = "componentPositionTool";

        this.__toolParams = {
            position: "position"
        };

        this.__renderKeys = ["FLOW", "CONTROL", "INVERSE"];

        this.__mint = "PUMP3D";
    }

    getPorts(params) {
        let valve;
        let cutout;
        let circ;
        let center;
        let ret = new paper.CompoundPath();

        let position = params["position"];
        let gap = params["gap"];
        let radius = params["valveRadius"];
        let color = params["color"];
        let rotation = params["rotation"];
        let spacing = params["spacing"];
        let channelwidth = params["flowChannelWidth"];

        let ports = [];

        ports.push(new ComponentPort(0, - spacing - radius, "1", "FLOW"));
        ports.push(new ComponentPort(0, spacing + radius, "2", "FLOW"));

        return ports;
    }

    render2D(params, key="FLOW") {
        if (key == "FLOW") {
            return this.__drawFlow(params);
        } else if (key == "CONTROL") {
            return this.__drawControl(params);
        } else if (key == "INVERSE"){
            return this.__drawInverse(params);
        }
    }

    render2DTarget(key, params) {
        let ret = new paper.CompoundPath();
        let flow = this.render2D(params, "FLOW");
        let control = this.render2D(params, "CONTROL");
        ret.addChild(control);
        ret.addChild(flow);
        ret.fillColor = params["color"];
        ret.fillColor.alpha = 0.5;
        return ret;
    }

    __drawFlow(params) {
        let valve;
        let cutout;
        let circ;
        let center;
        let ret = new paper.CompoundPath();

        let position = params["position"];
        let gap = params["gap"];
        let radius = params["valveRadius"];
        let color = params["color"];
        let rotation = params["rotation"];
        let spacing = params["spacing"];
        let channelwidth = params["flowChannelWidth"];

        center = new paper.Point(position[0], position[1]);
        // let h0p0, h0p1, h0p2, h1p0, h1p1, h1p2;
        circ = new paper.Path.Circle(center, radius);
        //circ.fillColor = color;
        //   if (String(color) == "3F51B5") {
        cutout = paper.Path.Rectangle({
            from: new paper.Point(position[0] - radius, position[1] - gap / 2),
            to: new paper.Point(position[0] + radius, position[1] + gap / 2)
        });
        //cutout.fillColor = "white";
        valve = circ.subtract(cutout);
        ret.addChild(valve);

        let bottomcenter = new paper.Point(position[0], position[1] + spacing);
        console.log(bottomcenter);
        circ = new paper.Path.Circle(bottomcenter, radius);
        //circ.fillColor = color;
        //   if (String(color) == "3F51B5") {
        cutout = paper.Path.Rectangle({
            from: new paper.Point(bottomcenter.x - radius, bottomcenter.y - gap / 2),
            to: new paper.Point(bottomcenter.x + radius, bottomcenter.y + gap / 2)
        });
        //cutout.fillColor = "white";
        valve = circ.subtract(cutout);
        ret.addChild(valve);

        let topcenter = new paper.Point(position[0], position[1] - spacing);

        circ = new paper.Path.Circle(topcenter, radius);
        //circ.fillColor = color;
        //   if (String(color) == "3F51B5") {
        cutout = paper.Path.Rectangle({
            from: new paper.Point(topcenter.x - radius, topcenter.y - gap / 2),
            to: new paper.Point(topcenter.x + radius, topcenter.y + gap / 2)
        });
        //cutout.fillColor = "white";
        valve = circ.subtract(cutout);
        ret.addChild(valve);

        //Create the channels that go through
        let bottomchannel = new paper.Path.Rectangle({
            from: new paper.Point(bottomcenter.x - channelwidth / 2, bottomcenter.y - gap / 2),
            to: new paper.Point(center.x + channelwidth / 2, center.y + gap / 2)
        });

        ret.addChild(bottomchannel);

        let topchannel = new paper.Path.Rectangle({
            from: new paper.Point(topcenter.x - channelwidth / 2, topcenter.y + gap / 2),
            to: new paper.Point(center.x + channelwidth / 2, center.y - gap / 2)
        });

        ret.addChild(topchannel);

        ret.rotate(rotation, center);
        ret.fillColor = color;

        return ret;
    }

    __drawControl(params) {
        let circ;
        let position = params["position"];
        let radius = params["valveRadius"];
        let color = params["color"];
        let rotation = params["rotation"];
        let spacing = params["spacing"];

        console.log("Spacing:", spacing);

        let ret = new paper.CompoundPath();

        let center = new paper.Point(position[0], position[1]);

        circ = new paper.Path.Circle(center, radius);
        ret.addChild(circ);

        let topcenter = new paper.Point(position[0], position[1] - spacing);
        circ = new paper.Path.Circle(topcenter, radius);
        ret.addChild(circ);

        let bottomcenter = new paper.Point(position[0], position[1] + spacing);
        circ = new paper.Path.Circle(bottomcenter, radius);
        ret.addChild(circ);

        ret.rotate(rotation, center);
        ret.fillColor = color;
        return ret;
    }

    __drawInverse(params){
        let circ;
        let position = params["position"];
        let radius = params["valveRadius"];
        let color = params["color"];
        let rotation = params["rotation"];
        let spacing = params["spacing"];

        console.log("Spacing:", spacing);

        let ret = new paper.CompoundPath();

        let center = new paper.Point(position[0], position[1]);

        circ = new paper.Path.Circle(center, radius);
        ret.addChild(circ);

        let topcenter = new paper.Point(position[0], position[1] - spacing);
        circ = new paper.Path.Circle(topcenter, radius);
        ret.addChild(circ);

        let bottomcenter = new paper.Point(position[0], position[1] + spacing);
        circ = new paper.Path.Circle(bottomcenter, radius);
        ret.addChild(circ);

        ret.rotate(rotation, center);
        ret.fillColor = color;
        return ret;
    }
}
<commit_msg>add ports to pump3D<commit_after>import Template from "./template";
import paper from "paper";
import ComponentPort from "../core/componentPort";

export default class Pump3D extends Template {
    constructor() {
        super();
    }

    __setupDefinitions() {
        this.__unique = {
            position: "Point"
        };

        this.__heritable = {
            valveRadius: "Float",
            height: "Float",
            gap: "Float",
            rotation: "Float",
            spacing: "Float",
            flowChannelWidth: "Float"
        };

        this.__defaults = {
            valveRadius: 1.2 * 1000,
            height: 250,
            gap: 0.6 * 1000,
            width: 2.4 * 1000,
            length: 2.4 * 1000,
            rotation: 90,
            spacing: 5000,
            flowChannelWidth: 300
        };

        this.__units = {
            valveRadius: "μm",
            height: "μm",
            gap: "μm",
            width: "μm",
            length: "μm",
            rotation: "°",
            spacing: "μm",
            flowChannelWidth: "μm"
        };

        this.__minimum = {
            valveRadius: 0.1 * 100,
            height: 0.1 * 100,
            gap: 0.5 * 10,
            rotation: 0,
            spacing: 10,
            flowChannelWidth: 1
        };

        this.__maximum = {
            valveRadius: 0.2 * 10000,
            height: 1.2 * 1000,
            gap: 0.1 * 10000,
            rotation: 360,
            spacing: 10000,
            flowChannelWidth: 10000
        };

        this.__featureParams = {
            position: "position",
            rotation: "rotation",
            valveRadius: "valveRadius",
            flowChannelWidth: "flowChannelWidth",
            spacing: "spacing",
            gap: "gap"
        };

        this.__targetParams = {
            rotation: "rotation",
            valveRadius: "valveRadius",
            flowChannelWidth: "flowChannelWidth",
            spacing: "spacing",
            gap: "gap"
        };

        this.__placementTool = "componentPositionTool";

        this.__toolParams = {
            position: "position"
        };

        this.__renderKeys = ["FLOW", "CONTROL", "INVERSE"];

        this.__mint = "PUMP3D";
    }

    getPorts(params) {
        let radius = params["valveRadius"];
        let spacing = params["spacing"];

        let ports = [];

        ports.push(new ComponentPort(0, - spacing - radius, "1", "FLOW"));
        ports.push(new ComponentPort(0, spacing + radius, "2", "FLOW"));

        return ports;
    }

    render2D(params, key="FLOW") {
        if (key == "FLOW") {
            return this.__drawFlow(params);
        } else if (key == "CONTROL") {
            return this.__drawControl(params);
        } else if (key == "INVERSE"){
            return this.__drawInverse(params);
        }
    }

    render2DTarget(key, params) {
        let ret = new paper.CompoundPath();
        let flow = this.render2D(params, "FLOW");
        let control = this.render2D(params, "CONTROL");
        ret.addChild(control);
        ret.addChild(flow);
        ret.fillColor = params["color"];
        ret.fillColor.alpha = 0.5;
        return ret;
    }

    __drawFlow(params) {
        let valve;
        let cutout;
        let circ;
        let center;
        let ret = new paper.CompoundPath();

        let position = params["position"];
        let gap = params["gap"];
        let radius = params["valveRadius"];
        let color = params["color"];
        let rotation = params["rotation"];
        let spacing = params["spacing"];
        let channelwidth = params["flowChannelWidth"];

        center = new paper.Point(position[0], position[1]);
        // let h0p0, h0p1, h0p2, h1p0, h1p1, h1p2;
        circ = new paper.Path.Circle(center, radius);
        //circ.fillColor = color;
        //   if (String(color) == "3F51B5") {
        cutout = paper.Path.Rectangle({
            from: new paper.Point(position[0] - radius, position[1] - gap / 2),
            to: new paper.Point(position[0] + radius, position[1] + gap / 2)
        });
        //cutout.fillColor = "white";
        valve = circ.subtract(cutout);
        ret.addChild(valve);

        let bottomcenter = new paper.Point(position[0], position[1] + spacing);
        console.log(bottomcenter);
        circ = new paper.Path.Circle(bottomcenter, radius);
        //circ.fillColor = color;
        //   if (String(color) == "3F51B5") {
        cutout = paper.Path.Rectangle({
            from: new paper.Point(bottomcenter.x - radius, bottomcenter.y - gap / 2),
            to: new paper.Point(bottomcenter.x + radius, bottomcenter.y + gap / 2)
        });
        //cutout.fillColor = "white";
        valve = circ.subtract(cutout);
        ret.addChild(valve);

        let topcenter = new paper.Point(position[0], position[1] - spacing);

        circ = new paper.Path.Circle(topcenter, radius);
        //circ.fillColor = color;
        //   if (String(color) == "3F51B5") {
        cutout = paper.Path.Rectangle({
            from: new paper.Point(topcenter.x - radius, topcenter.y - gap / 2),
            to: new paper.Point(topcenter.x + radius, topcenter.y + gap / 2)
        });
        //cutout.fillColor = "white";
        valve = circ.subtract(cutout);
        ret.addChild(valve);

        //Create the channels that go through
        let bottomchannel = new paper.Path.Rectangle({
            from: new paper.Point(bottomcenter.x - channelwidth / 2, bottomcenter.y - gap / 2),
            to: new paper.Point(center.x + channelwidth / 2, center.y + gap / 2)
        });

        ret.addChild(bottomchannel);

        let topchannel = new paper.Path.Rectangle({
            from: new paper.Point(topcenter.x - channelwidth / 2, topcenter.y + gap / 2),
            to: new paper.Point(center.x + channelwidth / 2, center.y - gap / 2)
        });

        ret.addChild(topchannel);

        ret.rotate(rotation, center);
        ret.fillColor = color;

        return ret;
    }

    __drawControl(params) {
        let circ;
        let position = params["position"];
        let radius = params["valveRadius"];
        let color = params["color"];
        let rotation = params["rotation"];
        let spacing = params["spacing"];

        console.log("Spacing:", spacing);

        let ret = new paper.CompoundPath();

        let center = new paper.Point(position[0], position[1]);

        circ = new paper.Path.Circle(center, radius);
        ret.addChild(circ);

        let topcenter = new paper.Point(position[0], position[1] - spacing);
        circ = new paper.Path.Circle(topcenter, radius);
        ret.addChild(circ);

        let bottomcenter = new paper.Point(position[0], position[1] + spacing);
        circ = new paper.Path.Circle(bottomcenter, radius);
        ret.addChild(circ);

        ret.rotate(rotation, center);
        ret.fillColor = color;
        return ret;
    }

    __drawInverse(params){
        let circ;
        let position = params["position"];
        let radius = params["valveRadius"];
        let color = params["color"];
        let rotation = params["rotation"];
        let spacing = params["spacing"];

        console.log("Spacing:", spacing);

        let ret = new paper.CompoundPath();

        let center = new paper.Point(position[0], position[1]);

        circ = new paper.Path.Circle(center, radius);
        ret.addChild(circ);

        let topcenter = new paper.Point(position[0], position[1] - spacing);
        circ = new paper.Path.Circle(topcenter, radius);
        ret.addChild(circ);

        let bottomcenter = new paper.Point(position[0], position[1] + spacing);
        circ = new paper.Path.Circle(bottomcenter, radius);
        ret.addChild(circ);

        ret.rotate(rotation, center);
        ret.fillColor = color;
        return ret;
    }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { LineMarkSeries, XYPlot, XAxis, YAxis, VerticalGridLines, HorizontalGridLines } from 'react-vis';
import { extractField, getReviewDate } from './utils.js';

import BookHint from './BookHint';

import _ from 'lodash';

export default class PagesVsTimePlot extends Component {
  constructor () {
    super();
    this.state = {
      over: null
    };
  }

  // derive data to plot from the review xmls in this.state
  plotData () {
    if (this.props.reviews) {
      return _(this.props.reviews)
        .filter((r) => extractField(r, "read_at"))
        .sortBy([getReviewDate])
        .reduce(function (acc, r) {
          let pages = parseInt(extractField(r, "book num_pages"), 10) || 0;
          let priorPages = acc.length === 0 ? 0 : acc[acc.length-1].y;
          return acc.concat({
            x: getReviewDate(r).valueOf(),
            y: priorPages + pages,
            imageUrl: extractField(r, "book small_image_url"),
            linkUrl: extractField(r, "book link"),
            bookTitle: extractField(r, "book title")
          });
        }, []);
    } else {
      return [];
    }
  }

  pagesRead() {
    let plotData = this.plotData();
    return plotData[plotData.length-1].y;
  }

  render () {
    let data = this.plotData();
    let over = this.state.over;
    if (data.length > 0) {
      return (
        <XYPlot
           width={1000}
           height={500}
           margin={{left: 60, bottom: 60, right: 60, top: 0}}
           yDomain={[0, Math.floor(1.1 * this.pagesRead())]}>
          <XAxis xType="time" title="Date" tickLabelAngle={-45} />
          <YAxis title="Pages" />
          <VerticalGridLines />
          <HorizontalGridLines />
          <LineMarkSeries
             data={data}
             onValueMouseOver={(v) => this.setState({over: v})}
            onValueMouseOut={(v) => this.setState({over: null})}
            />
            {over ? <BookHint value={over}/> : null}
        </XYPlot>
      );
    } else {
      return
Not enough data :(
;
    }
  }
}
<commit_msg>click takes you to book<commit_after>import React, { Component } from 'react';
import { LineMarkSeries, XYPlot, XAxis, YAxis, VerticalGridLines, HorizontalGridLines } from 'react-vis';
import { extractField, getReviewDate } from './utils.js';

import BookHint from './BookHint';

import _ from 'lodash';

export default class PagesVsTimePlot extends Component {
  constructor () {
    super();
    this.state = {
      over: null
    };
  }

  // derive data to plot from the review xmls in this.state
  plotData () {
    if (this.props.reviews) {
      return _(this.props.reviews)
        .filter((r) => extractField(r, "read_at"))
        .sortBy([getReviewDate])
        .reduce(function (acc, r) {
          let pages = parseInt(extractField(r, "book num_pages"), 10) || 0;
          let priorPages = acc.length === 0 ? 0 : acc[acc.length-1].y;
          return acc.concat({
            x: getReviewDate(r).valueOf(),
            y: priorPages + pages,
            imageUrl: extractField(r, "book small_image_url"),
            linkUrl: extractField(r, "book link"),
            bookTitle: extractField(r, "book title")
          });
        }, []);
    } else {
      return [];
    }
  }

  pagesRead() {
    let plotData = this.plotData();
    return plotData[plotData.length-1].y;
  }

  render () {
    let data = this.plotData();
    let over = this.state.over;
    if (data.length > 0) {
      return (
        <XYPlot
           width={1000}
           height={500}
           margin={{left: 60, bottom: 60, right: 60, top: 0}}
           yDomain={[0, Math.floor(1.1 * this.pagesRead())]}>
          <XAxis xType="time" title="Date" tickLabelAngle={-45} />
          <YAxis title="Pages" />
          <VerticalGridLines />
          <HorizontalGridLines />
          <LineMarkSeries
             data={data}
             onValueMouseOver={(v) => this.setState({over: v})}
             onValueMouseOut={(v) => this.setState({over: null})}
             onValueClick={(v) => window.location = v.linkUrl}
          />
          {over ? <BookHint value={over}/> : null}
        </XYPlot>
      );
    } else {
      return
Not enough data :(
;
    }
  }
}
<|endoftext|>


<commit_before>var tap = require("tap")
  , test = tap.test
  , math

test("load sut", function (t) {
  math = require("../lib/math")
  t.ok(math, "object loaded")
  t.end()
})

test("validate constants", function (t) {
  t.equal(math.LN10, 2.302585092994046, "ln 10")
  t.equal(math.PI, 3.141592653589793, "pi")
  t.equal(math.E, 2.718281828459045, "e")
  t.equal(math.LOG10E, 0.4342944819032518, "log 10 e")
  t.equal(math.SQRT2, 1.4142135623730951, "sqrt 2")
  t.equal(math.SQRT1_2, 0.7071067811865476, "sqrt 1/2")
  t.equal(math.LN2, 0.6931471805599453, "ln2")
  t.end()
})

test("using this", function (t) {
  // this also works.
  this.equal(t, this, "call in scope of test obj")
  this.end()
})

// test setTimeout, just a trivial example.
test("setTimeout", function (t) {
  var start = Date.now()
  setTimeout(function () {
    t.ok(Date.now() >= start + 50, "timeout fired after delay")
    t.end()
  }, 50)
})

// another way to do the same, using a plan.
// this is more robust, but annoying when you have a long list
// of tests for something.  For async stuff, it's generally better,
// since there's a higher risk of the control flowing off to lala land.
test("setTimeout planned", function (t) {
  t.plan(1)
  var start = Date.now()
  setTimeout(function () {
    t.ok(Date.now() >= start + 50, "timeout fired after delay")
  }, 50)
})

// plans also are good for cases where things may fire in a non-deterministic
// order, since it won't be as obvious when everything is done.
test("setTimeout parallel", function (t) {
  t.plan(2)
  var start = Date.now()
  setTimeout(function A () {
    t.ok(Date.now() >= start + 50, "timeout A fired after delay")
  }, 50)
  setTimeout(function B () {
    t.ok(Date.now() >= start + 50, "timeout B fired after delay")
  }, 50)
})

// something slightly less hello worldy
test("async test", function (t) {
  t.plan(4)
  var fs = require("fs")
  t.ok(fs, "fs library should load")
  var rs = fs.createReadStream(__filename)
  t.ok(rs, "read stream should start fine.")
  rs.on("open", function (fd) {
    t.type(fd, "number", "file descriptor should be a number")
    t.equal(fd, rs.fd, "fd should match stream fd")
  })
})

// you can bail out of the entire everything if something is just
// Not Right (db not installed, etc.)
test("tarp", function (parent) {
  if (7 === 5) {
    parent.bailout("math is broken")
  }
  // bailout bubbles up a bit like "error" events
  // if unhandled, then the parent will bail, as well.
  parent.test("child bailouts", function (child) {
    child.on("bailout", function (s) {
      parent.fail("children shouldn't bail.")
    })
    child.bailout("try to bail out, but instead just fail a test")
  })

  parent.test("child bailout 2", function (child) {
    child.bailout("this one will bail out")
  })
})

// tests marked "todo" can fail without counting against the overall score
// never ever ever write tests to "verify" incorrect behavior!
test("unfinished test", function (t) {
  t.equal(math.cos(math.PI), -1, "cos(PI)")
  t.equal(math.sin(math.PI),  0, "sin(PI)")
  t.equal(math.face, "your face", "math.face should be your face # TODO")
  t.end()
})

// tests can have children.
test("http server", function (t) {
  // one test plus 4 children.
  t.plan(5)

  var http = require("http")
    , PORT = 12346

  t.ok(http, "http module should load")
  var server

  t.test("set up server", function (t) {
    t.plan(2)
    server = http.createServer(function (req, res) {
      t.comment("Request: "+req.url)
      res.writeHead(200, {})
      res.end(req.method + " " + req.url)
    })
    t.ok(server, "createServer should create a server")
    server.listen(PORT, t.cb("listen should fire callback"))
  })

  // set the "parallel" flag on this one.
  // That signals the harness to proceed immediately to the next test,
  // and run them in parallel.
  // Default behavior is to wait for each test to complete before proceeding
  // to the next one.
  // The first not-parallel test encountered will cause it to wait for that
  // test, as well as all the parallel tests before it.
  // A, B', C', D', E (where ' means "parallel")
  // Runs A, and then B, C, and D in parallel, and then E.
  t.test("testing POST", true, function (t) {
    t.plan(1)
    http.request("POST", { method: "POST"
                         , host: "localhost"
                         , path: "/foo"
                         , port: PORT }).on("response", function (res) {
      t.bufferStream(res, function (s) { t.equal(s, "POST /foo") })
    }).end()
  })

  t.test("testing GET", true, function (t) {
    t.plan(1)
    http.request("POST", { method: "GET"
                         , host: "localhost"
                         , path: "/foo"
                         , port: PORT }).on("response", function (res) {
      t.bufferStream(res, function (s) { t.equal(s, "GET /foo") })
    }).end()
  })

  // wrap in a test so that if this throws, it'll log as a failed test.
  t.test("teardown", function (t) {
    server.close()
    t.end()
  })
})

// yo dawg!
test("meta-tests", function (t) {
  t.plan(5)

  // t.fails() wraps a child test and succeeds if it fails.
  t.fails(t.test("this should fail", function (t) {
    t.ok(false, "assert false")
    t.end()
  }))

  // t.timesOut() wraps a child test and succeeds if it times out.
  // if t.end() is called, or if a plan is completed, then it fails.
  t.timesOut(t.test("this should timeout", function (t) {
    // set the timeout really low so that it will not take forever.
    t.timeout = 1
    t.ok(true, "assert true")
    // t.end() never called.
  }))

  // t.incomplete() wraps a child test and succeeds if it ends before
  // the plan is finished.
  t.incomplete(t.test("this should be incomplete", function (t) {
    t.plan(100)
    t.ok(true, "assert true")
    // calling end prematurely.
    t.end()
  }))

  // t.bailsOut() wraps a child test and succeeds if it calls bailout()
  t.bailsOut(t.test("this should bailout", function (t) {
    t.bailout("oh noes, bailing out!")
  }))

  // low-level analysis of subtests
  t.test("verifying test success/failure expectations", function (t) {
    t.once("end", function () {
      var res = t.results
        , is = t.equal
      // hijack!
      t.clear()
      is(res.ok,         false, "ok")

      is(res.bailedOut,  false, "bailed out")

      is(res.skip,       2, "skips")
      is(res.skipPass,   1, "skip that passed")
      is(res.skipFail,   1, "skip that failed")

      is(res.todo,       2, "todos")
      is(res.todoPass,   1, "todo that passed")
      is(res.todoFail,   1, "todo that failed")

      is(res.failTotal,  3, "failures total")
      is(res.fail,       1, "relevant failure")

      is(res.passTotal,  3, "passes total")
      is(res.pass,       1, "relevant pass")

      is(res.testsTotal, 6, "total tests")
      is(res.tests,      2, "should be 2 relevant tests")

      t.end()
    })

    // run the metatest.
    // *this* is the actual SUT in this case.
    t.ok(false, "failing todo #todo")
    t.ok(true, "succeeding todo #todo")
    t.ok(false, "failing skip #skip")
    t.ok(true, "suceeding skip #skip")
    t.ok(false, "failing test")
    t.ok(true, "succeeding test")
    t.end()
  })
})
<commit_msg>example setting #skip/#todo with an object<commit_after>var tap = require("tap")
  , test = tap.test
  , math

test("load sut", function (t) {
  math = require("../lib/math")
  t.ok(math, "object loaded")
  t.end()
})

test("validate constants", function (t) {
  t.equal(math.LN10, 2.302585092994046, "ln 10")
  t.equal(math.PI, 3.141592653589793, "pi")
  t.equal(math.E, 2.718281828459045, "e")
  t.equal(math.LOG10E, 0.4342944819032518, "log 10 e")
  t.equal(math.SQRT2, 1.4142135623730951, "sqrt 2")
  t.equal(math.SQRT1_2, 0.7071067811865476, "sqrt 1/2")
  t.equal(math.LN2, 0.6931471805599453, "ln2")
  t.end()
})

test("using this", function (t) {
  // this also works.
  this.equal(t, this, "call in scope of test obj")
  this.end()
})

// test setTimeout, just a trivial example.
test("setTimeout", function (t) {
  var start = Date.now()
  setTimeout(function () {
    t.ok(Date.now() >= start + 50, "timeout fired after delay")
    t.end()
  }, 50)
})

// another way to do the same, using a plan.
// this is more robust, but annoying when you have a long list
// of tests for something.  For async stuff, it's generally better,
// since there's a higher risk of the control flowing off to lala land.
test("setTimeout planned", function (t) {
  t.plan(1)
  var start = Date.now()
  setTimeout(function () {
    t.ok(Date.now() >= start + 50, "timeout fired after delay")
  }, 50)
})

// plans also are good for cases where things may fire in a non-deterministic
// order, since it won't be as obvious when everything is done.
test("setTimeout parallel", function (t) {
  t.plan(2)
  var start = Date.now()
  setTimeout(function A () {
    t.ok(Date.now() >= start + 50, "timeout A fired after delay")
  }, 50)
  setTimeout(function B () {
    t.ok(Date.now() >= start + 50, "timeout B fired after delay")
  }, 50)
})

// something slightly less hello worldy
test("async test", function (t) {
  t.plan(4)
  var fs = require("fs")
  t.ok(fs, "fs library should load")
  var rs = fs.createReadStream(__filename)
  t.ok(rs, "read stream should start fine.")
  rs.on("open", function (fd) {
    t.type(fd, "number", "file descriptor should be a number")
    t.equal(fd, rs.fd, "fd should match stream fd")
  })
})

// you can bail out of the entire everything if something is just
// Not Right (db not installed, etc.)
test("tarp", function (parent) {
  if (7 === 5) {
    parent.bailout("math is broken")
  }
  // bailout bubbles up a bit like "error" events
  // if unhandled, then the parent will bail, as well.
  parent.test("child bailouts", function (child) {
    child.on("bailout", function (s) {
      parent.fail("children shouldn't bail.")
    })
    child.bailout("try to bail out, but instead just fail a test")
  })

  parent.test("child bailout 2", function (child) {
    child.bailout("this one will bail out")
  })
})

// tests marked "todo" can fail without counting against the overall score
// never ever ever write tests to "verify" incorrect behavior!
test("unfinished test", function (t) {
  t.equal(math.cos(math.PI), -1, "cos(PI)")
  t.equal(math.sin(math.PI),  0, "sin(PI)")
  t.equal(math.face, "your face", "math.face should be your face # TODO")
  t.end()
})

// tests can have children.
test("http server", function (t) {
  // one test plus 4 children.
  t.plan(5)

  var http = require("http")
    , PORT = 12346

  t.ok(http, "http module should load")
  var server

  t.test("set up server", function (t) {
    t.plan(2)
    server = http.createServer(function (req, res) {
      t.comment("Request: "+req.url)
      res.writeHead(200, {})
      res.end(req.method + " " + req.url)
    })
    t.ok(server, "createServer should create a server")
    server.listen(PORT, t.cb("listen should fire callback"))
  })

  // set the "parallel" flag on this one.
  // That signals the harness to proceed immediately to the next test,
  // and run them in parallel.
  // Default behavior is to wait for each test to complete before proceeding
  // to the next one.
  // The first not-parallel test encountered will cause it to wait for that
  // test, as well as all the parallel tests before it.
  // A, B', C', D', E (where ' means "parallel")
  // Runs A, and then B, C, and D in parallel, and then E.
  t.test("testing POST", true, function (t) {
    t.plan(1)
    http.request("POST", { method: "POST"
                         , host: "localhost"
                         , path: "/foo"
                         , port: PORT }).on("response", function (res) {
      t.bufferStream(res, function (s) { t.equal(s, "POST /foo") })
    }).end()
  })

  t.test("testing GET", true, function (t) {
    t.plan(1)
    http.request("POST", { method: "GET"
                         , host: "localhost"
                         , path: "/foo"
                         , port: PORT }).on("response", function (res) {
      t.bufferStream(res, function (s) { t.equal(s, "GET /foo") })
    }).end()
  })

  // wrap in a test so that if this throws, it'll log as a failed test.
  t.test("teardown", function (t) {
    server.close()
    t.end()
  })
})

// yo dawg!
test("meta-tests", function (t) {
  t.plan(5)

  // t.fails() wraps a child test and succeeds if it fails.
  t.fails(t.test("this should fail", function (t) {
    t.ok(false, "assert false")
    t.end()
  }))

  // t.timesOut() wraps a child test and succeeds if it times out.
  // if t.end() is called, or if a plan is completed, then it fails.
  t.timesOut(t.test("this should timeout", function (t) {
    // set the timeout really low so that it will not take forever.
    t.timeout = 1
    t.ok(true, "assert true")
    // t.end() never called.
  }))

  // t.incomplete() wraps a child test and succeeds if it ends before
  // the plan is finished.
  t.incomplete(t.test("this should be incomplete", function (t) {
    t.plan(100)
    t.ok(true, "assert true")
    // calling end prematurely.
    t.end()
  }))

  // t.bailsOut() wraps a child test and succeeds if it calls bailout()
  t.bailsOut(t.test("this should bailout", function (t) {
    t.bailout("oh noes, bailing out!")
  }))

  // low-level analysis of subtests
  t.test("verifying test success/failure expectations", function (t) {
    t.once("end", function () {
      var res = t.results
        , is = t.equal
      // hijack!
      t.clear()
      is(res.ok,         false, "ok")

      is(res.bailedOut,  false, "bailed out")

      is(res.skip,       2, "skips")
      is(res.skipPass,   1, "skip that passed")
      is(res.skipFail,   1, "skip that failed")

      is(res.todo,       2, "todos")
      is(res.todoPass,   1, "todo that passed")
      is(res.todoFail,   1, "todo that failed")

      is(res.failTotal,  3, "failures total")
      is(res.fail,       1, "relevant failure")

      is(res.passTotal,  3, "passes total")
      is(res.pass,       1, "relevant pass")

      is(res.testsTotal, 6, "total tests")
      is(res.tests,      2, "should be 2 relevant tests")

      t.end()
    })

    // run the metatest.
    // *this* is the actual SUT in this case.
    t.ok(false, "failing todo #todo")
    // can also set #todo or #skip explicitly
    t.ok(true, "succeeding todo", {todo: true})
    t.ok(false, "failing skip #skip", {skip: true})
    t.ok(true, "suceeding skip #skip")
    t.ok(false, "failing test")
    t.ok(true, "succeeding test")
    t.end()
  })
})
<|endoftext|>


<commit_before>'use strict';
/*global setTimeout, clearTimeout*/

import ActionButton from 'metabase/components/ActionButton.react';
import AddToDashboard from './add_to_dashboard.react';
import AddToDashSelectDashModal from '../components/AddToDashSelectDashModal.react';
import CardFavoriteButton from './card_favorite_button.react';
import DeleteQuestionModal from '../components/DeleteQuestionModal.react';
import Header from "metabase/components/Header.react";
import HistoryModal from "metabase/components/HistoryModal.react";
import Icon from "metabase/components/Icon.react";
import Modal from "metabase/components/Modal.react";
import ModalWithTrigger from "metabase/components/ModalWithTrigger.react";
import QueryModeToggle from './query_mode_toggle.react';
import QuestionSavedModal from '../components/QuestionSavedModal.react';
import SaveQuestionModal from '../components/SaveQuestionModal.react';

import inflection from "inflection";
import cx from "classnames";

export default React.createClass({
    displayName: 'QueryHeader',
    propTypes: {
        card: React.PropTypes.object.isRequired,
        tableMetadata: React.PropTypes.object, // can't be required, sometimes null
        cardApi: React.PropTypes.func.isRequired,
        dashboardApi: React.PropTypes.func.isRequired,
        revisionApi: React.PropTypes.func.isRequired,
        notifyCardChangedFn: React.PropTypes.func.isRequired,
        notifyCardAddedToDashFn: React.PropTypes.func.isRequired,
        reloadCardFn: React.PropTypes.func.isRequired,
        setQueryModeFn: React.PropTypes.func.isRequired,
        isShowingDataReference: React.PropTypes.bool.isRequired,
        toggleDataReferenceFn: React.PropTypes.func.isRequired,
        cardIsNewFn: React.PropTypes.func.isRequired,
        cardIsDirtyFn: React.PropTypes.func.isRequired
    },

    getInitialState: function() {
        return {
            recentlySaved: null,
            modal: null,
            revisions: null
        };
    },

    resetStateOnTimeout: function() {
        // clear any previously set timeouts then start a new one
        clearTimeout(this.timeout);
        this.timeout = setTimeout(() => {
            if (this.isMounted()) {
                this.setState({
                    recentlySaved: null
                });
            }
        }, 5000);
    },

    onCreate: async function(card) {
        let newCard = await this.props.cardApi.create(card).$promise;
        this.props.notifyCardCreatedFn(newCard);
        if (this.isMounted()) {
            // update local state to reflect new card state
            this.setState({ recentlySaved: "created", modal: "saved" }, this.resetStateOnTimeout);
        }
    },

    onSave: async function() {
        let card = this.props.card;
        let updatedCard = await this.props.cardApi.update(card).$promise;
        if (this.props.fromUrl) {
            this.onGoBack();
            return;
        }
        this.props.notifyCardUpdatedFn(updatedCard);
        if (this.isMounted()) {
            // update local state to reflect new card state
            this.setState({ recentlySaved: "updated" }, this.resetStateOnTimeout);
        }
    },

    onCancel: async function() {
        this.onGoBack();
    },

    onDelete: async function () {
        await this.props.cardApi.delete({ 'cardId': this.props.card.id }).$promise;
        this.onGoBack();
    },

    setQueryMode: function(mode) {
        this.props.setQueryModeFn(mode);
    },

    toggleDataReference: function() {
        this.props.toggleDataReferenceFn();
    },

    setCardAttribute: function(attribute, value) {
        this.props.card[attribute] = value;
        this.props.notifyCardChangedFn(this.props.card);
    },

    onGoBack: function() {
        this.props.onChangeLocation(this.props.fromUrl || "/");
    },

    onFetchRevisions: async function({ entity, id }) {
        var revisions = await this.props.revisionApi.list({ entity, id }).$promise;
        this.setState({ revisions });
    },

    onRevertToRevision: function({ entity, id, revision_id }) {
        return this.props.revisionApi.revert({ entity, id, revision_id }).$promise;
    },

    onRevertedRevision: function() {
        this.props.reloadCardFn();
        this.refs.cardHistory.toggle();
    },

    getHeaderButtons: function() {
        var buttons = [];

        if (this.props.cardIsNewFn() && this.props.cardIsDirtyFn()) {
            buttons.push(
                <ModalWithTrigger
                    ref="saveModal"
                    triggerClasses="h4 px1 text-grey-4 text-brand-hover text-uppercase"
                    triggerElement="Save"
                >
                    <SaveQuestionModal
                        card={this.props.card}
                        tableMetadata={this.props.tableMetadata}
                        saveFn={this.onCreate}
                        closeFn={() => this.refs.saveModal.toggle()}
                    />
                </ModalWithTrigger>
            );
        }

        if (!this.props.cardIsNewFn()) {
            buttons.push(
                <ModalWithTrigger
                    ref="cardHistory"
                    triggerElement={<Icon name="history" width="16px" height="16px" />}
                >
                    <HistoryModal
                        revisions={this.state.revisions}
                        entityType="card"
                        entityId={this.props.card.id}
                        onFetchRevisions={this.onFetchRevisions}
                        onRevertToRevision={this.onRevertToRevision}
                        onClose={() => this.refs.cardHistory.toggle()}
                        onReverted={this.onRevertedRevision}
                    />
                </ModalWithTrigger>
            );
        }

        if (this.props.cardIsNewFn() && !this.props.cardIsDirtyFn()) {
            buttons.push(
                <QueryModeToggle
                    currentQueryMode={this.props.card.dataset_query.type}
                    setQueryModeFn={this.setQueryMode}
                />
            );
        }

        var dataReferenceButtonClasses = cx({
            'mx1': true,
            'transition-color': true,
            'text-grey-4': !this.props.isShowingDataReference,
            'text-brand': this.props.isShowingDataReference,
            'text-brand-hover': !this.state.isShowingDataReference
        });
        var dataReferenceButton = (

                <Icon name='reference' width="16px" height="16px" onClick={this.toggleDataReference}></Icon>

        );

        return [buttons, [dataReferenceButton]];
    },

    getEditingButtons: function() {
        var editingButtons = [];
        editingButtons.push(
            <ActionButton
                actionFn={() => this.onSave()}
                className="Button Button--small Button--primary text-uppercase"
                normalText="Save"
                activeText="Saving…"
                failedText="Save failed"
                successText="Saved"
            />
        );
        editingButtons.push(
             this.onCancel()}>Cancel
        );
        editingButtons.push(
            <ModalWithTrigger
                ref="deleteModal"
                triggerClasses="Button Button--small text-uppercase"
                triggerElement="Delete"
            >
                <DeleteQuestionModal
                    card={this.props.card}
                    deleteCardFn={() => this.onDelete()}
                    closeFn={() => this.refs.deleteModal.toggle()}
                />
            </ModalWithTrigger>
        );
        return editingButtons;
    },

    render: function() {
        var subtitleText;
        if (this.props.card) {
            if (this.props.card.dashboard_count > 0) {
                subtitleText = "Changes will be reflected in " + this.props.card.dashboard_count + " " + inflection.inflect("dashboard", this.props.card.dashboard_count) + " and can be reverted.";
            } else {
                subtitleText = "Changes can be reverted."
            }
        }

        return (
            <Header
                objectType="question"
                item={this.props.card}
                isEditing={!this.props.cardIsNewFn() && this.props.card.is_creator}
                isEditingInfo={!this.props.cardIsNewFn() && this.props.card.is_creator}
                headerButtons={this.getHeaderButtons()}
                editingTitle="You are editing a saved question"
                editingSubtitle={subtitleText}
                editingButtons={this.getEditingButtons()}
                setItemAttributeFn={this.setCardAttribute}
            >
                <Modal isOpen={this.state.modal === "saved"}>
                    <QuestionSavedModal
                        addToDashboardFn={() => this.setState({ modal: "add-to-dashboard" })}
                        closeFn={() => this.setState({ modal: null })}
                    />
                </Modal>
                <Modal isOpen={this.state.modal === "add-to-dashboard"}>
                    <AddToDashSelectDashModal
                        card={this.props.card}
                        dashboardApi={this.props.dashboardApi}
                        closeFn={() => this.setState({ modal: null })}
                        notifyCardAddedToDashFn={this.props.notifyCardAddedToDashFn}
                    />
                </Modal>

        );
    }
});
<commit_msg>Clean the query before saving<commit_after>'use strict';
/*global setTimeout, clearTimeout*/

import ActionButton from 'metabase/components/ActionButton.react';
import AddToDashboard from './add_to_dashboard.react';
import AddToDashSelectDashModal from '../components/AddToDashSelectDashModal.react';
import CardFavoriteButton from './card_favorite_button.react';
import DeleteQuestionModal from '../components/DeleteQuestionModal.react';
import Header from "metabase/components/Header.react";
import HistoryModal from "metabase/components/HistoryModal.react";
import Icon from "metabase/components/Icon.react";
import Modal from "metabase/components/Modal.react";
import ModalWithTrigger from "metabase/components/ModalWithTrigger.react";
import QueryModeToggle from './query_mode_toggle.react';
import QuestionSavedModal from '../components/QuestionSavedModal.react';
import SaveQuestionModal from '../components/SaveQuestionModal.react';

import Query from "metabase/lib/query";

import inflection from "inflection";
import cx from "classnames";

export default React.createClass({
    displayName: 'QueryHeader',
    propTypes: {
        card: React.PropTypes.object.isRequired,
        tableMetadata: React.PropTypes.object, // can't be required, sometimes null
        cardApi: React.PropTypes.func.isRequired,
        dashboardApi: React.PropTypes.func.isRequired,
        revisionApi: React.PropTypes.func.isRequired,
        notifyCardChangedFn: React.PropTypes.func.isRequired,
        notifyCardAddedToDashFn: React.PropTypes.func.isRequired,
        reloadCardFn: React.PropTypes.func.isRequired,
        setQueryModeFn: React.PropTypes.func.isRequired,
        isShowingDataReference: React.PropTypes.bool.isRequired,
        toggleDataReferenceFn: React.PropTypes.func.isRequired,
        cardIsNewFn: React.PropTypes.func.isRequired,
        cardIsDirtyFn: React.PropTypes.func.isRequired
    },

    getInitialState: function() {
        return {
            recentlySaved: null,
            modal: null,
            revisions: null
        };
    },

    resetStateOnTimeout: function() {
        // clear any previously set timeouts then start a new one
        clearTimeout(this.timeout);
        this.timeout = setTimeout(() => {
            if (this.isMounted()) {
                this.setState({
                    recentlySaved: null
                });
            }
        }, 5000);
    },

    onCreate: async function(card) {
        let newCard = await this.props.cardApi.create(card).$promise;
        this.props.notifyCardCreatedFn(newCard);
        if (this.isMounted()) {
            // update local state to reflect new card state
            this.setState({ recentlySaved: "created", modal: "saved" }, this.resetStateOnTimeout);
        }
    },

    onSave: async function() {
        let card = this.props.card;

        if (card.dataset_query.query) {
            Query.cleanQuery(card.dataset_query.query);
        }

        let updatedCard = await this.props.cardApi.update(card).$promise;
        if (this.props.fromUrl) {
            this.onGoBack();
            return;
        }
        this.props.notifyCardUpdatedFn(updatedCard);
        if (this.isMounted()) {
            // update local state to reflect new card state
            this.setState({ recentlySaved: "updated" }, this.resetStateOnTimeout);
        }
    },

    onCancel: async function() {
        this.onGoBack();
    },

    onDelete: async function () {
        await this.props.cardApi.delete({ 'cardId': this.props.card.id }).$promise;
        this.onGoBack();
    },

    setQueryMode: function(mode) {
        this.props.setQueryModeFn(mode);
    },

    toggleDataReference: function() {
        this.props.toggleDataReferenceFn();
    },

    setCardAttribute: function(attribute, value) {
        this.props.card[attribute] = value;
        this.props.notifyCardChangedFn(this.props.card);
    },

    onGoBack: function() {
        this.props.onChangeLocation(this.props.fromUrl || "/");
    },

    onFetchRevisions: async function({ entity, id }) {
        var revisions = await this.props.revisionApi.list({ entity, id }).$promise;
        this.setState({ revisions });
    },

    onRevertToRevision: function({ entity, id, revision_id }) {
        return this.props.revisionApi.revert({ entity, id, revision_id }).$promise;
    },

    onRevertedRevision: function() {
        this.props.reloadCardFn();
        this.refs.cardHistory.toggle();
    },

    getHeaderButtons: function() {
        var buttons = [];

        if (this.props.cardIsNewFn() && this.props.cardIsDirtyFn()) {
            buttons.push(
                <ModalWithTrigger
                    ref="saveModal"
                    triggerClasses="h4 px1 text-grey-4 text-brand-hover text-uppercase"
                    triggerElement="Save"
                >
                    <SaveQuestionModal
                        card={this.props.card}
                        tableMetadata={this.props.tableMetadata}
                        saveFn={this.onCreate}
                        closeFn={() => this.refs.saveModal.toggle()}
                    />
                </ModalWithTrigger>
            );
        }

        if (!this.props.cardIsNewFn()) {
            buttons.push(
                <ModalWithTrigger
                    ref="cardHistory"
                    triggerElement={<Icon name="history" width="16px" height="16px" />}
                >
                    <HistoryModal
                        revisions={this.state.revisions}
                        entityType="card"
                        entityId={this.props.card.id}
                        onFetchRevisions={this.onFetchRevisions}
                        onRevertToRevision={this.onRevertToRevision}
                        onClose={() => this.refs.cardHistory.toggle()}
                        onReverted={this.onRevertedRevision}
                    />
                </ModalWithTrigger>
            );
        }

        if (this.props.cardIsNewFn() && !this.props.cardIsDirtyFn()) {
            buttons.push(
                <QueryModeToggle
                    currentQueryMode={this.props.card.dataset_query.type}
                    setQueryModeFn={this.setQueryMode}
                />
            );
        }

        var dataReferenceButtonClasses = cx({
            'mx1': true,
            'transition-color': true,
            'text-grey-4': !this.props.isShowingDataReference,
            'text-brand': this.props.isShowingDataReference,
            'text-brand-hover': !this.state.isShowingDataReference
        });
        var dataReferenceButton = (

                <Icon name='reference' width="16px" height="16px" onClick={this.toggleDataReference}></Icon>

        );

        return [buttons, [dataReferenceButton]];
    },

    getEditingButtons: function() {
        var editingButtons = [];
        editingButtons.push(
            <ActionButton
                actionFn={() => this.onSave()}
                className="Button Button--small Button--primary text-uppercase"
                normalText="Save"
                activeText="Saving…"
                failedText="Save failed"
                successText="Saved"
            />
        );
        editingButtons.push(
             this.onCancel()}>Cancel
        );
        editingButtons.push(
            <ModalWithTrigger
                ref="deleteModal"
                triggerClasses="Button Button--small text-uppercase"
                triggerElement="Delete"
            >
                <DeleteQuestionModal
                    card={this.props.card}
                    deleteCardFn={() => this.onDelete()}
                    closeFn={() => this.refs.deleteModal.toggle()}
                />
            </ModalWithTrigger>
        );
        return editingButtons;
    },

    render: function() {
        var subtitleText;
        if (this.props.card) {
            if (this.props.card.dashboard_count > 0) {
                subtitleText = "Changes will be reflected in " + this.props.card.dashboard_count + " " + inflection.inflect("dashboard", this.props.card.dashboard_count) + " and can be reverted.";
            } else {
                subtitleText = "Changes can be reverted."
            }
        }

        return (
            <Header
                objectType="question"
                item={this.props.card}
                isEditing={!this.props.cardIsNewFn() && this.props.card.is_creator}
                isEditingInfo={!this.props.cardIsNewFn() && this.props.card.is_creator}
                headerButtons={this.getHeaderButtons()}
                editingTitle="You are editing a saved question"
                editingSubtitle={subtitleText}
                editingButtons={this.getEditingButtons()}
                setItemAttributeFn={this.setCardAttribute}
            >
                <Modal isOpen={this.state.modal === "saved"}>
                    <QuestionSavedModal
                        addToDashboardFn={() => this.setState({ modal: "add-to-dashboard" })}
                        closeFn={() => this.setState({ modal: null })}
                    />
                </Modal>
                <Modal isOpen={this.state.modal === "add-to-dashboard"}>
                    <AddToDashSelectDashModal
                        card={this.props.card}
                        dashboardApi={this.props.dashboardApi}
                        closeFn={() => this.setState({ modal: null })}
                        notifyCardAddedToDashFn={this.props.notifyCardAddedToDashFn}
                    />
                </Modal>

        );
    }
});
<|endoftext|>


<commit_before>define(['app', 'text!./announcement.html', 'filters/html-sanitizer'], function(app, template) {

    app.directive("cctvFrameAnnouncement", ['$filter', '$window', function($filter, $window) {
        return {
            restrict: 'E',
            template: template,
            replace: true,
            scope: {
                content: '='
            },
            link: function($scope, element) {

                $scope.html = $scope.content.html;

                var htmlEditorTools = element.find("#htmlEditorTools button");
                var htmlEditor      = element.find("#htmlEditor");

                htmlEditorTools.tooltip();
                htmlEditor.keypress(function(){ updateHtml();});
                htmlEditor.keyup   (function(){ updateHtml();});
                htmlEditor.blur    (function(){ updateHtml();});

                $scope.execCommand=function(evt, cmd, options) {
                //    evt.stopPropagation();

                    if(options && options.useCss)
                        document.execCommand('styleWithCSS', false, true);

                    if(!options.arg && options.prompt) {
                        options.arg = $window.prompt(options.prompt);

                        if(!options.arg)
                            return;
                    }

                    document.execCommand(cmd,false, (options && options.arg)||null);

                    if(options && options.useCss)
                        document.execCommand('styleWithCSS', false, false);

                    updateHtml();
                };

                //========================================
                //
                //========================================
                function updateHtml() {
                    $scope.$applyAsync(function(){
                        var html         = htmlEditor.html();
                        var sanitizeHtml = $filter('sanitizeHtml')(htmlEditor.html());

                        if(html!=sanitizeHtml)
                            $scope.html = sanitizeHtml;

                        $scope.content.html = sanitizeHtml;
                    });
                }
            }
        };
    }]);
});
<commit_msg>Fix `undefined` bug<commit_after>define(['app', 'text!./announcement.html', 'filters/html-sanitizer'], function(app, template) {

    app.directive("cctvFrameAnnouncement", ['$filter', '$window', function($filter, $window) {
        return {
            restrict: 'E',
            template: template,
            replace: true,
            scope: {
                content: '='
            },
            link: function($scope, element) {

                $scope.html = $scope.content.html;

                var htmlEditorTools = element.find("#htmlEditorTools button");
                var htmlEditor      = element.find("#htmlEditor");

                htmlEditorTools.tooltip();
                htmlEditor.keypress(function(){ updateHtml();});
                htmlEditor.keyup   (function(){ updateHtml();});
                htmlEditor.blur    (function(){ updateHtml();});

                $scope.execCommand=function(evt, cmd, options) {

                    options = options || {};

                    if(options && options.useCss)
                        document.execCommand('styleWithCSS', false, true);

                    if(!options.arg && options.prompt) {
                        options.arg = $window.prompt(options.prompt);

                        if(!options.arg)
                            return;
                    }

                    document.execCommand(cmd,false, (options && options.arg)||null);

                    if(options && options.useCss)
                        document.execCommand('styleWithCSS', false, false);

                    updateHtml();
                };

                //========================================
                //
                //========================================
                function updateHtml() {
                    $scope.$applyAsync(function(){
                        var html         = htmlEditor.html();
                        var sanitizeHtml = $filter('sanitizeHtml')(htmlEditor.html());

                        if(html!=sanitizeHtml)
                            $scope.html = sanitizeHtml;

                        $scope.content.html = sanitizeHtml;
                    });
                }
            }
        };
    }]);
});
<|endoftext|>


<commit_before>'use strict';
var yeoman = require('yeoman-generator');
var fs = require('fs');
var path = require('path');
var httpStatusCodes = ['204', '404', '500'];
var writeYaml = require('write-yaml');

module.exports = yeoman.Base.extend({
  prompting: function () {
    console.log('ADD HTTPCODES');
  },
  end: function () {
    var cb = this.async();
    // console.log('options', this.config.getAll());
    var configOptions = this.config.getAll();
    addHTTPCodes(configOptions, cb);
  }
});

//
// FORMATING FUNCTIONS
//
var capitalizeFirstLetter = function (string) {
  return string.charAt(0).toUpperCase() + string.slice(1);
};
//
// JOB HANDELING FUNCTIONS
//
var addHTTPCodes = function (options, cb) {
  /*
  **  Reading the copied json file and adding the required paramaters
  */
  fs.readFile(path.resolve('swaggerConfig/input.json'), 'utf8', function (error, jsonObj) {
    if (error) {
      throw error;
    }
    // console.log('WE MADE IT', options);
    var inputJSON = JSON.parse(jsonObj);
    var relationalObjects = options.APIRelationships;
    relationalObjects.forEach(function (relation) {
      if (relation.Relationship === 'BelongsTo') {
        addToPaths(inputJSON, options, relation.ToResource, relation.FromResource);
      } else {
        addToPaths(inputJSON, options, relation.FromResource, relation.ToResource);
      }
    });
    // /*
    // ** saving final json file for future references
    // */
    fs.writeFile('swaggerConfig/input.json', JSON.stringify(inputJSON), function (err) {
      if (err) {
        return console.log(err);
      }
      console.log('The Json file is saved!');
    /*
    **  Creating the Yaml file from the json
    */
      writeYaml('api/swagger.yaml', inputJSON, function (err) {
        if (err) {
          return console.log(err);
        }
        console.log('The Yaml file is saved!');
        cb();
      });
    });
  });
};
/*
** This method add's user selected paths with appropriate error codes
*/
var addToPaths = function (inputJSON, options, fromRelationship, toRelationship) {
  var pathRelation = '/' + fromRelationship + 's/{id}/' + toRelationship;
  if (inputJSON.paths === {} || typeof inputJSON.paths[pathRelation] === 'undefined') {
    inputJSON.paths[pathRelation] = {};
  }
  //
  // For each httpMethod
  //
  for (var i = 0; i < options.JSONExtraction.length; i++) {
    if (options.JSONExtraction[i].resourceName === fromRelationship) {
      var httpMethods = options.JSONExtraction[i].HTTPMethods;
      var apiObject = options.JSONExtraction[i];
    }
  }
  httpMethods.forEach(function (httpMethod) {
    inputJSON.paths[pathRelation][httpMethod] = {};
    var httpOptions = {};
    httpOptions.tags = [capitalizeFirstLetter(fromRelationship), capitalizeFirstLetter(toRelationship)];
    httpOptions.description = capitalizeFirstLetter(httpMethod) + 's all ' + toRelationship + ' from ' + fromRelationship + ' from the system that the user has access to';
    httpOptions.operationId = httpMethod + capitalizeFirstLetter(toRelationship) + 's';
    httpOptions.produces = options.APIOverviewProps.APIProduces;
    httpOptions.responses = {};
    //
    // Adding HTTP Response Code
    //
    var responses = {};
    httpStatusCodes.forEach(function (httpStatusCode) {
      if (httpMethod === 'get' && httpStatusCode === '204') {
        httpStatusCode = '200';
      }
      responses[httpStatusCode] = {};
      responses[httpStatusCode].description = fromRelationship + 'and ' + toRelationship + ' response';
      responses[httpStatusCode].schema = {};
      if (httpStatusCode === '200' || httpStatusCode === '204') {
        responses[httpStatusCode].schema.type = 'array';
        responses[httpStatusCode].schema.items = {};
        responses[httpStatusCode].schema.items.$ref = '#/definitions/' + apiObject.resourceName;
      } else {
        responses[httpStatusCode].schema.type = 'object';
      }
    });
    httpOptions.responses = responses;
    inputJSON.paths[pathRelation][httpMethod] = httpOptions;
  });
};
<commit_msg>updated http-codes-yaml to show relation in swagger<commit_after>'use strict';
var yeoman = require('yeoman-generator');
var fs = require('fs');
var path = require('path');
var httpStatusCodes = ['204', '404', '500'];
var writeYaml = require('write-yaml');

module.exports = yeoman.Base.extend({
  prompting: function () {
    console.log('ADD HTTPCODES');
  },
  end: function () {
    var cb = this.async();
    // console.log('options', this.config.getAll());
    var configOptions = this.config.getAll();
    addHTTPCodes(configOptions, cb);
  }
});

//
// FORMATING FUNCTIONS
//
var capitalizeFirstLetter = function (string) {
  return string.charAt(0).toUpperCase() + string.slice(1);
};
//
// JOB HANDELING FUNCTIONS
//
var addHTTPCodes = function (options, cb) {
  /*
  **  Reading the copied json file and adding the required paramaters
  */
  fs.readFile(path.resolve('swaggerConfig/input.json'), 'utf8', function (error, jsonObj) {
    if (error) {
      throw error;
    }
    // console.log('WE MADE IT', options);
    var inputJSON = JSON.parse(jsonObj);
    var relationalObjects = options.APIRelationships;
    relationalObjects.forEach(function (relation) {
      if (relation.Relationship === 'BelongsTo') {
        addToPaths(inputJSON, options, relation.ToResource, relation.FromResource);
      } else {
        addToPaths(inputJSON, options, relation.FromResource, relation.ToResource);
      }
    });
    // /*
    // ** saving final json file for future references
    // */
    fs.writeFile('swaggerConfig/input.json', JSON.stringify(inputJSON), function (err) {
      if (err) {
        return console.log(err);
      }
      console.log('The Json file is saved!');
    /*
    **  Creating the Yaml file from the json
    */
      writeYaml('swaggerConfig/input.yaml', inputJSON, function (err) {
        if (err) {
          return console.log(err);
        }
        console.log('The Yaml file is saved!');
        cb();
      });
    });
  });
};
/*
** This method add's user selected paths with appropriate error codes
*/
var addToPaths = function (inputJSON, options, fromRelationship, toRelationship) {
  var pathRelation = '/' + fromRelationship + 's/{id}/' + toRelationship;
  if (inputJSON.paths === {} || typeof inputJSON.paths[pathRelation] === 'undefined') {
    inputJSON.paths[pathRelation] = {};
  }
  //
  // For each httpMethod
  //
  for (var i = 0; i < options.JSONExtraction.length; i++) {
    if (options.JSONExtraction[i].resourceName === fromRelationship) {
      var httpMethods = options.JSONExtraction[i].HTTPMethods;
      var apiObject = options.JSONExtraction[i];
    }
  }
  httpMethods.forEach(function (httpMethod) {
    inputJSON.paths[pathRelation][httpMethod] = {};
    var httpOptions = {};
    httpOptions.tags = [capitalizeFirstLetter(fromRelationship), capitalizeFirstLetter(toRelationship)];
    httpOptions.description = capitalizeFirstLetter(httpMethod) + 's all ' + toRelationship + ' from ' + fromRelationship + ' from the system that the user has access to';
    httpOptions.operationId = httpMethod + capitalizeFirstLetter(toRelationship) + 's';
    httpOptions.produces = options.APIOverviewProps.APIProduces;
    httpOptions.parameters = [];
    var outline = {
      name: 'id',
      in: 'path',
      type: 'string',
      required: true
    };
    httpOptions.parameters.push(outline);
    httpOptions.responses = {};
    //
    // Adding HTTP Response Code
    //
    var responses = {};
    httpStatusCodes.forEach(function (httpStatusCode) {
      if (httpMethod === 'get' && httpStatusCode === '204') {
        httpStatusCode = '200';
      }
      responses[httpStatusCode] = {};
      responses[httpStatusCode].description = fromRelationship + 'and ' + toRelationship + ' response';
      responses[httpStatusCode].schema = {};
      if (httpStatusCode === '200' || httpStatusCode === '204') {
        responses[httpStatusCode].schema.type = 'array';
        responses[httpStatusCode].schema.items = {};
        responses[httpStatusCode].schema.items.$ref = '#/definitions/' + apiObject.resourceName;
      } else {
        responses[httpStatusCode].schema.type = 'object';
      }
    });
    httpOptions.responses = responses;
    inputJSON.paths[pathRelation][httpMethod] = httpOptions;
  });
};
<|endoftext|>


<commit_before>/*    Copyright 2016 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

let log = require('../net2/logger.js')(__filename);

let config = require('../net2/config.js').getConfig();

let sensors = [];

function initSensors() {
  let sensorConfigs = config.sensors;

  if(!sensorConfigs)
    return;

  Object.keys(sensorConfigs).forEach((sensorName) => {
    try {
      let fp = './' + sensorName + '.js';
      let s = require(fp);
      let ss = new s();
      ss.setConfig(sensorConfigs[sensorName]);
      sensors.push(ss);
    } catch(err) {
      log.error(`Failed to load sensor: ${sensorName}: ${err}`)
    }
  });
}

function run() {
  sensors.forEach((s) => {
    log.info("Installing Sensor:", s.constructor.name, {});
    s.run();
  });
}

module.exports = {
  initSensors:initSensors,
  run:run
};
<commit_msg>add protection on sensor installation<commit_after>/*    Copyright 2016 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

let log = require('../net2/logger.js')(__filename);

let config = require('../net2/config.js').getConfig();

let sensors = [];

function initSensors() {
  let sensorConfigs = config.sensors;

  if(!sensorConfigs)
    return;

  Object.keys(sensorConfigs).forEach((sensorName) => {
    try {
      let fp = './' + sensorName + '.js';
      let s = require(fp);
      let ss = new s();
      ss.setConfig(sensorConfigs[sensorName]);
      sensors.push(ss);
    } catch(err) {
      log.error(`Failed to load sensor: ${sensorName}: ${err}`)
    }
  });
}

function run() {
  sensors.forEach((s) => {
    log.info("Installing Sensor:", s.constructor.name, {});
    try {
      s.run()
    } catch(err) {
      log.error(`Failed to install sensor: ${s.constructor.name}, err: ${err}`)
    }
  });
}

module.exports = {
  initSensors:initSensors,
  run:run
};
<|endoftext|>


<commit_before>module.exports = class Cipher {
rot(text, point){

  let value =[]
  let res = []
  for (let key of text){
    value.push(key.charCodeAt(key))
  }
  value = value.map(x => x+point)
  for (let key of value){
    if(key > 122){
      let aux = key - 122
      key = 97 + aux-1
    }
    res.push(String.fromCharCode(key))
  }
  return res.join('')
}
}

//cipher = new Cipher()
//console.log(cipher.rot('xyz', 2))
<commit_msg>Update cipher.js<commit_after>module.exports = class Cipher {
rot(text, point){
module.exports = class Cipher {
rot(text, point){
  let caracteres = 'abcdefghijklmnopqrstuvwxyz'.split('')
  let resp =''
  const verific = ((a, b)=> a+b > 25? (a+b)-26:a+b)
  text.toLowerCase().split('').forEach(x =>{
    let res = caracteres.indexOf(x)
    res = verific(res, point);
    resp += caracteres[res]
  })
  return resp
}
}
//cipher = new Cipher()
//console.log(cipher.rot('xyz', 2))
<|endoftext|>