<commit_before>import _ from 'underscore';
import is from 'is_js';
import app from '../../app';
import { getIndexedCountries } from '../../data/countries';
import { events as listingEvents, shipsFreeToMe } from './';
import { decimalToInteger, integerToDecimal } from '../../utils/currency';
import { defaultQuantityBaseUnit } from '../../data/cryptoListingCurrencies';
import BaseModel from '../BaseModel';
import Item from './Item';
import Metadata from './Metadata';
import ShippingOptions from '../../collections/listing/ShippingOptions.js';
import Coupons from '../../collections/listing/Coupons.js';

export default class extends BaseModel {
  constructor(attrs, options = {}) {
    super(attrs, options);
    this.guid = options.guid;
  }

  url() {
    // url is handled by sync, but backbone bombs if I don't have
    // something explicitly set
    return 'use-sync';
  }

  defaults() {
    return {
      termsAndConditions: '',
      refundPolicy: '',
      item: new Item(),
      metadata: new Metadata(),
      shippingOptions: new ShippingOptions(),
      coupons: new Coupons(),
    };
  }

  isNew() {
    return !this.get('slug');
  }

  get nested() {
    return {
      item: Item,
      metadata: Metadata,
      shippingOptions: ShippingOptions,
      coupons: Coupons,
    };
  }

  get shipsFreeToMe() {
    return shipsFreeToMe(this);
  }

  get max() {
    return {
      refundPolicyLength: 10000,
      termsAndConditionsLength: 10000,
      couponCount: 30,
    };
  }

  get isOwnListing() {
    if (this.guid === undefined) {
      throw new Error('Unable to determine ownListing ' +
        'because a guid has not been set on this model.');
    }

    return app.profile.id === this.guid;
  }

  get isCrypto() {
    return this.get('metadata')
      .get('contractType') === 'CRYPTOCURRENCY';
  }

  get price() {
    if (this.isCrypto) {
      return {
        amount: 1,
        currencyCode: this.get('metadata')
          .get('coinType'),
      };
    }

    return {
      amount: this.get('item')
        .get('price'),
      currencyCode: this.get('metadata')
        .get('pricingCurrency'),
    };
  }

  /**
   * Returns a new instance of the listing with mostly identical attributes. Certain
   * attributes like slug and hash will be stripped since they are not appropriate
   * if this listing is being used as a template for a new listing. This differs from
   * clone() which will maintain identical attributes.
   */
  cloneListing() {
    const clone = this.clone();
    clone.unset('slug');
    clone.unset('hash');
    clone.guid = this.guid;
    clone.lastSyncedAttrs = {};
    return clone;
  }

  validate(attrs) {
    let errObj = {};
    const addError = (fieldName, error) => {
      errObj[fieldName] = errObj[fieldName] || [];
      errObj[fieldName].push(error);
    };
    const metadata = {
      ...this.get('metadata').toJSON(),
      ...attrs.metadata,
    };
    const contractType = metadata.contractType;
    const item = {
      ...this.get('item').toJSON(),
      ...attrs.item,
    };

    if (attrs.refundPolicy) {
      if (is.not.string(attrs.refundPolicy)) {
        addError('refundPolicy', 'The return policy must be of type string.');
      } else if (attrs.refundPolicy.length > this.max.refundPolicyLength) {
        addError('refundPolicy', app.polyglot.t('listingModelErrors.returnPolicyTooLong'));
      }
    }

    if (attrs.termsAndConditions) {
      if (is.not.string(attrs.termsAndConditions)) {
        addError('termsAndConditions', 'The terms and conditions must be of type string.');
      } else if (attrs.termsAndConditions.length > this.max.termsAndConditionsLength) {
        addError('termsAndConditions',
          app.polyglot.t('listingModelErrors.termsAndConditionsTooLong'));
      }
    }

    if (contractType === 'PHYSICAL_GOOD') {
      if (!attrs.shippingOptions.length) {
        addError('shippingOptions', app.polyglot.t('listingModelErrors.provideShippingOption'));
      }
    }

    if (contractType === 'CRYPTOCURRENCY') {
      if (!metadata || !metadata.coinType || typeof metadata.coinType !== 'string') {
        addError('metadata.coinType', 'The coin type must be provided as a string.');
      }

      if (metadata && typeof metadata.pricingCurrency !== 'undefined') {
        addError('metadata.pricingCurrency', 'The pricing currency should not be set on ' +
          'cryptocurrency listings.');
      }

      if (item && typeof item.price !== 'undefined') {
        addError('item.price', 'The price should not be set on cryptocurrency ' +
          'listings.');
      }

      if (item && typeof item.condition !== 'undefined') {
        addError('item.condition', 'The condition should not be set on cryptocurrency ' +
          'listings.');
      }

      if (item && typeof item.quantity !== 'undefined') {
        addError('item.quantity', 'The quantity should not be set on cryptocurrency ' +
          'listings.');
      }
    } else {
      if (item && typeof item.cryptoQuantity !== 'undefined') {
        addError('item.cryptoQuantity', 'The cryptoQuantity should only be set on cryptocurrency ' +
          'listings.');
      }
    }

    if (attrs.coupons.length > this.max.couponCount) {
      addError('coupons', app.polyglot.t('listingModelErrors.tooManyCoupons',
        { maxCouponCount: this.max.couponCount }));
    }

    errObj = this.mergeInNestedErrors(errObj);

    if (contractType === 'CRYPTOCURRENCY') {
      // Remove the validation of certain fields that should not be set for
      // cryptocurrency listings.
      delete errObj['metadata.pricingCurrency'];
      delete errObj['item.price'];
      delete errObj['item.condition'];
      delete errObj['item.quantity'];
    } else {
      delete errObj['item.cryptoQuantity'];
    }

    // Coupon price discount cannot exceed the item price.
    attrs.coupons.forEach(coupon => {
      const priceDiscount = coupon.get('priceDiscount');

      if (typeof priceDiscount !== 'undefined' && priceDiscount >= attrs.item.get('price')) {
        addError(`coupons[${coupon.cid}].priceDiscount`,
          app.polyglot.t('listingModelErrors.couponsPriceTooLarge'));
      }
    });

    if (Object.keys(errObj).length) return errObj;

    return undefined;
  }

  sync(method, model, options) {
    let returnSync = 'will-set-later';

    if (method === 'read') {
      if (!this.guid) {
        throw new Error('In order to fetch a listing, a guid must be set on the model instance.');
      }

      const slug = this.get('slug');

      if (!slug) {
        throw new Error('In order to fetch a listing, a slug must be set as a model attribute.');
      }

      if (this.isOwnListing) {
        options.url = options.url ||
          app.getServerUrl(`ob/listing/${slug}`);
      } else {
        options.url = options.url ||
          app.getServerUrl(`ob/listing/${this.guid}/${slug}`);
      }
    } else {
      if (method !== 'delete') {
        options.url = options.url || app.getServerUrl('ob/listing/');
        // it's a create or update
        options.attrs = options.attrs || this.toJSON();

        // convert price fields
        if (options.attrs.item.price) {
          const price = options.attrs.item.price;
          options.attrs.item.price = decimalToInteger(price,
            options.attrs.metadata.pricingCurrency);
        }

        options.attrs.shippingOptions.forEach(shipOpt => {
          shipOpt.services.forEach(service => {
            if (typeof service.price === 'number') {
              service.price = decimalToInteger(service.price,
                options.attrs.metadata.pricingCurrency);
            }

            if (typeof service.additionalItemPrice === 'number') {
              service.additionalItemPrice = decimalToInteger(service.additionalItemPrice,
                options.attrs.metadata.pricingCurrency);
            }
          });
        });

        options.attrs.coupons.forEach(coupon => {
          if (typeof coupon.priceDiscount === 'number') {
            coupon.priceDiscount = decimalToInteger(coupon.priceDiscount,
              options.attrs.metadata.pricingCurrency);
          }
        });

        const baseUnit = options.attrs.metadata.coinDivisibility =
          options.attrs.metadata.coinDivisibility || defaultQuantityBaseUnit;

        if (options.attrs.metadata.contractType === 'CRYPTOCURRENCY') {
          // round to ensure integer
          options.attrs.item.cryptoQuantity =
            Math.round(options.attrs.item.cryptoQuantity * baseUnit);

          // Don't send over the price on crypto listings.
          delete options.attrs.price;
        }
        // END - convert price fields

        // If providing a quanitity and / or productID on the Item and not
        // providing any SKUs, then we'll send item.quantity and item.productID
        // in as a "dummy" SKU (as the server expects). If you are providing any
        // SKUs, then item.quantity and item.productID will be ignored.
        if (!options.attrs.item.skus.length) {
          const dummySku = {};

          if (options.attrs.metadata.contractType === 'CRYPTOCURRENCY') {
            dummySku.quantity = options.attrs.item.cryptoQuantity;
          } else if (typeof options.attrs.item.quantity === 'number') {
            dummySku.quantity = options.attrs.item.quantity;
          }

          if (typeof options.attrs.item.productID === 'string' &&
            options.attrs.item.productID.length) {
            dummySku.productID = options.attrs.item.productID;
          }

          if (Object.keys(dummySku).length) {
            options.attrs.item.skus = [dummySku];
          }
        } else {
          options.attrs.item.skus.forEach(sku => {
            if (typeof sku.surcharge === 'number') {
              sku.surcharge = decimalToInteger(sku.surcharge,
                options.attrs.metadata.pricingCurrency);
            }
          });
        }

        delete options.attrs.item.productID;
        delete options.attrs.item.quantity;

        // Our Sku has an infinteInventory boolean attribute, but the server
        // is expecting a quantity negative quantity in that case.
        options.attrs.item.skus.forEach(sku => {
          if (sku.infiniteInventory) {
            sku.quantity = -1;
          }

          delete sku.infiniteInventory;
        });

        // remove the hash
        delete options.attrs.hash;

        // If all countries are individually provided as shipping regions, we'll send
        // 'ALL' to the server.
        options.attrs.shippingOptions.forEach(shipOpt => {
          if (_.isEqual(Object.keys(getIndexedCountries()), shipOpt.regions)) {
            shipOpt.regions = ['ALL'];
          }
        });
      } else {
        options.url = options.url ||
          app.getServerUrl(`ob/listing/${this.get('slug')}`);
      }
    }

    returnSync = super.sync(method, model, options);

    const eventOpts = {
      xhr: returnSync,
      url: options.url,
    };

    if (method === 'create' || method === 'update') {
      const attrsBeforeSync = this.lastSyncedAttrs;

      returnSync.done(data => {
        const hasChanged = () => (!_.isEqual(attrsBeforeSync, this.toJSON()));

        if (data.slug) {
          this.set('slug', data.slug);
        }

        listingEvents.trigger('saved', this, {
          ...eventOpts,
          created: method === 'create',
          slug: this.get('slug'),
          prev: attrsBeforeSync,
          hasChanged,
        });
      });
    } else if (method === 'delete') {
      listingEvents.trigger('destroying', this, {
        ...eventOpts,
        slug: this.get('slug'),
      });

      returnSync.done(() => {
        listingEvents.trigger('destroy', this, {
          ...eventOpts,
          slug: this.get('slug'),
        });
      });
    }

    return returnSync;
  }

  parse(response) {
    this.unparsedResponse = JSON.parse(JSON.stringify(response)); // deep clone
    const parsedResponse = response.listing;

    if (parsedResponse) {
      const isCrypto = parsedResponse.metadata &&
        parsedResponse.metadata.contractType === 'CRYPTOCURRENCY';

      // set the hash
      parsedResponse.hash = response.hash;

      // convert price fields
      if (parsedResponse.item) {
        const price = parsedResponse.item.price;
        const cur = parsedResponse.metadata &&
          parsedResponse.metadata.pricingCurrency;

        if (price) {
          parsedResponse.item.price = integerToDecimal(price, cur);
        }
      }

      if (parsedResponse.shippingOptions && parsedResponse.shippingOptions.length) {
        parsedResponse.shippingOptions.forEach((shipOpt, shipOptIndex) => {
          if (shipOpt.services && shipOpt.services.length) {
            shipOpt.services.forEach((service, serviceIndex) => {
              const price = service.price;
              const cur = parsedResponse.metadata &&
                parsedResponse.metadata.pricingCurrency;

              if (typeof price === 'number') {
                parsedResponse.shippingOptions[shipOptIndex]
                  .services[serviceIndex].price = integerToDecimal(price, cur);
              } else {
                // This is necessary because of this bug:
                // https://github.com/OpenBazaar/openbazaar-go/issues/178
                parsedResponse.shippingOptions[shipOptIndex]
                  .services[serviceIndex].price = 0;
              }

              const price2 = service.additionalItemPrice;
              if (typeof price2 === 'number') {
                parsedResponse.shippingOptions[shipOptIndex]
                  .services[serviceIndex].additionalItemPrice = integerToDecimal(price2, cur);
              } else {
                // This is necessary because of this bug:
                // https://github.com/OpenBazaar/openbazaar-go/issues/178
                parsedResponse.shippingOptions[shipOptIndex]
                  .services[serviceIndex].additionalItemPrice = 0;
              }
            });
          }

          // If the shipping regions are set to 'ALL', we'll replace with a list of individual
          // countries, which is what our UI is designed to work with.
          if (shipOpt.regions && shipOpt.regions.length && shipOpt.regions[0] === 'ALL') {
            parsedResponse.shippingOptions[shipOptIndex].regions =
              Object.keys(getIndexedCountries());
          }
        });
      }

      if (parsedResponse.coupons && parsedResponse.coupons.length) {
        parsedResponse.coupons.forEach((coupon, couponIndex) => {
          if (typeof coupon.priceDiscount === 'number') {
            const price = parsedResponse.coupons[couponIndex].priceDiscount;
            const cur = parsedResponse.metadata && parsedResponse.metadata.pricingCurrency;

            parsedResponse.coupons[couponIndex].priceDiscount =
              integerToDecimal(price, cur);
          }
        });
      }

      // Re-organize variant structure so a "dummy" SKU (if present) has its quanitity
      // and productID moved to be attributes of the Item model
      if (parsedResponse.item && parsedResponse.item.skus &&
        parsedResponse.item.skus.length === 1 &&
        typeof parsedResponse.item.skus[0].variantCombo === 'undefined') {
        const dummySku = parsedResponse.item.skus[0];

        if (isCrypto) {
          parsedResponse.item.cryptoQuantity = dummySku.quantity /
            parsedResponse.metadata.coinDivisibility;
        } else {
          parsedResponse.item.quantity = dummySku.quantity;
        }

        parsedResponse.item.productID = dummySku.productID;
      }

      if (parsedResponse.item && parsedResponse.item.skus) {
        parsedResponse.item.skus.forEach(sku => {
          // If a sku quantity is set to less than 0, we'll set the
          // infinite inventory flag.
          if (sku.quantity < 0) {
            sku.infiniteInventory = true;
          } else {
            sku.infiniteInventory = false;
          }
          // convert the surcharge
          const surcharge = sku.surcharge;
          const cur = parsedResponse.metadata && parsedResponse.metadata.pricingCurrency;

          if (surcharge) {
            sku.surcharge = integerToDecimal(surcharge, cur);
          }
        });
        // END - convert price fields
      }

      if (parsedResponse.metadata) {
        parsedResponse.metadata.acceptedCurrencies =
          parsedResponse.metadata.acceptedCurrencies || [];
      }
    }

    return parsedResponse;
  }
}
<commit_msg>auto generating the title for crypto listings<commit_after>import _ from 'underscore';
import is from 'is_js';
import app from '../../app';
import { getServerCurrency } from '../../data/cryptoCurrencies';
import { getIndexedCountries } from '../../data/countries';
import { events as listingEvents, shipsFreeToMe } from './';
import { decimalToInteger, integerToDecimal } from '../../utils/currency';
import { defaultQuantityBaseUnit } from '../../data/cryptoListingCurrencies';
import BaseModel from '../BaseModel';
import Item from './Item';
import Metadata from './Metadata';
import ShippingOptions from '../../collections/listing/ShippingOptions.js';
import Coupons from '../../collections/listing/Coupons.js';

export default class extends BaseModel {
  constructor(attrs, options = {}) {
    super(attrs, options);
    this.guid = options.guid;
  }

  url() {
    // url is handled by sync, but backbone bombs if I don't have
    // something explicitly set
    return 'use-sync';
  }

  defaults() {
    return {
      termsAndConditions: '',
      refundPolicy: '',
      item: new Item(),
      metadata: new Metadata(),
      shippingOptions: new ShippingOptions(),
      coupons: new Coupons(),
    };
  }

  isNew() {
    return !this.get('slug');
  }

  get nested() {
    return {
      item: Item,
      metadata: Metadata,
      shippingOptions: ShippingOptions,
      coupons: Coupons,
    };
  }

  get shipsFreeToMe() {
    return shipsFreeToMe(this);
  }

  get max() {
    return {
      refundPolicyLength: 10000,
      termsAndConditionsLength: 10000,
      couponCount: 30,
    };
  }

  get isOwnListing() {
    if (this.guid === undefined) {
      throw new Error('Unable to determine ownListing ' +
        'because a guid has not been set on this model.');
    }

    return app.profile.id === this.guid;
  }

  get isCrypto() {
    return this.get('metadata')
      .get('contractType') === 'CRYPTOCURRENCY';
  }

  get price() {
    if (this.isCrypto) {
      return {
        amount: 1,
        currencyCode: this.get('metadata')
          .get('coinType'),
      };
    }

    return {
      amount: this.get('item')
        .get('price'),
      currencyCode: this.get('metadata')
        .get('pricingCurrency'),
    };
  }

  /**
   * Returns a new instance of the listing with mostly identical attributes. Certain
   * attributes like slug and hash will be stripped since they are not appropriate
   * if this listing is being used as a template for a new listing. This differs from
   * clone() which will maintain identical attributes.
   */
  cloneListing() {
    const clone = this.clone();
    clone.unset('slug');
    clone.unset('hash');
    clone.guid = this.guid;
    clone.lastSyncedAttrs = {};
    return clone;
  }

  validate(attrs) {
    let errObj = {};
    const addError = (fieldName, error) => {
      errObj[fieldName] = errObj[fieldName] || [];
      errObj[fieldName].push(error);
    };
    const metadata = {
      ...this.get('metadata').toJSON(),
      ...attrs.metadata,
    };
    const contractType = metadata.contractType;
    const item = {
      ...this.get('item').toJSON(),
      ...attrs.item,
    };

    if (attrs.refundPolicy) {
      if (is.not.string(attrs.refundPolicy)) {
        addError('refundPolicy', 'The return policy must be of type string.');
      } else if (attrs.refundPolicy.length > this.max.refundPolicyLength) {
        addError('refundPolicy', app.polyglot.t('listingModelErrors.returnPolicyTooLong'));
      }
    }

    if (attrs.termsAndConditions) {
      if (is.not.string(attrs.termsAndConditions)) {
        addError('termsAndConditions', 'The terms and conditions must be of type string.');
      } else if (attrs.termsAndConditions.length > this.max.termsAndConditionsLength) {
        addError('termsAndConditions',
          app.polyglot.t('listingModelErrors.termsAndConditionsTooLong'));
      }
    }

    if (contractType === 'PHYSICAL_GOOD') {
      if (!attrs.shippingOptions.length) {
        addError('shippingOptions', app.polyglot.t('listingModelErrors.provideShippingOption'));
      }
    }

    if (contractType === 'CRYPTOCURRENCY') {
      if (!metadata || !metadata.coinType || typeof metadata.coinType !== 'string') {
        addError('metadata.coinType', 'The coin type must be provided as a string.');
      }

      if (metadata && typeof metadata.pricingCurrency !== 'undefined') {
        addError('metadata.pricingCurrency', 'The pricing currency should not be set on ' +
          'cryptocurrency listings.');
      }

      if (item && typeof item.price !== 'undefined') {
        addError('item.price', 'The price should not be set on cryptocurrency ' +
          'listings.');
      }

      if (item && typeof item.condition !== 'undefined') {
        addError('item.condition', 'The condition should not be set on cryptocurrency ' +
          'listings.');
      }

      if (item && typeof item.quantity !== 'undefined') {
        addError('item.quantity', 'The quantity should not be set on cryptocurrency ' +
          'listings.');
      }
    } else {
      if (item && typeof item.cryptoQuantity !== 'undefined') {
        addError('item.cryptoQuantity', 'The cryptoQuantity should only be set on cryptocurrency ' +
          'listings.');
      }
    }

    if (attrs.coupons.length > this.max.couponCount) {
      addError('coupons', app.polyglot.t('listingModelErrors.tooManyCoupons',
        { maxCouponCount: this.max.couponCount }));
    }

    errObj = this.mergeInNestedErrors(errObj);

    if (contractType === 'CRYPTOCURRENCY') {
      // Remove the validation of certain fields that should not be set for
      // cryptocurrency listings.
      delete errObj['metadata.pricingCurrency'];
      delete errObj['item.price'];
      delete errObj['item.condition'];
      delete errObj['item.quantity'];
      delete errObj['item.title'];
    } else {
      delete errObj['item.cryptoQuantity'];
    }

    // Coupon price discount cannot exceed the item price.
    attrs.coupons.forEach(coupon => {
      const priceDiscount = coupon.get('priceDiscount');

      if (typeof priceDiscount !== 'undefined' && priceDiscount >= attrs.item.get('price')) {
        addError(`coupons[${coupon.cid}].priceDiscount`,
          app.polyglot.t('listingModelErrors.couponsPriceTooLarge'));
      }
    });

    if (Object.keys(errObj).length) return errObj;

    return undefined;
  }

  sync(method, model, options) {
    let returnSync = 'will-set-later';

    if (method === 'read') {
      if (!this.guid) {
        throw new Error('In order to fetch a listing, a guid must be set on the model instance.');
      }

      const slug = this.get('slug');

      if (!slug) {
        throw new Error('In order to fetch a listing, a slug must be set as a model attribute.');
      }

      if (this.isOwnListing) {
        options.url = options.url ||
          app.getServerUrl(`ob/listing/${slug}`);
      } else {
        options.url = options.url ||
          app.getServerUrl(`ob/listing/${this.guid}/${slug}`);
      }
    } else {
      if (method !== 'delete') {
        options.url = options.url || app.getServerUrl('ob/listing/');
        // it's a create or update
        options.attrs = options.attrs || this.toJSON();

        // convert price fields
        if (options.attrs.item.price) {
          const price = options.attrs.item.price;
          options.attrs.item.price = decimalToInteger(price,
            options.attrs.metadata.pricingCurrency);
        }

        options.attrs.shippingOptions.forEach(shipOpt => {
          shipOpt.services.forEach(service => {
            if (typeof service.price === 'number') {
              service.price = decimalToInteger(service.price,
                options.attrs.metadata.pricingCurrency);
            }

            if (typeof service.additionalItemPrice === 'number') {
              service.additionalItemPrice = decimalToInteger(service.additionalItemPrice,
                options.attrs.metadata.pricingCurrency);
            }
          });
        });

        options.attrs.coupons.forEach(coupon => {
          if (typeof coupon.priceDiscount === 'number') {
            coupon.priceDiscount = decimalToInteger(coupon.priceDiscount,
              options.attrs.metadata.pricingCurrency);
          }
        });

        const baseUnit = options.attrs.metadata.coinDivisibility =
          options.attrs.metadata.coinDivisibility || defaultQuantityBaseUnit;

        if (options.attrs.metadata.contractType === 'CRYPTOCURRENCY') {
          // round to ensure integer
          options.attrs.item.cryptoQuantity =
            Math.round(options.attrs.item.cryptoQuantity * baseUnit);

          // Don't send over the price on crypto listings.
          delete options.attrs.price;
        }
        // END - convert price fields

        // If providing a quanitity and / or productID on the Item and not
        // providing any SKUs, then we'll send item.quantity and item.productID
        // in as a "dummy" SKU (as the server expects). If you are providing any
        // SKUs, then item.quantity and item.productID will be ignored.
        if (!options.attrs.item.skus.length) {
          const dummySku = {};

          if (options.attrs.metadata.contractType === 'CRYPTOCURRENCY') {
            dummySku.quantity = options.attrs.item.cryptoQuantity;
          } else if (typeof options.attrs.item.quantity === 'number') {
            dummySku.quantity = options.attrs.item.quantity;
          }

          if (typeof options.attrs.item.productID === 'string' &&
            options.attrs.item.productID.length) {
            dummySku.productID = options.attrs.item.productID;
          }

          if (Object.keys(dummySku).length) {
            options.attrs.item.skus = [dummySku];
          }
        } else {
          options.attrs.item.skus.forEach(sku => {
            if (typeof sku.surcharge === 'number') {
              sku.surcharge = decimalToInteger(sku.surcharge,
                options.attrs.metadata.pricingCurrency);
            }
          });
        }

        delete options.attrs.item.productID;
        delete options.attrs.item.quantity;

        // Our Sku has an infinteInventory boolean attribute, but the server
        // is expecting a quantity negative quantity in that case.
        options.attrs.item.skus.forEach(sku => {
          if (sku.infiniteInventory) {
            sku.quantity = -1;
          }

          delete sku.infiniteInventory;
        });

        // remove the hash
        delete options.attrs.hash;

        // If all countries are individually provided as shipping regions, we'll send
        // 'ALL' to the server.
        options.attrs.shippingOptions.forEach(shipOpt => {
          if (_.isEqual(Object.keys(getIndexedCountries()), shipOpt.regions)) {
            shipOpt.regions = ['ALL'];
          }
        });

        // Update the crypto title based on the accepted currency and
        // coin type.
        if (options.attrs.metadata.contractType === 'CRYPTOCURRENCY') {
          const coinType = options.attrs.metadata.coinType;

          // TODO: This will need to change when we implement multi-currency
          // support. The listing itself will likely contain the coin or coins
          // it accepts.
          const fromCur = getServerCurrency().code;
          options.attrs.item.title = `${fromCur} > ${coinType}`;

          // The autogenerated slug doesn't like spaces and the greater than, so
          // we'll generate our own.
          if (method === 'create') {
            options.attrs.slug = `${fromCur}-${coinType}`;
          }
        }
      } else {
        options.url = options.url ||
          app.getServerUrl(`ob/listing/${this.get('slug')}`);
      }
    }

    returnSync = super.sync(method, model, options);

    const eventOpts = {
      xhr: returnSync,
      url: options.url,
    };

    if (method === 'create' || method === 'update') {
      const attrsBeforeSync = this.lastSyncedAttrs;

      returnSync.done(data => {
        const hasChanged = () => (!_.isEqual(attrsBeforeSync, this.toJSON()));

        if (data.slug) {
          this.set('slug', data.slug);
        }

        listingEvents.trigger('saved', this, {
          ...eventOpts,
          created: method === 'create',
          slug: this.get('slug'),
          prev: attrsBeforeSync,
          hasChanged,
        });
      });
    } else if (method === 'delete') {
      listingEvents.trigger('destroying', this, {
        ...eventOpts,
        slug: this.get('slug'),
      });

      returnSync.done(() => {
        listingEvents.trigger('destroy', this, {
          ...eventOpts,
          slug: this.get('slug'),
        });
      });
    }

    return returnSync;
  }

  parse(response) {
    this.unparsedResponse = JSON.parse(JSON.stringify(response)); // deep clone
    const parsedResponse = response.listing;

    if (parsedResponse) {
      const isCrypto = parsedResponse.metadata &&
        parsedResponse.metadata.contractType === 'CRYPTOCURRENCY';

      // set the hash
      parsedResponse.hash = response.hash;

      // convert price fields
      if (parsedResponse.item) {
        const price = parsedResponse.item.price;
        const cur = parsedResponse.metadata &&
          parsedResponse.metadata.pricingCurrency;

        if (price) {
          parsedResponse.item.price = integerToDecimal(price, cur);
        }
      }

      if (parsedResponse.shippingOptions && parsedResponse.shippingOptions.length) {
        parsedResponse.shippingOptions.forEach((shipOpt, shipOptIndex) => {
          if (shipOpt.services && shipOpt.services.length) {
            shipOpt.services.forEach((service, serviceIndex) => {
              const price = service.price;
              const cur = parsedResponse.metadata &&
                parsedResponse.metadata.pricingCurrency;

              if (typeof price === 'number') {
                parsedResponse.shippingOptions[shipOptIndex]
                  .services[serviceIndex].price = integerToDecimal(price, cur);
              } else {
                // This is necessary because of this bug:
                // https://github.com/OpenBazaar/openbazaar-go/issues/178
                parsedResponse.shippingOptions[shipOptIndex]
                  .services[serviceIndex].price = 0;
              }

              const price2 = service.additionalItemPrice;
              if (typeof price2 === 'number') {
                parsedResponse.shippingOptions[shipOptIndex]
                  .services[serviceIndex].additionalItemPrice = integerToDecimal(price2, cur);
              } else {
                // This is necessary because of this bug:
                // https://github.com/OpenBazaar/openbazaar-go/issues/178
                parsedResponse.shippingOptions[shipOptIndex]
                  .services[serviceIndex].additionalItemPrice = 0;
              }
            });
          }

          // If the shipping regions are set to 'ALL', we'll replace with a list of individual
          // countries, which is what our UI is designed to work with.
          if (shipOpt.regions && shipOpt.regions.length && shipOpt.regions[0] === 'ALL') {
            parsedResponse.shippingOptions[shipOptIndex].regions =
              Object.keys(getIndexedCountries());
          }
        });
      }

      if (parsedResponse.coupons && parsedResponse.coupons.length) {
        parsedResponse.coupons.forEach((coupon, couponIndex) => {
          if (typeof coupon.priceDiscount === 'number') {
            const price = parsedResponse.coupons[couponIndex].priceDiscount;
            const cur = parsedResponse.metadata && parsedResponse.metadata.pricingCurrency;

            parsedResponse.coupons[couponIndex].priceDiscount =
              integerToDecimal(price, cur);
          }
        });
      }

      // Re-organize variant structure so a "dummy" SKU (if present) has its quanitity
      // and productID moved to be attributes of the Item model
      if (parsedResponse.item && parsedResponse.item.skus &&
        parsedResponse.item.skus.length === 1 &&
        typeof parsedResponse.item.skus[0].variantCombo === 'undefined') {
        const dummySku = parsedResponse.item.skus[0];

        if (isCrypto) {
          parsedResponse.item.cryptoQuantity = dummySku.quantity /
            parsedResponse.metadata.coinDivisibility;
        } else {
          parsedResponse.item.quantity = dummySku.quantity;
        }

        parsedResponse.item.productID = dummySku.productID;
      }

      if (parsedResponse.item && parsedResponse.item.skus) {
        parsedResponse.item.skus.forEach(sku => {
          // If a sku quantity is set to less than 0, we'll set the
          // infinite inventory flag.
          if (sku.quantity < 0) {
            sku.infiniteInventory = true;
          } else {
            sku.infiniteInventory = false;
          }
          // convert the surcharge
          const surcharge = sku.surcharge;
          const cur = parsedResponse.metadata && parsedResponse.metadata.pricingCurrency;

          if (surcharge) {
            sku.surcharge = integerToDecimal(surcharge, cur);
          }
        });
        // END - convert price fields
      }

      if (parsedResponse.metadata) {
        parsedResponse.metadata.acceptedCurrencies =
          parsedResponse.metadata.acceptedCurrencies || [];
      }
    }

    return parsedResponse;
  }
}
<|endoftext|>


<commit_before>/*
 *   Copyright 2012 OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/**
 * The save query dialog
 */
var OpenDialog = Modal.extend({
    type: "save",
    closeText: "Open",

    events: {
        'click': 'select_root_folder', /* select root folder */
        'click .dialog_footer a:' : 'call',
        'click .query': 'select_name',
        'dblclick .query': 'open_query',
        'click li.folder': 'toggle_folder',
        'keyup .search_file' : 'search_file',
        'click .cancel_search' : 'cancel_search',
        'click .export' : 'export_zip'
    },

    buttons: [
        { id: "test", text: "Open", method: "open_query" },
        { text: "Cancel", method: "close" }
    ],

    initialize: function(args) {
        // Append events
        var self = this;
        var name = "";
        this.message = '
Search:  '
                + ' <input type="text" class="search_file"></input>
'
                + "
Loading....

Please select a file.....
"
        _.extend(this.options, {
            title: "Open"
        });

        // Initialize repository
        this.repository = new Repository({}, { dialog: this });

        this.bind( 'open', function( ) {
            var height = ( $( "body" ).height() / 2 ) + ( $( "body" ).height() / 6 );
            if( height > 420 ) {
                height = 420;
            }
            $(this.el).find('.RepositoryObjects').height( height );
            $(this.el).dialog( 'option', 'position', 'center' );
            $(this.el).parents('.ui-dialog').css({ width: "550px" });
            $(this.el).find('.dialog_footer').find('a[href="#open_query"]').hide();

            self.repository.fetch( );
        } );

        // Maintain `this`
        _.bindAll( this, "close", "toggle_folder", "select_name", "populate" , "cancel_search")

    },

    populate: function( repository ) {
        $( this.el ).find( '.RepositoryObjects' ).html(
            _.template( $( '#template-repository-objects' ).html( ) )( {
                repoObjects: repository
            } )
        );
    },

    select_root_folder: function( event ) {
        var isNameInputField = $( event.target ).attr( 'name' ) === 'name';
        if( !isNameInputField ) {
            this.unselect_current_selected_folder( );
        }
    },

    toggle_folder: function( event ) {
        var $target = $( event.currentTarget );
        this.unselect_current_selected_folder( );
        $target.children('.folder_row').addClass( 'selected' );
        $target.children('.folder_row').append("");
        var $queries = $target.children( '.folder_content' );
        var isClosed = $target.children( '.folder_row' ).find('.sprite').hasClass( 'collapsed' );
        if( isClosed ) {
            $target.children( '.folder_row' ).find('.sprite').removeClass( 'collapsed' );
            $queries.removeClass( 'hide' );
        } else {
            $target.children( '.folder_row' ).find('.sprite').addClass( 'collapsed' );
            $queries.addClass( 'hide' );
        }
        return false;
    },

    select_name: function( event ) {
        var $currentTarget = $( event.currentTarget );
        this.unselect_current_selected_folder( );
        $currentTarget.parent( ).parent( ).has( '.folder' ).children('.folder_row').addClass( 'selected' );
        var name = $currentTarget.find( 'a' ).attr('href');
        name = name.replace('#','');
        $(this.el).find('.query_name').html( name );
        $(this.el).find('.dialog_footer').find('a[href="#open_query"]').show();
        return false;
    },

    unselect_current_selected_folder: function( ) {
        $( this.el ).find( '.selected' ).removeClass( 'selected' );
        $( this.el ).find( '.export' ).remove();
    },

    // XXX - duplicaten from OpenQuery
    search_file: function(event) {
        var filter = $(this.el).find('.search_file').val().toLowerCase();
        var isEmpty = (typeof filter == "undefined" || filter == "" || filter == null);
        if (isEmpty || event.which == 27 || event.which == 9) {
            this.cancel_search();
        } else {
            if ($(this.el).find('.search_file').val()) {
                $(this.el).find('.cancel_search').show();
            } else {
                $(this.el).find('.cancel_search').hide();
            }
            $(this.el).find('li.query').removeClass('hide')
            $(this.el).find('li.query a').filter(function (index) {
                return $(this).text().toLowerCase().indexOf(filter) == -1;
            }).parent().addClass('hide');
            $(this.el).find('li.folder').addClass('hide');
            $(this.el).find('li.query').not('.hide').parents('li.folder').removeClass('hide');
            //$(this.el).find( 'li.folder .folder_content').not(':has(.query:visible)').parent().addClass('hide');

            //not(':contains("' + filter + '")').parent().hide();
            $(this.el).find( 'li.folder .folder_row' ).find('.sprite').removeClass( 'collapsed' );
            $(this.el).find( 'li.folder .folder_content' ).removeClass('hide');
        }
        return false;
    },
    cancel_search: function(event) {
        $(this.el).find('input.search_file').val('');
        $(this.el).find('.cancel_search').hide();
        $(this.el).find('li.query, li.folder').removeClass('hide');
        $(this.el).find( '.folder_row' ).find('.sprite').addClass( 'collapsed' );
        $(this.el).find( 'li.folder .folder_content' ).addClass('hide');
        $(this.el).find('.search_file').val('').focus();
        $(this.el).find('.cancel_search').hide();

    },

    export_zip: function(event) {
        var file = $( this.el ).find( '.selected a' ).attr('href').replace('#','');
        if (typeof file != "undefined" && file != "") {
            var url = Settings.REST_URL + (new RepositoryZipExport({ directory : file })).url();
            window.open(url + "?directory=" + file);
        }
    },

    open_query: function(event) {
        // Save the name for future reference
        var $currentTarget = $( event.currentTarget );
        var file = $(this.el).find('.query_name').html();
        if ($currentTarget.hasClass('query')) {
            file = $currentTarget.find( 'a' ).attr('href').replace('#','');
        }

        var selected_query = new SavedQuery({ file: file });
        this.close();
        Saiku.ui.block("Opening query...");
        selected_query.fetch({
            success: selected_query.move_query_to_workspace,
            error: function() { Saiku.ui.unblock(); },
            dataType: "text"
        });

        event.preventDefault();
        return false;
    }
});
<commit_msg>new export / import design, first step<commit_after>/*
 *   Copyright 2012 OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/**
 * The save query dialog
 */
var OpenDialog = Modal.extend({
    type: "save",
    closeText: "Open",

    events: {
        'click': 'select_root_folder', /* select root folder */
        'click .dialog_footer a:' : 'call',
        'click .query': 'select_name',
        'dblclick .query': 'open_query',
        'click li.folder': 'toggle_folder',
        'keyup .search_file' : 'search_file',
        'click .cancel_search' : 'cancel_search',
        'click .export' : 'export_zip',
        'click .import' : 'import_zip'
    },

    buttons: [
        { id: "test", text: "Open", method: "open_query" },
        { text: "Cancel", method: "close" }
    ],

    initialize: function(args) {
        // Append events
        var self = this;
        var name = "";
        this.message = '
Search:  '
                + ' <input type="text" class="search_file"></input>
'
                + "
Loading....

Please select a file.....
"
                + "
<form id='importForm' target='_blank' method='POST' enctype='multipart/form-data'>"
                + "<input type='hidden' name='directory' class='directory'/>"
                + "<input type='file' name='file' class='file'/>"
                + "<input type='submit' value='import' />"
                + "</form>";
        _.extend(this.options, {
            title: "Open"
        });

        // Initialize repository
        this.repository = new Repository({}, { dialog: this });

        this.bind( 'open', function( ) {
            var height = ( $( "body" ).height() / 2 ) + ( $( "body" ).height() / 6 );
            if( height > 420 ) {
                height = 420;
            }
            $(this.el).find('.RepositoryObjects').height( height );
            $(this.el).dialog( 'option', 'position', 'center' );
            $(this.el).parents('.ui-dialog').css({ width: "550px" });
            $(this.el).find('.dialog_footer').find('a[href="#open_query"]').hide();

            self.repository.fetch( );
        } );

        // Maintain `this`
        _.bindAll( this, "close", "toggle_folder", "select_name", "populate" , "cancel_search", "import_zip");

    },

    populate: function( repository ) {
        $( this.el ).find( '.RepositoryObjects' ).html(
            _.template( $( '#template-repository-objects' ).html( ) )( {
                repoObjects: repository
            } )
        );
    },

    select_root_folder: function( event ) {
        var isNameInputField = $( event.target ).attr( 'name' ) === 'name';
        if( !isNameInputField ) {
            this.unselect_current_selected_folder( );
        }
    },

    toggle_folder: function( event ) {
        var $target = $( event.currentTarget );
        this.unselect_current_selected_folder( );
        $target.children('.folder_row').addClass( 'selected' );
        $target.children('.folder_row').append("imp");
        var $queries = $target.children( '.folder_content' );
        var isClosed = $target.children( '.folder_row' ).find('.sprite').hasClass( 'collapsed' );
        if( isClosed ) {
            $target.children( '.folder_row' ).find('.sprite').removeClass( 'collapsed' );
            $queries.removeClass( 'hide' );
        } else {
            $target.children( '.folder_row' ).find('.sprite').addClass( 'collapsed' );
            $queries.addClass( 'hide' );
        }

        this.import_zip();
        return false;
    },

    select_name: function( event ) {
        var $currentTarget = $( event.currentTarget );
        this.unselect_current_selected_folder( );
        $currentTarget.parent( ).parent( ).has( '.folder' ).children('.folder_row').addClass( 'selected' );
        var name = $currentTarget.find( 'a' ).attr('href');
        name = name.replace('#','');
        $(this.el).find('.query_name').html( name );
        $(this.el).find('.dialog_footer').find('a[href="#open_query"]').show();
        return false;
    },

    unselect_current_selected_folder: function( ) {
        $( this.el ).find( '.selected' ).removeClass( 'selected' );
        $( this.el ).find( '.export' ).remove();
        $( this.el ).find( '.import' ).remove();
    },

    // XXX - duplicaten from OpenQuery
    search_file: function(event) {
        var filter = $(this.el).find('.search_file').val().toLowerCase();
        var isEmpty = (typeof filter == "undefined" || filter == "" || filter == null);
        if (isEmpty || event.which == 27 || event.which == 9) {
            this.cancel_search();
        } else {
            if ($(this.el).find('.search_file').val()) {
                $(this.el).find('.cancel_search').show();
            } else {
                $(this.el).find('.cancel_search').hide();
            }
            $(this.el).find('li.query').removeClass('hide')
            $(this.el).find('li.query a').filter(function (index) {
                return $(this).text().toLowerCase().indexOf(filter) == -1;
            }).parent().addClass('hide');
            $(this.el).find('li.folder').addClass('hide');
            $(this.el).find('li.query').not('.hide').parents('li.folder').removeClass('hide');
            //$(this.el).find( 'li.folder .folder_content').not(':has(.query:visible)').parent().addClass('hide');

            //not(':contains("' + filter + '")').parent().hide();
            $(this.el).find( 'li.folder .folder_row' ).find('.sprite').removeClass( 'collapsed' );
            $(this.el).find( 'li.folder .folder_content' ).removeClass('hide');
        }
        return false;
    },
    cancel_search: function(event) {
        $(this.el).find('input.search_file').val('');
        $(this.el).find('.cancel_search').hide();
        $(this.el).find('li.query, li.folder').removeClass('hide');
        $(this.el).find( '.folder_row' ).find('.sprite').addClass( 'collapsed' );
        $(this.el).find( 'li.folder .folder_content' ).addClass('hide');
        $(this.el).find('.search_file').val('').focus();
        $(this.el).find('.cancel_search').hide();

    },

    export_zip: function(event) {
        var file = $( this.el ).find( '.selected a' ).attr('href').replace('#','');
        if (typeof file != "undefined" && file != "") {
            var url = Settings.REST_URL + (new RepositoryZipExport({ directory : file })).url();
            window.open(url + "?directory=" + file);
        }
    },

    import_zip: function(event) {
        var file = $( this.el ).find( '.selected a' ).attr('href').replace('#','');
        var form = $('#importForm');
        form.find('.directory').val(file);

        if (typeof file != "undefined" && file != "") {
            var url = Settings.REST_URL + (new RepositoryZipExport({ directory : file })).url() + "upload";
            form.attr('action', url);
        }

    },

    open_query: function(event) {
        // Save the name for future reference
        var $currentTarget = $( event.currentTarget );
        var file = $(this.el).find('.query_name').html();
        if ($currentTarget.hasClass('query')) {
            file = $currentTarget.find( 'a' ).attr('href').replace('#','');
        }

        var selected_query = new SavedQuery({ file: file });
        this.close();
        Saiku.ui.block("Opening query...");
        selected_query.fetch({
            success: selected_query.move_query_to_workspace,
            error: function() { Saiku.ui.unblock(); },
            dataType: "text"
        });

        event.preventDefault();
        return false;
    }
});
<|endoftext|>


<commit_before>function (user, context, callback) {
  var WHITELIST = [
    'moc+servicenow@mozilla.com',      // MOC see: https://bugzilla.mozilla.org/show_bug.cgi?id=1423903
    'moc-sso-monitoring@mozilla.com',  // MOC see: https://bugzilla.mozilla.org/show_bug.cgi?id=1423903
  ];

  if (!user.email_verified) {
    console.log(`duosecurity: user primary email NOT verified, refusing login for ${user.email}`);
    return callback(null, user, global.postError('notingroup', context));
  }

  // Fake 2FA
  if (WHITELIST.includes(user.email)) {
    console.log(`duosecurity: whitelisted account ${user.email}, no 2FA check performed`);
    context.multifactor = true;
    return callback(null, user, context);
  }

  // Any user logging in with LDAP (ad) requires MFA authentication.
  if (context.connectionStrategy === 'ad') {
    context.multifactor = {
      host: configuration.duo_apihost_mozilla,
      ikey: configuration.duo_ikey_mozilla,
      provider: 'duo',
      skey: configuration.duo_skey_mozilla,
      username: user.email,

      // Optional: Force DuoSecurity everytime this rule runs. Defaults to false.
      // If accepted by users the cookie lasts for 30 days - i.e. 30 days MFA session (this cannot be changed)
      ignoreCookie: false,
    };
  }

  console.log(`duosecurity: ${user.email} is in LDAP and requires 2FA check`);

  return callback(null, user, context);
}
<commit_msg>Add TODO to handle configuration being unset<commit_after>function (user, context, callback) {
  var WHITELIST = [
    'moc+servicenow@mozilla.com',      // MOC see: https://bugzilla.mozilla.org/show_bug.cgi?id=1423903
    'moc-sso-monitoring@mozilla.com',  // MOC see: https://bugzilla.mozilla.org/show_bug.cgi?id=1423903
  ];

  if (!user.email_verified) {
    console.log(`duosecurity: user primary email NOT verified, refusing login for ${user.email}`);
    return callback(null, user, global.postError('notingroup', context));
  }

  // Fake 2FA
  if (WHITELIST.includes(user.email)) {
    console.log(`duosecurity: whitelisted account ${user.email}, no 2FA check performed`);
    context.multifactor = true;
    return callback(null, user, context);
  }

  // Any user logging in with LDAP (ad) requires MFA authentication.
  // TODO: Fix undefined behavior if the configuration variables aren't set
  if (context.connectionStrategy === 'ad') {
    context.multifactor = {
      host: configuration.duo_apihost_mozilla,
      ikey: configuration.duo_ikey_mozilla,
      provider: 'duo',
      skey: configuration.duo_skey_mozilla,
      username: user.email,

      // Optional: Force DuoSecurity everytime this rule runs. Defaults to false.
      // If accepted by users the cookie lasts for 30 days - i.e. 30 days MFA session (this cannot be changed)
      ignoreCookie: false,
    };
  }

  console.log(`duosecurity: ${user.email} is in LDAP and requires 2FA check`);

  return callback(null, user, context);
}
<|endoftext|>


<commit_before>
(function ($) {

	AjaxSolr.TimelineWidget = AjaxSolr.AbstractWidget.extend({
		start: 0,

		init: function(){
			this.$tabs = $(this.target).parents(".tabs-container");
			this.apiURL = "http://eumssi.cloudapp.net/EumssiEventExplorer/webresources/API/";
			this.rowsNumber = 100;
		},

		/** adding libs for timeline
		*/
		beforeRequest: function () {
			//donothing
		},

		afterRequest: function () {
			var tabPosition = $(this.target).parents(".ui-tabs-panel").data("tabpos");

			if(this.$tabs.tabs( "option", "active") === tabPosition) {
				this._renderTimeline();
			} else {
				this.$tabs.off("tabsactivate.timelinewidget");
				this.$tabs.on("tabsactivate.timelinewidget", this._tabChange.bind(this) );
			}
		},

		/**
		 * Check if the current open tab is this widget tab and then load the timeline
		 * @private
		 */
		_tabChange: function(){
			var tabPosition = $(this.target).parents(".ui-tabs-panel").data("tabpos");
			if(this.$tabs.tabs( "option", "active") === tabPosition) {
				this.$tabs.off("tabsactivate.timelinewidget");
				this._renderTimeline();
			}
		},

		_renderTimeline: function(){
			$(this.target).addClass("ui-loading-modal");
			this.getImportantEvents();
		},

		/**
		 * Error Management
		 * @param message
		 */
		afterRequestError: function(message) {
			$(this.target).html($("
").addClass("ui-error-text").text(message));
		},

		getImportantEvents: function(){
			$.ajax({
				url: this.apiURL + "getImportantEvents/json/"+this.rowsNumber+"/" + ( EUMSSI.Manager.getLastQuery() || "*%3A*"),
				success: this._renderTimelineAPI.bind(this)
			});
		},

		_renderTimelineAPI: function(response){
			$(this.target).empty();
			$(".event-placeholder").empty();
			$(this.target).removeClass("ui-loading-modal");
			var tlobj = {};
			tlobj["type"] = "default";

			var dateObj = [];

			for (var i = 0, l = response.length; i < l; i++) {
				var doc = response[i];
				var output= {};

				output["headline"] = doc['headline'];
				output["text"] = doc['description'];
				output["endDate"] = doc['date'].replace(/-/g,",");
				output["startDate"] =  doc['date'].replace(/-/g,",");

				if (!!output["headline"] && output["headline"].length>0) {
					if (dateObj.length == this.rowsNumber) { break; }
					if (!!output["text"]) {output["text"] = output["text"].substring(0,200);}
					dateObj.push(output);
				}

				this._renderEvent(doc);
			}

			if (dateObj.length==0) {return;}
			tlobj["date"] = dateObj;

			var timelineobject = {};
			timelineobject["timeline"] = tlobj;

			createStoryJS({
				type: 'timeline',
				width: '760',
				height: '500',
				start_zoom_adjust: -2,
				source:  timelineobject,
				embed_id: 'my-timeline'
			});

		},

		_renderEvent: function(event){
			var $event = $("
");
			$event.append($('
').text(event.headline));
			$event.append($('
').html(event.date));
			$event.append($('
').html(event.description));
			$(".event-placeholder").append($event);
		}

	});

})(jQuery);<commit_msg>timeline interactive<commit_after>(function ($) {

	AjaxSolr.TimelineWidget = AjaxSolr.AbstractWidget.extend({
		start: 0,

		init: function(){
			this.$tabs = $(this.target).parents(".tabs-container");
			this.apiURL = "http://eumssi.cloudapp.net/EumssiEventExplorer/webresources/API/";
			this.rowsNumber = 100;
		},

		/** adding libs for timeline
		*/
		beforeRequest: function () {
			//donothing
		},

		afterRequest: function () {
			var tabPosition = $(this.target).parents(".ui-tabs-panel").data("tabpos");

			if(this.$tabs.tabs( "option", "active") === tabPosition) {
				this._renderTimeline();
			} else {
				this.$tabs.off("tabsactivate.timelinewidget");
				this.$tabs.on("tabsactivate.timelinewidget", this._tabChange.bind(this) );
			}
		},

		/**
		 * Check if the current open tab is this widget tab and then load the timeline
		 * @private
		 */
		_tabChange: function(){
			var tabPosition = $(this.target).parents(".ui-tabs-panel").data("tabpos");
			if(this.$tabs.tabs( "option", "active") === tabPosition) {
				this.$tabs.off("tabsactivate.timelinewidget");
				this._renderTimeline();
			}
		},

		_renderTimeline: function(){
			$(this.target).addClass("ui-loading-modal");
			this.getImportantEvents();
		},

		/**
		 * Error Management
		 * @param message
		 */
		afterRequestError: function(message) {
			$(this.target).html($("
").addClass("ui-error-text").text(message));
		},

		getImportantEvents: function(entity){
			$(this.target).addClass("ui-loading-modal");
			if (!entity) {
				$.ajax({
					url: this.apiURL + "getImportantEvents/json/"+this.rowsNumber+"/" + ( EUMSSI.Manager.getLastQuery() || "*%3A*"),
					success: this._renderTimelineAPI.bind(this)
				});
			}

			else {
				$.ajax({
					url: this.apiURL + "getImportantEvents/json/"+this.rowsNumber+"/" + ( "meta.extracted.text.ner.all:*" + entity + "*" ),
					success: this._renderTimelineAPI.bind(this)
				});
			}

		},

		_renderTimelineAPI: function(response){
			$(this.target).empty();
			$(".event-placeholder").empty();
			$(this.target).removeClass("ui-loading-modal");
			var tlobj = {};
			tlobj["type"] = "default";

			var dateObj = [];

			for (var i = 0, l = response.length; i < l; i++) {
				var doc = response[i];
				var output= {};

				output["headline"] = doc['headline'];
				output["text"] = doc['description'];
				output["endDate"] = doc['date'].replace(/-/g,",");
				output["startDate"] =  doc['date'].replace(/-/g,",");

				if (!!output["headline"] && output["headline"].length>0) {
					if (dateObj.length == this.rowsNumber) { break; }
					if (!!output["text"]) {output["text"] = output["text"].substring(0,200);}
					dateObj.push(output);
				}

				this._renderEvent(doc);
			}

			if (dateObj.length==0) {return;}
			tlobj["date"] = dateObj;

			var timelineobject = {};
			timelineobject["timeline"] = tlobj;

			createStoryJS({
				type: 'timeline',
				width: '760',
				height: '500',
				start_zoom_adjust: -2,
				source:  timelineobject,
				embed_id: 'my-timeline'
			});

		},

		_renderEvent: function(event){
			var $event = $("
");
			var $value = $('').addClass("info-value");
			var entities = event['entity'];
			for (i = 0; i<entities.length; i++) {
				//$value += entities[i].name + " ; ";
				var $entitylink = $('')
				.text(entities[i].name + " ; ")
				.click(this._onEnityClick.bind(this, entities[i].name ));
				$value.append($entitylink);
			}

			$event.append($('
').text(event.headline));
			$event.append($('
').html(event.date));
			$event.append($('
').html(event.description));
			var $key = $('').addClass("info-label").text("Major Entities");
			$event.append($('
').append($key).append($value));
			$(".event-placeholder").append($event);
		},

		_onEnityClick: function(name){
			this.getImportantEvents(name);
		}

	});

})(jQuery);
<|endoftext|>


<commit_before>/**
 * Show helpful welcome notification for onlinedev developers!
 */
define(function(require, exports, module) {
    "use strict";

    main.consumes = [
        "Plugin", "ui", "dialog.notification", "pubsub"
    ];
    main.provides = ["onlinedev_helper"];
    return main;

    function main(options, imports, register) {
        var Plugin = imports.Plugin;
        var notification = imports["dialog.notification"];
        var pubsub = imports.pubsub;

        var plugin = new Plugin("Ajax.org", main.consumes);

        var loaded = false;
        function load() {
            if (loaded) return false;
            loaded = true;

            var suffix = options.baseUrl.replace(/.*:\/\//, "");
            if (suffix === "c9.dev")
                return; // bail out, we have a cert for that

            var hide = notification.show('
Welcome to onlinedev! Please authorize certificates of these pages: '
                + '' + suffix + ' '
                + 'vfs.' + suffix + ' '
                + "
");

            pubsub.once("connected", function() {
                hide();
            });
        }

        plugin.on("load", function(){
            load();
        });
        plugin.on("unload", function(){
            loaded = false;
        });

        register(null, { "onlinedev_helper" : plugin });
    }
});<commit_msg>Add api to onlinedev_helper<commit_after>/**
 * Show helpful welcome notification for onlinedev developers!
 */
define(function(require, exports, module) {
    "use strict";

    main.consumes = [
        "Plugin", "ui", "dialog.notification", "pubsub"
    ];
    main.provides = ["onlinedev_helper"];
    return main;

    function main(options, imports, register) {
        var Plugin = imports.Plugin;
        var notification = imports["dialog.notification"];
        var pubsub = imports.pubsub;

        var plugin = new Plugin("Ajax.org", main.consumes);

        var loaded = false;
        function load() {
            if (loaded) return false;
            loaded = true;

            var suffix = options.baseUrl.replace(/.*:\/\//, "");
            if (suffix === "c9.dev")
                return; // bail out, we have a cert for that

            var hide = notification.show('
Welcome to onlinedev! Please authorize certificates of these pages: '
                + 'vfs.' + suffix + ' '
                + 'api.' + suffix + ' '
                + '' + suffix + ' '
                + "
");

            pubsub.once("connected", function() {
                hide();
            });
        }

        plugin.on("load", function(){
            load();
        });
        plugin.on("unload", function(){
            loaded = false;
        });

        register(null, { "onlinedev_helper" : plugin });
    }
});<|endoftext|>


<commit_before>/**
 *Source section
 */

//Timer for keyword update
timer = "";

//When the document is ready, prepare and initiate different function to the object of the modal
$(document).ready(function() {
    $("#keywordTable").hide();
    $("#progressBarFiltering").hide();

    //Instanciate the autocomplete for semantic search
    $("#keyword").autocomplete({
        source : [""],
        search : function(event, ui) {
            $("#keyword").autocomplete({
                source : "/complete_entities/" + $("#keyword").val() + ".json"
            });
        },
        select : function(event,ui) {
        	if(ui.item.value.toLowerCase()!=$("#keyword").val().toLowerCase()){
            	askUpdateKeywordTable();
           }
           $("#keyword").attr("filter-uri",ui.item.uri)
           console.log( ui.item ?
          "Selected: " + ui.item.value + " aka " + ui.item.uri :
          "Nothing selected, input was " + this.value );
        },
        minLength : 3
    }).autocomplete("widget").addClass("span1");

    $("#addAllRSS").attr("disable", false);
    $("#addAllTwitter").attr("disable", false);
});

//slide down the source tab for the source selected
function slideDown(id) {
    if ($(id).is(":visible"))
        $(id).slideUp();
    else
        $(".form").not(id).slideUp('swing', function() {
            $(".form").not(id).hide();
            $(id).slideDown();
        });
}

//Add a source in the table
function addSource(table, value) {
    if (table == "Twitter") {
    	var reg = new RegExp('[, ]+');
        text = $(value).val().split(reg);
        if (value == "#searchTwitter"){
        	$.each(text,function(){
        		content = "#" + this;
           		$("#wellSources").append("" + content + "  ");
        	})
        }else{
			$.each(text,function(){
        		content = "@" + this;
           		$("#wellSources").append("" + content + "  ");
       		})
        }
        $("#addAllTwitter").attr("disabled", true);
    } else if (table == "RSS") {
        $("#wellSources").append("" + $(value).val() + "  ");
        $("#addAllRSS").attr("disabled", true);
    }
    $(value).val("");
    $(value).html("");
}

//add "all" sources in the table
function addAllSource(table, value) {
    if (table == "Twitter") {
        $("#wellSources").append("" + value + "  ");
        $("#searchTwitter").attr("disabled", true);
        $("#loginTwitter").attr("disabled", true);
        $("#searchTwitter").val("").html("");
        $("#loginTwitter").val("").html("");
        $("#addAllTwitter").attr("disabled", true);
    } else if (table == "RSS") {
        $("#wellSources").append("" + value + "  ");
        $("#searchRSS").attr("disabled", true);
        $("#searchRSS").val("").html("");
        $("#addAllRSS").attr("disabled", true);
    }
}

//Check the well to see if it has children. If not, addAllSources button are activated.
function checkWell(table) {
    if (table == "Twitter")
        $("#addAllTwitter").attr("disabled", false);
    else if (table == "RSS")
        $("#addAllRSS").attr("disabled", false);
    if ($("#wellSources").children(".twitterSource").length == 0)
        $("#addAllTwitter").attr("disabled", false);
    if ($("#wellSources").children(".rssSource").length == 0)
        $("#addAllRSS").attr("disabled", false);
}

/*
 * End of source section
 */

/**
 * Filtering section
 */

//Add a filter to the list of filter
function addFilter(type) {
    $("#progressBarFiltering").hide();
    $("#keywordTable").hide();
    clearTimeout(timer);
    if ($('#keyword').val() == "") {
        return false
    }
    var id = 1;
    var classtr = "";
    //Choose the class of the line of the table ( red for WITHOUT, blue for OR, green for AND)
    if (type == 'and') {
        id = 1;
        classtr == 'success';
    } else if (type == 'or') {
        id = 0;
        classtr = 'info';
    } else if (type == 'without') {
        id = 2;
        classtr = 'error';
    } else {
        return false;
    }

    //Add the related word to the keyword
    var motcle = $('#keyword').val();

	var id = getId();
    //Add the line to the table
    if (type == 'and')
        $('#wellAnd').append("" + motcle + " ");
    else if (type == 'or')
        $('#wellOr').append("" + motcle + " ");
    else if (type == 'without')
        $('#wellWithout').append("" + motcle + " ");

    $('#keywordTable tbody > tr > td > label > input').each(function() {
        if ($(this).is(':checked')) {
        	id = getId();
            if (type == 'and')
                $('#wellAnd').append("" + $(this).val() + " ");
            else if (type == 'or')
                $('#wellOr').append("" + $(this).val() + " ");
            else if (type == 'without')
                $('#wellWithout').append("" + $(this).val() + " ");
        }
    });
    $('#keyword').val('');
    $('#keyword').attr('filter-uri','undefined');

    //Reset the filtering
    rebootFiltering();
}

//Reset the dropdown selector and the table of related word
function rebootFiltering() {
    $('#keywordTable tbody > tr').each(function() {
        $(this).remove();
    });

}

//Fill the related keyword table with the right keyword
function updateKeywordTable() {
    rebootFiltering();
    if ($('#keyword').val() != "" && $('#keyword').val() != null)
        $.getJSON('/linked_words/' + $('#keyword').val() + '.json', function(data) {
            rebootFiltering();
            $.each(data, function(key, val) {
                if ($('#keyword').val() != "" && $('#keyword').val().length>2) {
                    $('#keywordTable').append('
<input type="checkbox" value="' + val.value + '" filter-uri="'+ val.uri+'">' + val.value + '
');
                }
            });
            $("#keywordTable").show();
            $("#progressBarFiltering").hide();
        });
}

//ask the timer if the related keyword table can be show. It will wait 1 second before doing it. If the function is call again, it will stop the current timer and start a new
function askUpdateKeywordTable() {
    $("#keywordTable").hide();
    if ($('#keyword').val() != "" && $('#keyword').val() != null && $('#keyword').val().length>2) {
        $("#progressBarFiltering").show();
        clearTimeout(timer);
        timer = setTimeout(function() {
            updateKeywordTable()
        }, 1000);
    } else {
        $("#progressBarFiltering").hide();
    }
}

//Define the action on ENTER key press for the filtering
function keywordComplete() {
    if (event.keyCode == 13) {
        addFilter();
        $('#keyword').autocomplete('close');
        return false;
    }
}

//Allow to switch tab in the new semantic search
function switchTab() {
    if ($('#filtering').hasClass('active'))
        return;
    $('#sources').removeClass('active');
    $('#breadcrumbSources').removeClass('active');

    $('#filtering').addClass('active');
    $('#breadcrumbFiltering').addClass('active');
    $('#breadcrumbFiltering').show();

    $('#filtering').hide();
    $('#sources').fadeOut('swing', function() {
        $('#filtering').fadeIn();
    });

    $(".form").hide();
}

//Allow to reverse switch tab in the new semantic search
function reverseSwitchTab() {
    if ($('#sources').hasClass('active'))
        return;
    $('#filtering').removeClass('active');
    $('#breadcrumbFiltering').removeClass('active');

    $('#sources').addClass('active');
    $('#breadcrumbSources').addClass('active');
    $('#breadcrumbSources').show();

    $('#sources').hide();
    $('#filtering').fadeOut('swing', function() {
        $('#sources').fadeIn();
    });
}

//show or hide the import rss panel
function showImportRss(){
	if ( $(".importRss").is(":visible")){
		$(".importRss").slideUp();
	} else{
		$(".importRss").slideDown();
	}
}

function addPersonnalRss(url){
	$("#wellSources").append("" + url + "  ");
    $("#addAllRSS").attr("disabled", true);
}
<commit_msg>Block the backspace action and reverse switch tab<commit_after>/**
 *Source section
 */

//Timer for keyword update
timer = "";

//When the document is ready, prepare and initiate different function to the object of the modal
$(document).ready(function() {
    $("#keywordTable").hide();
    $("#progressBarFiltering").hide();

    //Instanciate the autocomplete for semantic search
    $("#keyword").autocomplete({
        source : [""],
        search : function(event, ui) {
            $("#keyword").autocomplete({
                source : "/complete_entities/" + $("#keyword").val() + ".json"
            });
        },
        select : function(event,ui) {
        	if(ui.item.value.toLowerCase()!=$("#keyword").val().toLowerCase()){
            	askUpdateKeywordTable();
           }
           $("#keyword").attr("filter-uri",ui.item.uri)
           console.log( ui.item ?
          "Selected: " + ui.item.value + " aka " + ui.item.uri :
          "Nothing selected, input was " + this.value );
        },
        minLength : 3
    }).autocomplete("widget").addClass("span1");

    $("#addAllRSS").attr("disable", false);
    $("#addAllTwitter").attr("disable", false);

    //Block the original backspace action, and reverse switch the tab of the search
    $(document).keydown(function(e){
    	if(e.keyCode == 8){
    		reverseSwitchTab();
    		e.preventDefault();
    	}
   })
});

//slide down the source tab for the source selected
function slideDown(id) {
    if ($(id).is(":visible"))
        $(id).slideUp();
    else
        $(".form").not(id).slideUp('swing', function() {
            $(".form").not(id).hide();
            $(id).slideDown();
        });
}

//Add a source in the table
function addSource(table, value) {
    if (table == "Twitter") {
    	var reg = new RegExp('[, ]+');
        text = $(value).val().split(reg);
        if (value == "#searchTwitter"){
        	$.each(text,function(){
        		content = "#" + this;
           		$("#wellSources").append("" + content + "  ");
        	})
        }else{
			$.each(text,function(){
        		content = "@" + this;
           		$("#wellSources").append("" + content + "  ");
       		})
        }
        $("#addAllTwitter").attr("disabled", true);
    } else if (table == "RSS") {
        $("#wellSources").append("" + $(value).val() + "  ");
        $("#addAllRSS").attr("disabled", true);
    }
    $(value).val("");
    $(value).html("");
}

//add "all" sources in the table
function addAllSource(table, value) {
    if (table == "Twitter") {
        $("#wellSources").append("" + value + "  ");
        $("#searchTwitter").attr("disabled", true);
        $("#loginTwitter").attr("disabled", true);
        $("#searchTwitter").val("").html("");
        $("#loginTwitter").val("").html("");
        $("#addAllTwitter").attr("disabled", true);
    } else if (table == "RSS") {
        $("#wellSources").append("" + value + "  ");
        $("#searchRSS").attr("disabled", true);
        $("#searchRSS").val("").html("");
        $("#addAllRSS").attr("disabled", true);
    }
}

//Check the well to see if it has children. If not, addAllSources button are activated.
function checkWell(table) {
    if (table == "Twitter")
        $("#addAllTwitter").attr("disabled", false);
    else if (table == "RSS")
        $("#addAllRSS").attr("disabled", false);
    if ($("#wellSources").children(".twitterSource").length == 0)
        $("#addAllTwitter").attr("disabled", false);
    if ($("#wellSources").children(".rssSource").length == 0)
        $("#addAllRSS").attr("disabled", false);
}

/*
 * End of source section
 */

/**
 * Filtering section
 */

//Add a filter to the list of filter
function addFilter(type) {
    $("#progressBarFiltering").hide();
    $("#keywordTable").hide();
    clearTimeout(timer);
    if ($('#keyword').val() == "") {
        return false
    }
    var id = 1;
    var classtr = "";
    //Choose the class of the line of the table ( red for WITHOUT, blue for OR, green for AND)
    if (type == 'and') {
        id = 1;
        classtr == 'success';
    } else if (type == 'or') {
        id = 0;
        classtr = 'info';
    } else if (type == 'without') {
        id = 2;
        classtr = 'error';
    } else {
        return false;
    }

    //Add the related word to the keyword
    var motcle = $('#keyword').val();

	var id = getId();
    //Add the line to the table
    if (type == 'and')
        $('#wellAnd').append("" + motcle + " ");
    else if (type == 'or')
        $('#wellOr').append("" + motcle + " ");
    else if (type == 'without')
        $('#wellWithout').append("" + motcle + " ");

    $('#keywordTable tbody > tr > td > label > input').each(function() {
        if ($(this).is(':checked')) {
        	id = getId();
            if (type == 'and')
                $('#wellAnd').append("" + $(this).val() + " ");
            else if (type == 'or')
                $('#wellOr').append("" + $(this).val() + " ");
            else if (type == 'without')
                $('#wellWithout').append("" + $(this).val() + " ");
        }
    });
    $('#keyword').val('');
    $('#keyword').attr('filter-uri','undefined');

    //Reset the filtering
    rebootFiltering();
}

//Reset the dropdown selector and the table of related word
function rebootFiltering() {
    $('#keywordTable tbody > tr').each(function() {
        $(this).remove();
    });

}

//Fill the related keyword table with the right keyword
function updateKeywordTable() {
    rebootFiltering();
    if ($('#keyword').val() != "" && $('#keyword').val() != null)
        $.getJSON('/linked_words/' + $('#keyword').val() + '.json', function(data) {
            rebootFiltering();
            $.each(data, function(key, val) {
                if ($('#keyword').val() != "" && $('#keyword').val().length>2) {
                    $('#keywordTable').append('
<input type="checkbox" value="' + val.value + '" filter-uri="'+ val.uri+'">' + val.value + '
');
                }
            });
            $("#keywordTable").show();
            $("#progressBarFiltering").hide();
        });
}

//ask the timer if the related keyword table can be show. It will wait 1 second before doing it. If the function is call again, it will stop the current timer and start a new
function askUpdateKeywordTable() {
    $("#keywordTable").hide();
    if ($('#keyword').val() != "" && $('#keyword').val() != null && $('#keyword').val().length>2) {
        $("#progressBarFiltering").show();
        clearTimeout(timer);
        timer = setTimeout(function() {
            updateKeywordTable()
        }, 1000);
    } else {
        $("#progressBarFiltering").hide();
    }
}

//Define the action on ENTER key press for the filtering
function keywordComplete() {
    if (event.keyCode == 13) {
        addFilter();
        $('#keyword').autocomplete('close');
        return false;
    }
}

//Allow to switch tab in the new semantic search
function switchTab() {
    if ($('#filtering').hasClass('active'))
        return;
    $('#sources').removeClass('active');
    $('#breadcrumbSources').removeClass('active');

    $('#filtering').addClass('active');
    $('#breadcrumbFiltering').addClass('active');
    $('#breadcrumbFiltering').show();

    $('#filtering').hide();
    $('#sources').fadeOut('swing', function() {
        $('#filtering').fadeIn();
    });

    $(".form").hide();
}

//Allow to reverse switch tab in the new semantic search
function reverseSwitchTab() {
    if ($('#sources').hasClass('active'))
        return;
    $('#filtering').removeClass('active');
    $('#breadcrumbFiltering').removeClass('active');

    $('#sources').addClass('active');
    $('#breadcrumbSources').addClass('active');
    $('#breadcrumbSources').show();

    $('#sources').hide();
    $('#filtering').fadeOut('swing', function() {
        $('#sources').fadeIn();
    });
}

//show or hide the import rss panel
function showImportRss(){
	if ( $(".importRss").is(":visible")){
		$(".importRss").slideUp();
	} else{
		$(".importRss").slideDown();
	}
}

function addPersonnalRss(url){
	$("#wellSources").append("" + url + "  ");
    $("#addAllRSS").attr("disabled", true);
}
<|endoftext|>


<commit_before>var app = angular.module('app', ['ngMessages'])

app.config(function($interpolateProvider) {
    // change up angular's templating syntax to avoid
    // collisions with Jinja2
    $interpolateProvider.startSymbol('{a');
    $interpolateProvider.endSymbol('a}');
});

// tweet_url, page_url and title_url are defined in the base template
// by Flask's url_for

function TweetService($http) {
    var TweetService = {};

    function tweets(term) {
        return $http.get(tweet_url + term);
    };

    TweetService.getTweets = tweets;
    return TweetService;

};

function WikiPageService($http) {
    var WikiPageService = {};

    function getTitles(term) {
        return $http.get(title_url + term);
    };

    function getPage(title) {
        return $http.get(page_url + title)
    }

    WikiPageService.getTitles = getTitles;
    WikiPageService.getPage = getPage
    return WikiPageService
}

function MainController(TweetService, WikiPageService) {
    var vm = this;

    vm.activated = false;

    function init() {
        vm.twitter = {
            loaded: false,
            error: false,
            tweets: []
        };

        vm.wiki = {
            loaded: false,
            error: false,
            pages: []
        };

    };

    this.submit = function(term) {
        init();
        vm.activated = true;
        getTweets(term);
        getPages(term);
    };

    function getTweets(term) {
        return TweetService.getTweets(term)
            .success(function(data, status, headers, config) {
                vm.twitter.loaded = true;
                vm.twitter.tweets = data.tweets
            })
            .error(function(data, status, headers, config) {
                vm.twitter.error = true;
                vm.twitter.msg = data.msg;
            });
    };

    function getPages(term) {
        return WikiPageService.getTitles(term)
            .success(function(data, status, headers, config) {
                vm.wiki.pages = data.titles;
                vm.wiki.loaded = true;

                for (i=0; i < vm.wiki.pages.length; ++i) {
                    getPage(vm.wiki.pages[i]);
                };
            })
            .error(function(data, status, headers, config) {
                vm.wiki.error = true;
                vm.wiki.msg = data.msg;
            });
    };

    function getPage(page) {
        return WikiPageService.getPage(page.title)
            .success(function(data, status, headers, config) {
                page.summary = data.page.summary
            })
            .error(function(data, status, headers, config) {
                page.summary = data.msg
            });
    }
};

app.factory('TweetService', TweetService);
app.factory('WikiPageService', WikiPageService);
app.factory('TermService', TermService);
app.controller('MainController', MainController);
<commit_msg>...Forgot to remove it from the service registration as well<commit_after>var app = angular.module('app', ['ngMessages'])

app.config(function($interpolateProvider) {
    // change up angular's templating syntax to avoid
    // collisions with Jinja2
    $interpolateProvider.startSymbol('{a');
    $interpolateProvider.endSymbol('a}');
});

// tweet_url, page_url and title_url are defined in the base template
// by Flask's url_for

function TweetService($http) {
    var TweetService = {};

    function tweets(term) {
        return $http.get(tweet_url + term);
    };

    TweetService.getTweets = tweets;
    return TweetService;

};

function WikiPageService($http) {
    var WikiPageService = {};

    function getTitles(term) {
        return $http.get(title_url + term);
    };

    function getPage(title) {
        return $http.get(page_url + title)
    }

    WikiPageService.getTitles = getTitles;
    WikiPageService.getPage = getPage
    return WikiPageService
}

function MainController(TweetService, WikiPageService) {
    var vm = this;

    vm.activated = false;

    function init() {
        vm.twitter = {
            loaded: false,
            error: false,
            tweets: []
        };

        vm.wiki = {
            loaded: false,
            error: false,
            pages: []
        };

    };

    this.submit = function(term) {
        init();
        vm.activated = true;
        getTweets(term);
        getPages(term);
    };

    function getTweets(term) {
        return TweetService.getTweets(term)
            .success(function(data, status, headers, config) {
                vm.twitter.loaded = true;
                vm.twitter.tweets = data.tweets
            })
            .error(function(data, status, headers, config) {
                vm.twitter.error = true;
                vm.twitter.msg = data.msg;
            });
    };

    function getPages(term) {
        return WikiPageService.getTitles(term)
            .success(function(data, status, headers, config) {
                vm.wiki.pages = data.titles;
                vm.wiki.loaded = true;

                for (i=0; i < vm.wiki.pages.length; ++i) {
                    getPage(vm.wiki.pages[i]);
                };
            })
            .error(function(data, status, headers, config) {
                vm.wiki.error = true;
                vm.wiki.msg = data.msg;
            });
    };

    function getPage(page) {
        return WikiPageService.getPage(page.title)
            .success(function(data, status, headers, config) {
                page.summary = data.page.summary
            })
            .error(function(data, status, headers, config) {
                page.summary = data.msg
            });
    }
};

app.factory('TweetService', TweetService);
app.factory('WikiPageService', WikiPageService);
app.controller('MainController', MainController);
<|endoftext|>


<commit_before>var kafka = require('kafka-node');

var client = new kafka.Client(),
  consumer = new kafka.Consumer(
    client, [{
      topic: 'new-topics-recvd'
    }], {
      autoCommit: false
    }
  );

consumer.on('message', function(message) {
  console.log("received message", message);
});
<commit_msg>Fixed topic name.<commit_after>var kafka = require('kafka-node');

var client = new kafka.Client(),
  consumer = new kafka.Consumer(
    client, [{
      topic: 'new-proposals-recvd'
    }], {
      autoCommit: false
    }
  );

consumer.on('message', function(message) {
  console.log("received message", message);
});

consumer.on('error', function(err) {
  console.log(err);
});
<|endoftext|>


<commit_before>/**
 * Encode to MP3 and upload to server
 */
importScripts('lib/requirejs/require.js');

require(['lib/libmp3lame/dist/libmp3lame'], function(lame) {

    var mp3codec;

    postMessage('ready');

    onmessage = function(msg) {

        var size = msg.data.length;

        mp3codec = Lame.init();

        Lame.set_mode(mp3codec, Lame.MONO);
        Lame.set_num_channels(mp3codec, 1);
        Lame.set_num_samples(mp3codec, size);

        Lame.set_in_samplerate(mp3codec, 44100);
        Lame.set_out_samplerate(mp3codec, 44100);

        Lame.set_bitrate(mp3codec, 128);

        Lame.init_params(mp3codec);

        postMessage('Encoding...');

        var buff = new Float32Array(size);

        for (var i = 0; i < size; i++) {
            buff[i] = msg.data[i];
        }

        var mp3data = Lame.encode_buffer_ieee_float(mp3codec, buff, buff);

        postMessage('Uploading to server...');

        Lame.encode_flush(mp3codec);

        var blob = new Blob([new Uint8Array(mp3data.data)], {
            type: 'audio/mp3'
        });

        var fd = new FormData();
        fd.append('fname', '8bit.wav');
        fd.append('data', blob);

        var req = new XMLHttpRequest();
        req.open("POST", '../api/songs', true);

        req.onreadystatechange = function() {
            if (req.readyState === 4) {
                postMessage('done');
            }
        };

        req.send(fd);

        Lame.close(mp3codec);

        mp3codec = null;

        postMessage('done');
    }
});
<commit_msg>Removed unused form data<commit_after>/**
 * Encode to MP3 and upload to server
 */
importScripts('lib/requirejs/require.js');

require(['lib/libmp3lame/dist/libmp3lame'], function(lame) {

    var mp3codec;

    postMessage('ready');

    onmessage = function(msg) {

        var size = msg.data.length;

        mp3codec = Lame.init();

        Lame.set_mode(mp3codec, Lame.MONO);
        Lame.set_num_channels(mp3codec, 1);
        Lame.set_num_samples(mp3codec, size);

        Lame.set_in_samplerate(mp3codec, 44100);
        Lame.set_out_samplerate(mp3codec, 44100);

        Lame.set_bitrate(mp3codec, 128);

        Lame.init_params(mp3codec);

        postMessage('Encoding...');

        var buff = new Float32Array(size);

        for (var i = 0; i < size; i++) {
            buff[i] = msg.data[i];
        }

        var mp3data = Lame.encode_buffer_ieee_float(mp3codec, buff, buff);

        postMessage('Uploading to server...');

        Lame.encode_flush(mp3codec);

        var blob = new Blob([new Uint8Array(mp3data.data)], {
            type: 'audio/mp3'
        });

        var fd = new FormData();
        fd.append('data', blob);

        var req = new XMLHttpRequest();
        req.open("POST", '../api/songs', true);

        req.onreadystatechange = function() {
            if (req.readyState === 4) {
                postMessage('done');
            }
        };

        req.send(fd);

        Lame.close(mp3codec);

        mp3codec = null;

        postMessage('done');
    }
});
<|endoftext|>


<commit_before>(function () {
    "use strict";

    /**
     *
     * @param {ol.Feature} feature
     * @param {Mapbender.Digitizer.Scheme} schema
     * @param {Mapbender.Digitizer.PopupConfiguration} configuration
     * @returns {FeatureEditDialog}
     * @constructor
     */
    var FeatureEditDialog = function (feature, schema,configuration) {

        var dialog = this;

        var widget = schema.widget;
        var $popup = dialog.$popup = $("<div/>");

        $popup.data('feature', feature);

        widget.currentPopup && widget.currentPopup.popupDialog('close');
        widget.currentPopup = $popup;
        $popup.generateElements({children: schema.formItems});

        console.warn("Creating dm edit dialog", configuration);
        $popup.popupDialog(configuration);

        /** This is evil, but filling of input fields currently relies on that (see select field) **/
        setTimeout(function () {
            $popup.formData(feature.get('data'));
        }, 0);

        $popup.parent().bind("mouseenter",function(){
            feature.dispatchEvent({type: widget.TYPE+'.UnhoverFeature'});
        });

        return dialog;
    };

    Mapbender.Digitizer.PopupConfiguration = function (schema) {
        var popupConfiguration = this;
        popupConfiguration.schema = schema;

        $.extend(popupConfiguration, schema.popup);

        popupConfiguration.checkForDeprecatedUsageOfButtons_();
        popupConfiguration.buttons = popupConfiguration.createButtons_();

        Object.freeze(popupConfiguration.buttons);
    };

    Mapbender.Digitizer.PopupConfiguration.prototype.createButtons_ = function () {

        var popupConfiguration = this;
        var schema = popupConfiguration.schema;

        var buttons = {};
        if (schema.copy && schema.copy.enable) {
            buttons.copyButton = {
                text: Mapbender.trans('mb.digitizer.feature.clone.title'),
                click: function() {
                    schema.copyFeature(feature);
                }
            };
        }
        if (schema.allowCustomStyle) {
            buttons.styleButton = {
                text: Mapbender.trans('mb.digitizer.feature.style.change'),
                click: function() {
                    schema.openChangeStyleDialog(feature);
                }
            };
        }
        if (schema.printable && this.printClient) {
            buttons.printButton = {
                text: Mapbender.trans('mb.digitizer.feature.print'),
                click: function() {
                    schema.widget.printClient.printDigitizerFeauture(feature, schema);
                }
            };
        }
        if (schema.allowEditData) {
            buttons.saveButton = {
                text: Mapbender.trans('mb.digitizer.feature.save.title'),
                click: function() {
                    var formData = dialog.$popup.formData();
                    var $allNamedInputs = $(':input[name]', dialog.$popup);
                    var $invalidInputs = $allNamedInputs.filter(function() {
                        // NOTE: jQuery pseudo-selector :valid can not be chained into a single .find (or snytactic variant)
                        return $(this).is(':not(:valid)');
                    });
                    // @todo vis-ui: some inputs (with ".mandatory") are made invalid only visually when
                    //               empty, but do not have the HTML required or pattern property to
                    //               support selector detection. Work around that here.
                    $invalidInputs = $invalidInputs.add($('.has-error :input', dialog.$popup));
                    if ($invalidInputs.length) {
                        console.warn("Error", $invalidInputs.get());
                        return;
                    }

                    dialog.$popup.disableForm();

                    schema.saveFeature(feature, formData).then(function (response) {
                        if (response.hasOwnProperty('errors')) {
                            dialog.$popup.enableForm();
                            return;
                        }
                        dialog.$popup.popupDialog('instance').close();
                    });
                }
            };
        }
        if (schema.allowDelete) {
            buttons.deleteButton = {
                text: Mapbender.trans('mb.digitizer.feature.remove.title'),
                click: function() {
                    schema.removeFeature(feature);
                }
            };
        }

        buttons.cancelButton = {
            text: Mapbender.trans('mb.digitizer.cancel'),
            click: function() {
                dialog.$popup.popupDialog('instance').cancel();
            }
        };

        return buttons;
    };

    Mapbender.Digitizer.PopupConfiguration.prototype.createEventListeners = function (dialog) {
        var configuration = this;
        var schema = configuration.schema;

        var feature = dialog.$popup.data("feature");

        var eventListeners = {};

        return eventListeners;
    };

    Object.assign(Mapbender.Digitizer.PopupConfiguration.prototype, {
        checkForDeprecatedUsageOfButtons_: function () {
            var configuration = this;
            _.each(configuration.buttons, function (button) {
                console.error("Using Javascript code in the configuration is deprecated:", button);
            });
        },
        clone: function () {
            return $.extend(true, {}, this)
        },
        createFeatureEditDialog: function (feature, schema) {
            var configuration = this;
            return new FeatureEditDialog(feature, schema, configuration.clone())
        }
    });

})();
<commit_msg>Use lists for form popup buttons<commit_after>(function () {
    "use strict";

    /**
     *
     * @param {ol.Feature} feature
     * @param {Mapbender.Digitizer.Scheme} schema
     * @param {Mapbender.Digitizer.PopupConfiguration} configuration
     * @returns {FeatureEditDialog}
     * @constructor
     */
    var FeatureEditDialog = function (feature, schema,configuration) {

        var dialog = this;

        var widget = schema.widget;
        var $popup = dialog.$popup = $("<div/>");

        $popup.data('feature', feature);

        widget.currentPopup && widget.currentPopup.popupDialog('close');
        widget.currentPopup = $popup;
        $popup.generateElements({children: schema.formItems});

        console.warn("Creating dm edit dialog", configuration);
        $popup.popupDialog(configuration);

        /** This is evil, but filling of input fields currently relies on that (see select field) **/
        setTimeout(function () {
            $popup.formData(feature.get('data'));
        }, 0);

        $popup.parent().bind("mouseenter",function(){
            feature.dispatchEvent({type: widget.TYPE+'.UnhoverFeature'});
        });

        return dialog;
    };

    Mapbender.Digitizer.PopupConfiguration = function (schema) {
        var popupConfiguration = this;
        popupConfiguration.schema = schema;

        $.extend(popupConfiguration, schema.popup);

        popupConfiguration.checkForDeprecatedUsageOfButtons_();
        popupConfiguration.buttons = popupConfiguration.createButtons_();

        Object.freeze(popupConfiguration.buttons);
    };

    Mapbender.Digitizer.PopupConfiguration.prototype.createButtons_ = function () {

        var popupConfiguration = this;
        var schema = popupConfiguration.schema;

        var buttons = [];
        if (schema.copy && schema.copy.enable) {
            buttons.push({
                text: Mapbender.trans('mb.digitizer.feature.clone.title'),
                click: function() {
                    schema.copyFeature(feature);
                }
            });
        }
        if (schema.allowCustomStyle) {
            buttons.push({
                text: Mapbender.trans('mb.digitizer.feature.style.change'),
                click: function() {
                    schema.openChangeStyleDialog(feature);
                }
            });
        }
        if (schema.printable && this.printClient) {
            buttons.push({
                text: Mapbender.trans('mb.digitizer.feature.print'),
                click: function() {
                    schema.widget.printClient.printDigitizerFeauture(feature, schema);
                }
            });
        }
        if (schema.allowEditData) {
            buttons.push({
                text: Mapbender.trans('mb.digitizer.feature.save.title'),
                click: function() {
                    var formData = dialog.$popup.formData();
                    var $allNamedInputs = $(':input[name]', dialog.$popup);
                    var $invalidInputs = $allNamedInputs.filter(function() {
                        // NOTE: jQuery pseudo-selector :valid can not be chained into a single .find (or snytactic variant)
                        return $(this).is(':not(:valid)');
                    });
                    // @todo vis-ui: some inputs (with ".mandatory") are made invalid only visually when
                    //               empty, but do not have the HTML required or pattern property to
                    //               support selector detection. Work around that here.
                    $invalidInputs = $invalidInputs.add($('.has-error :input', dialog.$popup));
                    if ($invalidInputs.length) {
                        console.warn("Error", $invalidInputs.get());
                        return;
                    }

                    dialog.$popup.disableForm();

                    schema.saveFeature(feature, formData).then(function (response) {
                        if (response.hasOwnProperty('errors')) {
                            dialog.$popup.enableForm();
                            return;
                        }
                        dialog.$popup.popupDialog('instance').close();
                    });
                }
            });
        }
        if (schema.allowDelete) {
            buttons.push({
                text: Mapbender.trans('mb.digitizer.feature.remove.title'),
                click: function() {
                    schema.removeFeature(feature);
                }
            });
        }

        buttons.push({
            text: Mapbender.trans('mb.digitizer.cancel'),
            click: function() {
                dialog.$popup.popupDialog('instance').cancel();
            }
        });

        return buttons;
    };

    Mapbender.Digitizer.PopupConfiguration.prototype.createEventListeners = function (dialog) {
        var configuration = this;
        var schema = configuration.schema;

        var feature = dialog.$popup.data("feature");

        var eventListeners = {};

        return eventListeners;
    };

    Object.assign(Mapbender.Digitizer.PopupConfiguration.prototype, {
        checkForDeprecatedUsageOfButtons_: function () {
            var configuration = this;
            _.each(configuration.buttons, function (button) {
                console.error("Using Javascript code in the configuration is deprecated:", button);
            });
        },
        clone: function () {
            return $.extend(true, {}, this)
        },
        createFeatureEditDialog: function (feature, schema) {
            var configuration = this;
            return new FeatureEditDialog(feature, schema, configuration.clone())
        }
    });

})();
<|endoftext|>